#pragma once

#include "srtskt.h"
#include "memblock.h"

class Table;

class TableEntry : public Link
{
public:
	TableEntry(Table *table, Plug *plug);
	~TableEntry();
};

#define TABLEENTRY_MEMORYBLOCK_ALLOCATION (100)

template <class V> class TableEntryOf : public TableEntry
{
public:
	TableEntryOf(Table *table, Plug *plug, const V &value);
	~TableEntryOf();

	void* operator new(size_t);
	void operator delete(void *where);

	V GetValue()			{ return value; }
	V* GetValuePointer()	{ return &value; }

private:
	static MemoryBlock *allocatedMemory;
	static CollectionSize allocationCount;

	V value;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~ TableEntryOf templates ~~~~~~~~~~~~~~~~~~~~~~~~~~~

template <class V> MemoryBlock* TableEntryOf<V>::allocatedMemory = NULL;
template <class V> CollectionSize TableEntryOf<V>::allocationCount = 0;

template <class V> TableEntryOf<V>::TableEntryOf(Table *table, Plug *plug, const V &value)
	: TableEntry(table, plug)
{
	this->value = value;
}

template <class V> TableEntryOf<V>::~TableEntryOf()
{
}

template <class V> void* TableEntryOf<V>::operator new(size_t)
{
	Verify(allocationCount >= 0);
	if (allocationCount++ == 0)
	{
		allocatedMemory = new MemoryBlock(sizeof(TableEntryOf<V>), TABLEENTRY_MEMORYBLOCK_ALLOCATION, TABLEENTRY_MEMORYBLOCK_ALLOCATION, "TableEntryOf");
		Register_Object(allocatedMemory);
	}
	Verify(allocationCount < INT_MAX);
	Check(allocatedMemory);
	return allocatedMemory->New();
}

template <class V> void	TableEntryOf<V>::operator delete(void *where)
{
	Check(allocatedMemory);
	allocatedMemory->Delete(where);
	if (--allocationCount == 0)
	{
		Unregister_Object(allocatedMemory);
		delete allocatedMemory;
		allocatedMemory = NULL;
	}
	Verify(allocationCount >= 0);
}

const IteratorPosition TableNullIndex = -1;

class Table : public SortedSocket
{
	friend class TableEntry;
	friend class TableIterator;

public:
	Table(Node *node, Logical has_unique_entries);
	~Table();

	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);

private:
	virtual TableEntry *MakeTableEntry(Plug *plug, const void *value);

	virtual int CompareTableEntries(TableEntry *entry1, TableEntry *entry2);

	virtual int CompareValueToTableEntry(const void *value, TableEntry *entry);

	void AddTableEntry(TableEntry *entry);
	void SortTableEntries();
	IteratorPosition SearchForValue(const void *value);
	IteratorPosition SearchForTableEntry(TableEntry *entry);
	void RemoveNthTableEntry(CollectionSize index);

	//
	//--------------------------------------------------------------------
	// Private data
	//--------------------------------------------------------------------
	//
	TableEntry **array;
	CollectionSize numItems;
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~ TableOf ~~~~~~~~~~~~~~~~~~~~~~~~~~~

template <class T, class V> class TableOf : public Table
{
public:
	TableOf(Node *node, Logical has_unique_entries);
	~TableOf();

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

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

private:
	TableEntry* MakeTableEntry(Plug *plug, const void *value)	{ return new TableEntryOf<V>(this, plug, *(V*)value); }
	int CompareTableEntries(TableEntry *entry1, TableEntry *entry2);
	int CompareValueToTableEntry(const void *value, TableEntry *entry);
};

template <class T, class V> TableOf<T, V>::TableOf(Node *node, Logical has_unique_entries)
	: Table(node, has_unique_entries)
{
}

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

#if 0
	template <class T, class V> int TableOf<T, V>::CompareTableEntries(TableEntry *entry1, TableEntry *entry2)
	{
		V result = (V)(Cast_Object(TableEntryOf<V>*, entry1)->GetValue() - Cast_Object(TableEntryOf<V>*, entry2)->GetValue());

		if (result == (V)0)
			return 0;
		return (result > (V)0) ? 1 : -1;
	}
#else
	template <class T, class V> int	TableOf<T, V>::CompareTableEntries(TableEntry *entry1, TableEntry *entry2)
	{
		V *ptr1 = Cast_Object(TableEntryOf<V>*, entry1)->GetValuePointer();
		V *ptr2 = Cast_Object(TableEntryOf<V>*, entry2)->GetValuePointer();

		Check_Pointer(ptr1);
		Check_Pointer(ptr2);

		if (*ptr1 == *ptr2)
			return 0;
		else
			return ((*ptr1 > *ptr2) ? 1 : -1);
	}
#endif

#if 0
	template <class T, class V> int TableOf<T, V>::CompareValueToTableEntry(const void *value, TableEntry *link)
	{
		Check_Pointer(value);

		V result = (V)(*(V*)value - Cast_Object(TableEntryOf<V>*, link)->GetValue());

		if (result == (V)0)
			return 0;
		return (result > (V)0) ? 1 : -1;
	}
#else
	template <class T, class V> int TableOf<T, V>::CompareValueToTableEntry(const void *value, TableEntry *link)
	{
		Check_Pointer(value);

		V *ptr = Cast_Object(TableEntryOf<V>*, link)->GetValuePointer();
		Check_Pointer(ptr);

		if (*(V*)value == *ptr)
			return 0;
		else
			return (*(V*)value > *ptr) ? 1 : -1;
	}
#endif

class TableIterator : public SortedIterator
{
public:
	TableIterator(Table *table);
	~TableIterator();
	Logical TestInstance() const;

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

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

	TableEntry* GetCurrentEntry()	{ return NthEntry(currentPosition); }

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

	TableEntry* NthEntry(CollectionSize index)
	#if DEBUG_LEVEL>0
		;
	#else
		{ return array[index]; }
	#endif

	void IncrementPosition()
	{
		if (++currentPosition >= numItems)
			currentPosition = TableNullIndex;
	}
	void DecrementPosition()
	{
		if (--currentPosition < 0)
			currentPosition = TableNullIndex;
	}

	TableEntry **array;
	CollectionSize numItems;
	IteratorPosition currentPosition;			
};

template <class T, class V> class TableIteratorOf : public TableIterator
{
public:
	TableIteratorOf(TableOf<T, V> *table);
	TableIteratorOf(TableOf<T, V> &table);
	~TableIteratorOf();

	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); }
	V GetValue()					{ return Cast_Object(TableEntryOf<V>*, GetCurrentEntry())->GetValue(); }
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~ TableIteratorOf templates ~~~~~~~~~~~~~~~~~~~~~~~~~~~

template <class T, class V> TableIteratorOf<T, V>::TableIteratorOf(TableOf<T, V> *table) : TableIterator(table)
{
}

template <class T, class V> TableIteratorOf<T, V>::TableIteratorOf(TableOf<T, V> &table) : TableIterator(&table)
{
}

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