/// @file templates.hh
/// @author Stefan Schmitt <sschmitt@ee.uwa.edu.au>
/// @version 1.0
/// @date 2003-07
/// 
/// Declares various class templates and template-like macros.

#ifndef TEMPLATES_HH
#define TEMPLATES_HH

namespace EyeMind {

/// Provide access to a single instance of CLASS. To be used in \c public:
/// declaration section of a class. See also NO_COPYING. CLASS::I() will 
/// return a reference to the single instance. The instance is created when it
/// is first needed and is automatically destroyed after main().

#define SINGLETON(CLASS) \
static CLASS& I() \
{ \
	static CLASS instance; \
	return instance; \
}


/// Companion to the SINGLETON macro, to be used in \c private: declaration.
/// Prevents copying of an instance and can also be used without SINGLETON.
/// You also need to declare the default constructor in the \c private: section
/// for the SINGLETON scheme to work.

#define NO_COPYING(CLASS) \
CLASS(const CLASS&);\
void operator=(const CLASS&){}


}; // namespace EyeMind

#include "base/constants.hh"


namespace EyeMind {

#ifdef EYEBOT
#include "librobi/c-protos.h"
#include "librobi/c-stubs.h"

/// Poor man's exception.
inline void OSPanicIf(bool expr, const char *msg)
{
	// The const_cast is necessary because of some shortcomings in the
	// EyeBot library. OSPanic() does not alter the contents of the string
	// and even if it would, who cares? The system stops working anyway
	// since it's OSPanic()'s big time.
	if (expr) OSPanic(const_cast<char*>(msg));
}

#else
#warning OSPanicIf does nothing
inline void OSPanicIf(bool expr, const char *msg){}
#endif //EYEBOT


/// Clips an int to min/max.
inline int clip(int value, int min, int max)
{
	if (value < min)
		return min;

	if (value > max)
		return max;

	return value;
}


/// Clips an unsigned to min/max.
inline unsigned clip(unsigned value, unsigned min, unsigned max)
{
	if (value < min)
		return min;

	if (value > max)
		return max;

	return value;
}


/// Clips a float to min/max.
inline float clip(float value, float min, float max)
{
	if (value < min)
		return min;

	if (value > max)
		return max;

	return value;
}



/// Default number of elements in Array collection.
const unsigned DEFAULT_ARRAY_SIZE=8;


/// Iterable pointer collection (lightweight, array-based, evil).
/// 
/// Provides operators to add, remove, iterate and read elements, but there are
/// no functions for altering the elements. The iteration is quite different
/// to the STL containers, so watch out.
/// 
/// @warning: Iteration is not thread-safe. Provide thread-safety in your user
/// program by preventing task-switching around iteration calls (if needed).

template <typename T, const unsigned size = DEFAULT_ARRAY_SIZE>
class Array
{
private:
	unsigned pos;  ///< Current iterator position.
	unsigned next; ///< Next element counter.
	T* data[size]; ///< Container for T.

	NO_COPYING(Array); ///< Prevent copying.

public:
	/// Default constructor; initializes data members with NULL.
	Array();

	/// @name Attribute manipulation functions.
	//@{
	unsigned Pos(){ return pos; } ///< Returns curren iterator position.
	void Pos(unsigned i){ pos=i; } ///< Sets iterator position.
	unsigned Size(){ return size; } ///< Returns max size of Array.
	unsigned Count(){ return next; } ///< Returns element count.
	//@}


	/// Add T to Array. This operator changes the instance. You may not
	/// expect this from an addition operator, but since it is not possible
	/// to create a symmetry to the substraction operator it is implemented
	/// in this way.
	/// 
	/// Note: The += and -= operators would not lead to symmetry, too.
	
	Array& operator+(T& e);


	/// Append T to Array. If the Array has reached the maximum size, a
	/// pointer to the first element is returned.
	/// @param e Reference to element to be appended.
	/// @returns Pointer to the removed element, NULL else.

	T* Append(T& e);


	/// Remove T at position \b i from Array.
	/// @param i Position of element to be removed
	/// @returns Removed T*
	/// 
	/// This operator changes the instance. (see addition operator)

	T* operator-(const unsigned i);


	/// Remove T referenced by e from Array.
	/// @param e Reference to element to be removed.
	/// @returns Removed T* if found, NULL else.
	/// 
	/// This operator changes the instance. (see addition operator)

	T* operator-(T& e);

	/// @name Iterator functions and operators.
	//@{
	/// Initialize T iterator; returns first T*.
	T* Begin();

	/// Initialize T reverse iterator; returns first T*.
	T* RBegin();

	/// Iterate through Ts; prefix ++; returns next T*.
	T* operator++(); //prefix

	/// Iterate through Ts; postfix ++; returns next T*.
	T* operator++(int); //postfix
	
	/// Iterate reverse through Ts; prefix --; returns next T*.
	T* operator--(); //prefix
	
	/// Iterate reverse through Ts; postfix --; returns next T*.
	T* operator--(int); //postfix

	/// Indexing operator; returns T* at index i.
	T* operator[](unsigned i) const;

	//@}


	/// Find index of \b e in Array
	/// @param e Element to find
	/// @return Index of element if found, NOK else
	
	int Find(T& e);
};


template <typename T, unsigned size>
Array<T, size>::Array()
{
	for (unsigned i = 0;i < size;i++)
		data[i] = NULL;

	pos = 0;
	next = 0;
}


template <typename T, unsigned size>
Array<T, size>& Array<T, size>::operator+(T& e)
{
	OSPanicIf(next >= size, "Array full");

	data[next] = &e;
	next++;

	return *this; // make chaining possible: Array+Element+Element+..
}


template <typename T, unsigned size>
T* Array<T, size>::Append(T& e)
{
	T *temp = NULL;

	if (next < size)
		*this + e;
	else {
		temp = *this - 0;
		*this + e;
	}

	return temp;
}
		

template <typename T, unsigned size>
T* Array<T, size>::operator-(unsigned i)
{
	T* temp;

	if (i < size) {
		temp = data[i];

		for (i = i; i < size; i++)
			data[i] = data[i + 1];

		return temp;
	} else {
		return NULL;
	}
}


template <typename T, unsigned size>
T* Array<T, size>::operator-(T& e)
{
	int temp=Find(e);
	
	if (temp >= 0)
		return (*this - temp);
	else
		return NULL;
}


template <typename T, unsigned size>
T* Array<T, size>::operator[](unsigned i) const
{
	if (i < size)
		return data[i];
	else
		return NULL;
}


template <typename T, unsigned size>
T* Array<T, size>::Begin()
{
	Pos(0);
	return data[pos];
}


template <typename T, unsigned size>
T* Array<T, size>::RBegin()
{
	unsigned temp = next;

	if (temp > 0)
		--temp;
	Pos(temp);
	
	return data[pos];
}


template <typename T, unsigned size>
T* Array<T, size>::operator++()
{
	++pos;
	if (pos < size)
		return data[pos];
	else
		return NULL;
}


template <typename T, unsigned size>
T* Array<T, size>::operator++(int)
{
	if (pos < size) {
		++pos;
		return data[pos-1];
	} else
		return NULL;
}


template <typename T, unsigned size>
T* Array<T, size>::operator--()
{
	// pos is unsigned, so decrementing it at 0 will make it UINT_MAX and
	// is thus never less than size (which has also a maximum of UINT_MAX)
	--pos;
	if (pos < size)
		return data[pos];
	else
		return NULL;
}


template <typename T, unsigned size>
T* Array<T, size>::operator--(int)
{
	if (pos < size) {
		--pos;
		return data[pos+1];
	} else
		return NULL;
}


template <typename T, unsigned size>
int Array<T, size>::Find(T& e)
{
	for(unsigned i = 0; i < next; ++i)
		if (data[i] == &e)
			return i;

	return NOK;
}



/// Iterable pointer collection (lightweight, linked-list-based).
/// 
/// Provides operators to add, remove and iterate elements.
/// 
/// @warning: Iteration is not thread-safe. Provide thread-safety in your user
/// program by preventing task-switching around iteration calls (if needed).

template <typename T>
class LinkedList
{
// the friend functions must (?) be defined here, not only declared. ugly, but
// at least this does what it should

/// Append T to LinkedList.
/// This operator changes the instance. You may not expect this from an
/// addition operator, but since it is not possible to create a symmetry to the
/// substraction operator it is implemented in this way.
/// 
/// Note: The += and -= operators would not lead to symmetry, too.
	
friend LinkedList& operator+(LinkedList<T>& l, T& e){ return l.Append(e); }


/// Prepend T to LinkedList.
/// This operator changes the instance. You may not expect this from an
/// addition operator, but since it is not possible to create a symmetry to the
/// substraction operator it is implemented in this way.
/// 
/// Note: The += and -= operators would not lead to symmetry, too.

friend LinkedList& operator+(T& e, LinkedList<T>& l){ return l.Prepend(e); }
private:
	/// Linked list type.
	struct LList {
		T* entity;
		LList* next;
	};

	LList* first; ///< List anchor.
	LList* last; ///< Last element pointer.
	LList* pos; ///< Current iterator position.
		
	unsigned count; ///< Element counter.

	NO_COPYING(LinkedList); ///< Prevent copying.

public:
	/// Default constructor; initializes data members.
	LinkedList();

	/// Destructor; deletes all list elements, but nor the entities they
	/// are pointing to.
	~LinkedList();

	/// @name Attribute manipulation functions.
	//@{
	unsigned Count(){ return count; }
	//@}
	
	/// Append a T to the end of the LinkedList.
	LinkedList& Append(T& e);

	/// Prepend a T to the start of the LinkedList.
	LinkedList& Prepend(T& e);


	/// Remove T referenced by e from LinkedList.
	/// @param e Reference to element to be removed.
	/// @returns Removed T* if found, NULL else.
	/// 
	/// This operator changes the instance. (see addition operator)
	
	T* operator-(T& e);


	/// @name Iterator functions and operators
	//@{
	/// Initialize T iterator; returns first T*.
	T* Begin();

	/// @name Iterate through Ts; prefix ++; returns next T*.
	T* operator++(); //prefix

	/// @name Iterate through Ts; postfix ++; returns next T*.
	T* operator++(int); //postfix
	
	//@}
};


template <typename T>
LinkedList<T>::LinkedList() : first(NULL), last(NULL), pos(NULL), count(0)
{
}


template <typename T>
LinkedList<T>::~LinkedList()
{
	LList* temp = first;
	
	while (temp) {
		LList* next = temp->next;
		delete temp;
		temp = next;
	};
}


template <typename T>
LinkedList<T>& LinkedList<T>::Append(T& e)
{
	LList* temp = new LList;
	temp->next = NULL;
	temp->entity = &e;

	if (first)
		last->next = temp;
	else // when creating the first element
		first = temp;
		
	last = temp;
	++count;

	return *this;
}
	

template <typename T>
LinkedList<T>& LinkedList<T>::Prepend(T& e)
{
	LList* temp = new LList;
	temp->next = first;
	temp->entity = &e;

	if (!last) // when creating the first element
		last = temp;

	first = temp;
	++count;

	return *this;
}


template <typename T>
T* LinkedList<T>::operator-(T& e)
{
	// is list empty?
	if (first == NULL)
		return NULL;

	// is element to be removed the first one?
	if (first->entity == &e) {
		LList* temp = first;
		first = first->next;
		if (first == NULL)
			last = NULL;
		delete temp;
		--count;
		return &e;
	}
			
	// so the element is somewhere else in the list
	LList* prev = first;
	LList* temp = first->next;
	while (temp) {
		if (temp->entity == &e) {
			if (last == temp) // when removing last element
				last = prev;
			prev->next = temp->next;
			delete temp;
			--count;
			return &e;
		};
		prev = temp;
		temp = temp->next;
	};

	// not found
	return NULL;
}



template <typename T>
T* LinkedList<T>::Begin()
{
	pos = first;
	if (pos)
		return pos->entity;
	else
		return NULL;
}

template <typename T>
T* LinkedList<T>::operator++()
{
	if (pos)
		pos = pos->next;
	
	if (pos)
		return pos->entity;
	else
		return NULL;
}

template <typename T>
T* LinkedList<T>::operator++(int)
{
	LList* temp = pos;

	if (pos)
		pos = pos->next;
	
	if (temp)
		return temp->entity;
	else
		return NULL;
}
	

}; // namespace EyeMind

#endif // TEMPLATES_HH
