#ifndef MvList_H
#define MvList_H

/****************************************************************************
* 
* Classes MvLink and MvList - sorted double linked list
*
****************************************************************************/

typedef enum { NoCase, LowerCase, UpperCase } ListCase;
typedef enum { SequentialList, SortedList} ListType;
typedef enum { NoSortBy, SortListByCode, SortListByName } ListSortBy;
typedef enum { NoSortType, SortListSingular, SortListMultiple } ListSortType;

#include <MvElement.hpp>

class MvList;

//
// Class MvLink
//
// This class is used exclusively by the MvList and implement one
// entry of the linked list
//

class MvLink
{
protected:

	friend	class	MvList;
	MvElement*	_self;
	MvLink*		_next;
	MvLink*		_previous;

public:
	MvLink (MvElement* itself, MvLink* previous = NULL, MvLink* next = NULL)
	{ _self = itself; _next = next; _previous = previous; _self->increment(); }

	~MvLink () { _self->decrement(); }
};

//
// Class MvList
//
// This class implements sorted double linked list
//

class MvList
{
protected :

	MvLink*			_first;
	MvLink*			_last;
	int			_n;
	MvLink*			_current;
	int			_curpos;	// position of current element
	int			_protect;

	ListType		_list_type;
	ListSortBy		_sort_by;
	ListSortType		_sort_type;
	ListCase		_list_case;

// Private functions

	void searchInit ();

	void insertPrivate(int, MvElement*);
	void insertFirstPrivate(MvElement* v) { insertPrivate(0,v); }
	void insertLastPrivate(MvElement*);

	void sort(int pos, MvLink*);
	int compare(MvLink*, MvLink*);

public:
	MvList (int protect = 0);
	//	Constructor
	//	Input:
	//		deleteElement: if TRUE, MvElement is deleted when MvLink

	MvList (ListType, ListSortBy, ListSortType, ListCase, int protect = 0, MvElement * = 0L);
	//	Constructor of empty list
	//	Input:
	//		type, link type, sort, sorttype and case
	//		deleteElement: if TRUE, MvElement is deleted when MvLink
	//		first element of the list

	~MvList () { removeAll(); }
	//	Delete list and components

	void removeAll();
	//	The list is emptied and all the contents deleted

	void setListTypes(ListType, ListSortBy, ListSortType, ListCase);

	void print(const char* = NULL);
	//	Print contents of the list
	//	Input:
	//		header to be printed before the list

// Inquire Functions

	MvElement* first();
	//	Return:
	//		first element of list and initialize sequential
	//		retrieval

	MvElement* last() { return (_last ? _last->_self : NULL); } 
	//	Return:
	//		last element of list

	MvElement* next();
	//	Return next element of list

	MvElement* previous();
	//	Resturn previous element of list

	MvElement* current() { return (_current ? _current->_self : NULL); }
	//	Return current element of list

	MvElement* get(int posit);
	//	Input:
	//		position of element, starting from 0

	//	Return:
	//		element in the desired position

	int positionOf(MvElement*);
	//	Input:
	//		element
	//	Return:
	//		position of element starting from 0, if not found -1

	int size() { return _n; }
	//	Return:
	//		List size

	inline ListType getListType()		{ return _list_type; }
	inline ListSortBy getSortBy()		{ return _sort_by; }
	inline ListSortType getSortType()	{ return _sort_type; }
	inline int getListCase() 		{ return _list_case; }
	inline int isEmpty() 			{ return _n==0; }

// Search

	MvElement* findByCode (int);
	MvElement* findByName (const char *);
	MvElement* findNearestCode (int);
	MvElement* findNearestName (const char *);

// Edit List

	void protectElement () { _protect = 1; }
	//	Set protection flag. Does not delete MvElement
	//	when the entry in the list is deleted

	void unprotectElement () { _protect = 1; }
	//	Reset protection flag. Will delete MvElement
	//	when the entry in the list is deleted

	void insert (int, MvElement*);
	//	Put element in a certain position
	//	Input:
	//		position to insert element, starting from 0
	//		pointer to element

	void insertFirst (MvElement* elem) { insert(0, elem); }
	//	Insert element at the beginning of the list
	//	Input:
	//		pointer to element

	void insertLast (MvElement*);
	//	Put element at the end of the List
	//	Input:
	//		element

	void append (MvElement* elem) { insertLast(elem); }

	void insertBeforeCurr(MvElement*);

	void insertAfterCurr(MvElement*);

	void replaceCurr(MvElement*);

	MvElement* insertByType(MvElement*);
	//	Include by Type
	//	May fail if only singular occurrences allowed

	MvElement* extract( int posit );
	// Removes object from the list without destroying it

	MvElement* extract(MvElement* elem){ return extract(positionOf(elem)); }
	// Removes object from the list without destroying it

	int remove(int posit);
	//	Remove element from list. If the element does not
	//	occurr in any other list and the list is not of type
	//	'protected', the element is deleted too.
	//	Input:
	//		position to be deleted
	//	Return:
	//		1 if deleted

	int remove(MvElement* elem) { return remove(positionOf(elem)); }
	//	Remove element from list. If the element does not
	//	occurr in any other list and the list is not of type
	//	'protected', the element is deleted too.
	//	Input:
	//		pointer to element
	//	Return:
	//		1 if deleted

	void removeCurr();
	//	Remove current element

	void removeByCode (int);
	void removeByName (const char *);

	void sort();
// Utility

	void convertCase (char *);
};

#endif
