#pragma once

#include "node.h"
#include "memblock.h"

class Chain;
class ChainIterator;

#define CHAINLINK_MEMORYBLOCK_ALLOCATION (100)

class ChainLink : public Link
{
	friend class Chain;
	friend class ChainIterator;

public:
	~ChainLink();
	Logical TestInstance() const;

private:
	ChainLink(Chain *chain, Plug *plug, ChainLink *nextChainLink, ChainLink *prevChainLink);

	ChainLink *nextChainLink;
	ChainLink *prevChainLink;

private:
	static MemoryBlock* GetAllocatedMemory();

	void *operator new(size_t)	{ return GetAllocatedMemory()->New(); }
	void operator delete(void *where)	{ GetAllocatedMemory()->Delete(where); }
};

class Chain : public Socket
{
	friend class ChainLink;
	friend class ChainIterator;

public:
	Chain(Node *node);
	~Chain();

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

protected:
	void AddImplementation(Plug *plug);

private:
	ChainLink *InsertChainLink(Plug *plug, ChainLink *current_link);

	ChainLink *head, *tail;
};

template <class T> class ChainOf : public Chain
{
public:
	ChainOf(Node *node);
	~ChainOf();

	void Add(T plug)
	{
		Chain::AddImplementation(Cast_Object(Plug*, plug));
	}
};

template <class T> ChainOf<T>::ChainOf(Node *node) : Chain(node)
{
}

template <class T> ChainOf<T>::~ChainOf()
{
}

class ChainIterator : public SocketIterator
{
public:
	ChainIterator(Chain *chain);
	ChainIterator(const ChainIterator &iterator);
	~ChainIterator();

	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);
	void InsertImplementation(Plug*);

	ChainLink *currentLink;
};

template <class T> class ChainIteratorOf : public ChainIterator
{
public:
	ChainIteratorOf(ChainOf<T> *chain);
	ChainIteratorOf(ChainOf<T> &chain);
	ChainIteratorOf(const ChainIteratorOf<T> &iterator);
	~ChainIteratorOf();

	T ReadAndNext()		{ return (T)ReadAndNextImplementation(); }
	T ReadAndPrevious()	{ return (T)ReadAndPreviousImplementation(); }
	T GetCurrent()		{ return (T)GetCurrentImplementation(); }
	T GetNth(CollectionSize index)	{ return (T)GetNthImplementation(index); }
	void Insert(T plug)	{ InsertImplementation(Cast_Object(Plug*, plug)); }

	ChainIteratorOf<T>& Begin()		{ return (ChainIteratorOf<T>&)BeginImplementation(); }
	ChainIteratorOf<T>& End()		{ return (ChainIteratorOf<T>&)EndImplementation(); }
	ChainIteratorOf<T>& Forward()	{ return (ChainIteratorOf<T>&)ForwardImplementation(); }
	ChainIteratorOf<T>& Backward()	{ return (ChainIteratorOf<T>&)BackwardImplementation(); }

#if 0
	Logical operator!()	{ return currentLink == NULL; }
	operator T*()		{ return GetCurrent(); }
	T* operator->()		{ return GetCurrent(); }
	T& operator*()		{ return *GetCurrent(); }

	ChainIteratorOf<T>& operator++()
	{
		Next();
		return *this;
	}

	ChainIteratorOf<T>& operator--()
	{
		Previous();
		return *this;
	}

	T* operator++(int)	{ return ReadAndNext(); }
	T* operator--(int)	{ return ReadAndPrevious(); }
#endif
};

template <class T> ChainIteratorOf<T>::ChainIteratorOf(ChainOf<T> *chain) : ChainIterator(chain)
{
}

template <class T> ChainIteratorOf<T>::ChainIteratorOf(ChainOf<T> &chain) : ChainIterator(&chain)
{
}

template <class T> ChainIteratorOf<T>::ChainIteratorOf(const ChainIteratorOf<T> &iterator) : ChainIterator(iterator)
{
}

template <class T> ChainIteratorOf<T>::~ChainIteratorOf()
{
}