/*
 * Tabulka s rozptýlenými položkami
 *
 * S využitím datových typů ze souboru hashtable.h a připravených koster
 * funkcí implementujte tabulku s rozptýlenými položkami s explicitně
 * zretězenými synonymy.
 *
 * Při implementaci uvažujte velikost tabulky HT_SIZE.
 */

#include "hashtable.h"
#include <stdlib.h>
#include <string.h>

int HT_SIZE = MAX_HT_SIZE;

/*
 * Rozptylovací funkce která přidělí zadanému klíči index z intervalu
 * <0,HT_SIZE-1>. Ideální rozptylovací funkce by měla rozprostírat klíče
 * rovnoměrně po všech indexech. Zamyslete sa nad kvalitou zvolené funkce.
 */
int get_hash(char *key) {
  int result = 1;
  int length = strlen(key);
  for (int i = 0; i < length; i++) {
    result += key[i];
  }
  return (result % HT_SIZE);
}

/*
 * Inicializace tabulky — zavolá sa před prvním použitím tabulky.
 */
void ht_init(ht_table_t *table) {
    // Inicializujeme všetky položky na NULL
    for (int i = 0; i < HT_SIZE; i++) {
        (*table)[i] = NULL;
    }
}

/*
 * Vyhledání prvku v tabulce.
 *
 * V případě úspěchu vrací ukazatel na nalezený prvek; v opačném případě vrací
 * hodnotu NULL.
 */
ht_item_t *ht_search(ht_table_t *table, char *key) {
    // Získame index pomocou hash funkcie
    int index = get_hash(key);

    // Prechádzame zoznam synoným
    ht_item_t *item = (*table)[index];
    while (item != NULL) {
        // Ak nájdeme kľúč, vrátime položku
        if (strcmp(item->key, key) == 0) {
            return item;
        }
        item = item->next;
    }

    // Prvok nebol nájdený
    return NULL;
}

/*
 * Vložení nového prvku do tabulky.
 *
 * Pokud prvek s daným klíčem už v tabulce existuje, nahraďte jeho hodnotu.
 *
 * Při implementaci využijte funkci ht_search. Pri vkládání prvku do seznamu
 * synonym zvolte nejefektivnější možnost a vložte prvek na začátek seznamu.
 */
void ht_insert(ht_table_t *table, char *key, float value) {
    // Skúsime nájsť existujúci prvok
    ht_item_t *item = ht_search(table, key);

    if (item != NULL) {
        // Ak existuje, aktualizujeme hodnotu
        item->value = value;
    } else {
        // Vytvoríme nový prvok
        int index = get_hash(key);
        item = malloc(sizeof(ht_item_t));
        if (item == NULL) {
            return; // Chyba alokácie
        }

        // Alokujeme a skopírujeme kľúč
        item->key = malloc(strlen(key) + 1);
        if (item->key == NULL) {
            free(item);
            return;
        }
        strcpy(item->key, key);

        // Nastavíme hodnotu a zaradíme na začiatok zoznamu synoným
        item->value = value;
        item->next = (*table)[index];
        (*table)[index] = item;
    }
}

/*
 * Získání hodnoty z tabulky.
 *
 * V případě úspěchu vrací funkce ukazatel na hodnotu prvku, v opačném
 * případě hodnotu NULL.
 *
 * Při implementaci využijte funkci ht_search.
 */
float *ht_get(ht_table_t *table, char *key) {
    // Vyhľadáme prvok
    ht_item_t *item = ht_search(table, key);

    if (item != NULL) {
        // Ak existuje, vrátime pointer na hodnotu
        return &(item->value);
    }

    return NULL;
}

/*
 * Smazání prvku z tabulky.
 *
 * Funkce korektně uvolní všechny alokované zdroje přiřazené k danému prvku.
 * Pokud prvek neexistuje, funkce nedělá nic.
 *
 * Při implementaci NEPOUŽÍVEJTE funkci ht_search.
 */
void ht_delete(ht_table_t *table, char *key) {
    int index = get_hash(key);
    ht_item_t *item = (*table)[index];
    ht_item_t *prev = NULL;

    // Prechádzame zoznam a hľadáme prvok
    while (item != NULL) {
        if (strcmp(item->key, key) == 0) {
            // Našli sme prvok na zmazanie
            if (prev == NULL) {
                // Je to prvý prvok v zozname
                (*table)[index] = item->next;
            } else {
                // Je to prvok v strede/na konci zoznamu
                prev->next = item->next;
            }

            // Uvoľníme pamäť
            free(item->key);
            free(item);
            return;
        }
        prev = item;
        item = item->next;
    }
}

/*
 * Smazání všech prvků z tabulky.
 *
 * Funkce korektně uvolní všechny alokované zdroje a uvede tabulku do stavu po 
 * inicializaci.
 */
void ht_delete_all(ht_table_t *table) {
    // Prechádzame všetky položky tabuľky
    for (int i = 0; i < HT_SIZE; i++) {
        ht_item_t *item = (*table)[i];

        // Postupne mažeme všetky prvky v zozname synoným
        while (item != NULL) {
            ht_item_t *next = item->next;
            free(item->key);
            free(item);
            item = next;
        }

        // Inicializujeme položku na NULL
        (*table)[i] = NULL;
    }
}
