// Implements a dictionary's functionality

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>

#include "dictionary.h"

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
}
node;

// Number of buckets in hash table
const unsigned int N = 26;

// Hash table
node *table[N];

// Total number of words loaded
int totalWords = 0;

// Returns true if word is in dictionary else false
bool check(const char *word)
{
    // Points to the head of index of the table
    node *cursor = table[hash(word)];

    // Compares strings insensitively
    if (strcasecmp(cursor->word, word) == 0)
    {
        return true;
    }

    // Traversal of linked list
    while (cursor->next != NULL)
    {
        cursor = cursor->next;

        if (strcasecmp(cursor->word, word) == 0)
        {
            return true;
        }
    }

    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    int n = (int) tolower(word[0]) - 97;
    return n;
}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    // Opens the dictionary
    FILE *fp1 = fopen(dictionary, "r");

    if (fp1 == NULL)
    {
        printf("File opening error\n");
        fclose(fp1);
        return false;
    }

    // Space to hold words
    char buffer[LENGTH];

    // Read from file until end of file
    while (fscanf(fp1, "%s", buffer) != EOF)
    {
        node *n = (node *)malloc(sizeof(node));

        if (n == NULL)
        {
            fclose(fp1);
            return false;
        }

        strcpy(n->word, buffer);
        totalWords++;

        n->next = table[hash(buffer)];
        table[hash(buffer)] = n;
    }

    fclose(fp1);
    return true;
}

// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
    return totalWords;
}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    node *temp, *cursor;

    for (int i = 0; i < N; i++)
    {
        if (table[i] == NULL)
        {
            continue;
        }

        cursor = table[i];
        temp = cursor;

        while (cursor->next != NULL)
        {
            cursor = cursor->next;
            free(temp);
            temp = cursor;
        }
        free(cursor);
    }

    return true;
}
