/**
 * Rahman, Asif
 * Assignment #5: Hash_DB.cpp
 * UserID: arahman2@fau.edu
 * Course: COP3530 Term: Fall 2008
 * Instructor: Dr. Lofton Bullard
 *
 * Hash_DB.cpp
 * ------
 * Hash_DB.cpp is the source code to the hash table
 */

#include <iostream>
#include <string>
#include "Hash_DB.h"
 
using namespace std;

/**
 * Default constructor
 * Preconditions: none
 * Postconditions: hash_db initialized
 * Description: The default constructor here doesnt do much :)
 */

Hash_DB::Hash_DB()
{
    
}

/**
 * insert()
 * Preconditions: Hash_DB initialized
 * Postconditions: See List::insert(), BST::insert(), status printed to screen for user
 * Description: If lastname and firstname (as a key) does not exist in the hashed BST, then insert it into the Linked list and BST
 */
void Hash_DB::insert(Record *rec)
{        
    //If record (lastname,firstname) does not already exist in the BST, then add to records and BST.
    if(search(rec->lastname, rec->firstname) == NULL) {
        Record *ptr = Records.insert(rec);        
        B[getIndex(rec->lastname)].insert(searchKey(rec->lastname, rec->firstname), ptr);
        cout << "Successfully inserted record into address book.\n";
    } else {
        cout << "Duplicate entry in address book! (" << rec->lastname << ", " << rec->firstname << ")\n"; 
    }
}

/**
 * load()
 * Preconditions: Hash_DB initialized
 * Postconditions: See List::insert(), BST::insert()
 * Description: Exactly the same as insert() except it runs silently (used for loading the linked list and hashed bst from data file)
 */
void Hash_DB::load(Record *rec)
{
    if(search(rec->lastname, rec->firstname) == NULL) {
        Record *ptr = Records.insert(rec);        
        B[getIndex(rec->lastname)].insert(searchKey(rec->lastname, rec->firstname), ptr);
    }
}

/**
 * remove()
 * Preconditions: Hash_DB initialized
 * Postconditions: See List::remove(), BST::remove()
 * Description: If node with lastname firstname key found, then remove it from the BST and linked list
 */
void Hash_DB::remove(string &lastname, string &firstname)
{
    node *ptr = search(lastname, firstname);
    if(ptr == NULL) {
        cout << "Error Deleting: This record does not exist in the address book!" << endl;
    } else {
        Record *list_ptr = ptr->record;
        B[getIndex(lastname)].remove(searchKey(lastname, firstname));
        Records.remove(list_ptr);  
        cout << "Successfully removed record from the address book." << endl;
    }
}

/**
 * search()
 * Preconditions: Hash_DB initialized
 * Postconditions: See BST::search()
 * Description: Returns node with matching lastname,firstname key (if exists, otherwise returns NULL)
 */
node *Hash_DB::search(string &lastname, string &firstname)
{
    return B[getIndex(lastname)].search(searchKey(lastname, firstname));
}

/**
 * searchKey()
 * Preconditions: Hash_DB initialized, lastname and firstname provided
 * Postconditions: Returns concatenated lastname and firstname in all uppercase
 * Description: Generates the searchkey from provided lastname and firstname, used for creating BST nodes and searching for BST nodes
 */
string Hash_DB::searchKey(string &lastname, string &firstname)
{
    string name = lastname + firstname;
    for(unsigned int i=0; i<name.length(); i++) {
        name[i] = toupper(name[i]);
    }
    return name;
}

/**
 * getIndex()
 * Preconditions: Hash_DB initialized, lastname provided
 * Postconditions: Returns the hash index from given lastname
 * Description: This is the hashing function for the hash table, takes first letter of lastname (case-insensitive) and returns integer value (a=0, b=1, c=2, etc)
 */
int Hash_DB::getIndex(string &lastname)
{
    return ((int)toupper(lastname[0]) - 65);
}
