#pragma once

#include "srtskt.h"
#include "vchain.h"

class Hash : public SortedSocket
{
	friend class HashIterator;

public:
	Hash(CollectionSize size, Node *node, Logical has_unique_entries);
	~Hash();

	Logical TestInstance() const;
	static Logical TestClass();
	static Logical ProfileClass();

protected:
	void AddImplementation(Plug *plug);
	void AddValueImplementation(Plug *plug, const void *value);
	Plug *FindImplementation(const void *value);

	VChain **hashTable;
	CollectionSize hashTableSize;

private:
	virtual VChain* MakeVChain();

	virtual IteratorPosition GetHashIndex(const void *value);

	void BuildHashTable();
};

template <class T, class V> class HashOf : public Hash
{
public:
	HashOf(CollectionSize size, Node *node, Logical has_unique_entries);
	~HashOf();

	void AddValue(T plug, const V &value)	{ AddValueImplementation(Cast_Object(Plug*, plug), &value); }

	T Find(const V &value)	{ return (T)FindImplementation(&value); }

private:
	VChain *MakeVChain();

	IteratorPosition GetHashIndex(const void *value);
};

template <class T, class V> HashOf<T, V>::HashOf(CollectionSize size, Node *node, Logical has_unique_entries) : Hash(size, node, has_unique_entries)
{
}

template <class T, class V> HashOf<T, V>::~HashOf()
{
}

template <class T, class V> VChain *HashOf<T, V>::MakeVChain()
{
	return new VChainOf<T, V>(GetReleaseNode(), HasUniqueEntries());
}

template <class T, class V> IteratorPosition HashOf<T, V>::GetHashIndex(const void *value)
{
	Check_Pointer(value);
	return (IteratorPosition(*(V*)value) % hashTableSize);
	// return ((IteratorPosition)*(V*)value % hashTableSize);
}

class HashIterator : public SortedIterator
{
public:
	HashIterator(Hash *hash);
	~HashIterator();
	Logical TestInstance() const;

	void First();
	void Last();
	void Next();
	void Previous();
	CollectionSize GetSize();
	void Remove();

protected:
#if 0
	void *ReadAndNextImplementation();
	void *ReadAndPreviousImplementation();
#endif
	void *GetCurrentImplementation();
#if 0
	void *GetNthImplementation(CollectionSize index);
#endif
	Plug *FindImplementation(const void *value);

private:
	void ReceiveMemo(IteratorMemo memo, void *content);

	void DeleteVChainIterator();

	void NextVChainIterator(IteratorPosition index);

	VChain **hashTable;
	CollectionSize hashTableSize;
	IteratorPosition currentPosition;
	VChainIterator *vchainIterator;
};

template <class T, class V> class HashIteratorOf : public HashIterator
{
public:
	HashIteratorOf(HashOf<T, V> *hash);
	HashIteratorOf(HashOf<T, V> &hash);
	~HashIteratorOf();

	T ReadAndNext()					{ return (T)ReadAndNextImplementation(); }
	T ReadAndPrevious()				{ return (T)ReadAndPreviousImplementation(); }
	T GetCurrent()					{ return (T)GetCurrentImplementation(); }
	T GetNth(CollectionSize index)	{ return (T)GetNthImplementation(index); }
	T Find(const V &value)			{ return (T)FindImplementation(&value); }
};

template <class T, class V> HashIteratorOf<T, V>::HashIteratorOf(HashOf<T, V> *hash) : HashIterator(hash)
{
}

template <class T, class V> HashIteratorOf<T, V>::HashIteratorOf(HashOf<T, V> &hash) : HashIterator(&hash)
{
}

template <class T, class V> HashIteratorOf<T, V>::~HashIteratorOf()
{
}