#pragma once

#include "vdata.h"
#include "iterator.h"
#include "link.h"

class PlugStream;

typedef Enumeration NodeCommandID;

enum
{
	NodeNullCommandID = 0,
	NodeNextCommandID
};

class PlugIterator;

class Plug : public RegisteredClass
{
	friend class Link;
	friend class PlugIterator;

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

protected:
	Plug(ClassID class_id = TrivialPlugClassID);
	Plug(PlugStream *stream);

private:
	Link *linkHead;
};

template <class T> class PlugOf : public Plug
{
public:
	PlugOf(const T &item);
	~PlugOf();

	operator T() const	{ return item; }

	T GetItem() const	{ return item; }
	T *GetPointer()		{ return &item; }

private:
	T item;
};

template <class T> PlugOf<T>::PlugOf(const T &the_item)
{
	item = the_item;
}

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

class PlugIterator : public Iterator
{
public:
	PlugIterator(const Plug *plug, RegisteredClass::ClassID class_to_iterate = RegisteredClass::NullClassID);
	PlugIterator(const PlugIterator &iterator);
	~PlugIterator();

	Logical TestInstance() const;

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

	int SendNodeCommand(NodeCommandID node_command, void *info = NULL);

	void RemoveSocket(Socket *socket);

protected:
	void *ReadAndNextImplementation();
	void *ReadAndPreviousImplementation();
	void *GetCurrentImplementation();
	void *GetNthImplementation(CollectionSize index);

protected:
	const Plug *plug;
	Link *currentLink;

private:
	RegisteredClass::ClassID classToIterate;

	void NextNode();
	void PreviousNode();
};

template <class T> class PlugIteratorOf : public PlugIterator
{
public:
	PlugIteratorOf(const Plug *plug, RegisteredClass::ClassID class_to_iterate=RegisteredClass::NullClassID);
	PlugIteratorOf(const Plug &plug, RegisteredClass::ClassID class_to_iterate=RegisteredClass::NullClassID);
	PlugIteratorOf(const PlugIteratorOf<T> &iterator);

	~PlugIteratorOf();

	T ReadAndNext()		{ return (T)ReadAndNextImplementation(); }
	T ReadAndPrevious()	{ return (T)ReadAndPreviousImplementation(); }
	T GetCurrent()		{ return (T)GetCurrentImplementation(); }
	T GetNth(CollectionSize index)	{ return (T)GetNthImplementation(index); }

#if 0
	Logical operator !()	{ return currentLink == NULL; }
	operator T()	{ return GetCurrent(); }
	T operator->()	{ return GetCurrent(); }
	PlugIteratorOf<T>& operator++()
	{
		Next();
		return *this;
	}
	PlugIteratorOf<T>& operator--()
	{
		Previous();
		return *this;
	}
	T operator++(int)	{ return ReadAndNext(); }
	T operator--(int)	{ return ReadAndPrevious(); }
#endif
};

template <class T> PlugIteratorOf<T>::PlugIteratorOf(const Plug *plug, RegisteredClass::ClassID class_to_iterate) : PlugIterator(plug, class_to_iterate)
{
}

template <class T> PlugIteratorOf<T>::PlugIteratorOf(const Plug &plug, RegisteredClass::ClassID class_to_iterate) : PlugIterator(&plug, class_to_iterate)
{
}

template <class T> PlugIteratorOf<T>::PlugIteratorOf(const PlugIteratorOf<T> &iterator) : PlugIterator(iterator)
{
}

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