#ifndef HASHTABLE_H
#define HASHTABLE_H

#include <string>
#include <vector>

using namespace std;

/**
   Oblicza skrót ciągu.
   @param str ciąg
   @return skrót
*/
int hash_code(const string& str);

class HashTable;
class Iterator;

class Node
{
private:
   string data;
   Node* next;

friend class HashTable;
friend class Iterator;
};

class Iterator
{
public:
   /**  
      Szuka wartości na danej pozycji.
      @return wartość węzła wskazywanego przez iterator
   */
   string get() const;
   /**
      Przesuwa iterator na następny węzeł.
   */
   void next();
   /**
      Porównuje dwa iteratory.
      @param other iterator porównywany z bieżącym
      @return wartość true, jeśli ten i drugi iterator są jednakowe
   */
   bool equals(const Iterator& other) const;
private:
   const HashTable* container;
   int bucket_index;
   Node* current;
   
friend class HashTable;
};

/**
   Klasa ta zawiera implementację tablicy mieszająceje przy użyciu metody łańcuchowej.
*/
class HashTable
{
public:
   /**
      Konstruuje tablicę mieszającą.
      @param nbuckets liczba kubełków
   */
   HashTable(int nbuckets);

   /**
      Sprawdza, czy element należy już do zbioru.
      @param x sprawdzany potencjalny element zbioru
      @return liczba 1, jeśli obiekt x jest już elementem tego zbioru, w przeciwnym razie 0
   */
   int count(const string& x);

   /**
      Dodaje element do tablicy mieszającej, jeśli jeszcze w niej nie występuje.
      @param x element do dodania
   */
   void insert(const string& x);

   /**
      Usuwa element z tablicy mieszającej, jeśli w niej występuje.
      @param x element do ewentualnego usunięcia
   */
   void erase(const string& x);

   /**
      Zwraca iterator wskazujący początek tablicy mieszającej.
      @return iterator tablicy mieszającej wskazujący na jej początek
   */
   Iterator begin() const;

   /**
      Zwraca iterator wskazujący poza koniec tablicy mieszającej.
      @return iterator tablicy mieszającej wskazujący poza jej koniec
   */
   Iterator end() const;

   /**
      Zwraca liczbę elementów zbioru.
      @return liczba elementów
   */
   int size() const;

private:
   vector<Node*> buckets;
   int current_size;   

friend class Iterator;
};

#endif

