#pragma once

#include "sfeskt.h"
#include "memblock.h"

#define SCHAINLINK_MEMORYBLOCK_ALLOCATION (100)

class SChainLink : public Link
{
	friend class SChain;
	friend class SChainIterator;

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

private:
	SChainLink(SChain *chain, Plug *plug, SChainLink *nextSChainLink, SChainLink *prevSChainLink);

	SChainLink *nextSChainLink;
	SChainLink *prevSChainLink;

private:
	static MemoryBlock* GetAllocatedMemory();

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

class SChain : public SafeSocket
{
	friend class SChainLink;
	friend class SChainIterator;

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

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

protected:
	void AddImplementation(Plug *plug);

private:
	SChainLink* InsertSChainLink(Plug *plug, SChainLink *link);

	SChainLink *head;
	SChainLink *tail;
};

template <class T> class SChainOf : public SChain
{
public:
	SChainOf(Node *node);
	~SChainOf();

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

template <class T> SChainOf<T>::SChainOf(Node *node) : SChain(node)
{
}

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

class SChainIterator : public SafeIterator
{
public:
	SChainIterator(SChain *chain);
	SChainIterator(const SChainIterator &iterator);
	~SChainIterator();

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

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

	SChainLink *currentLink;
};

template <class T> class SChainIteratorOf : public SChainIterator
{
public:
	SChainIteratorOf(SChainOf<T> *chain);
	SChainIteratorOf(SChainOf<T> &chain);
	SChainIteratorOf(const SChainIteratorOf<T> &iterator);

	~SChainIteratorOf();

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

template <class T> SChainIteratorOf<T>::SChainIteratorOf(SChainOf<T> *chain) : SChainIterator(chain)
{
}

template <class T> SChainIteratorOf<T>::SChainIteratorOf(SChainOf<T> &chain) : SChainIterator(&chain)
{
}

template <class T> SChainIteratorOf<T>::SChainIteratorOf(const SChainIteratorOf<T> &iterator) : SChainIterator(iterator)
{
}

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