/** 
 * @file llassoclist.h
 * @brief LLAssocList class header file
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 * 
 * Copyright (c) 2001-2009, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#ifndef LL_LLASSOCLIST_H
#define LL_LLASSOCLIST_H

//------------------------------------------------------------------------
// LLAssocList is an associative list container class.
//
// The implementation is a single linked list.
// Both index and value objects are stored by value (not reference).
// If pointer values are specified for index and/or value, this
// container does NOT assume ownership of the referenced objects,
// and does NOT delete() them on removal or destruction of the container.
//
// Note that operations are generally not optimized, and may of them
// are O(n) complexity.
//------------------------------------------------------------------------

#include <iostream>

template<class INDEX_TYPE, class VALUE_TYPE>
class LLAssocList
{
private:
	// internal list node type
	class Node
	{
	public:
		Node(const INDEX_TYPE &index, const VALUE_TYPE &value, Node *next)
		{
			mIndex = index;
			mValue = value;
			mNext = next;
		}
		~Node() { }
		INDEX_TYPE	mIndex;
		VALUE_TYPE	mValue;
		Node		*mNext;
	};

	// head of the linked list
	Node *mHead;

public:
	// Constructor
	LLAssocList()
	{
		mHead = NULL;
	}

	// Destructor
	~LLAssocList()
	{
		removeAll();
	}

	// Returns TRUE if list is empty.
	BOOL isEmpty()
	{
		return (mHead == NULL);
	}

	// Returns the number of items in the list.
	U32 length()
	{
		U32 count = 0;
		for (	Node *node = mHead;
				node;
				node = node->mNext )
		{
			count++;
		}
		return count;
	}

	// Removes item with the specified index.
	BOOL remove( const INDEX_TYPE &index )
	{
		if (!mHead)
			return FALSE;

		if (mHead->mIndex == index)
		{
			Node *node = mHead;
			mHead = mHead->mNext;
			delete node;
			return TRUE;
		}

		for (	Node *prev = mHead;
				prev->mNext;
				prev = prev->mNext )
		{
			if (prev->mNext->mIndex == index)
			{
				Node *node = prev->mNext;
				prev->mNext = prev->mNext->mNext;
				delete node;
				return TRUE;
			}
		}
		return FALSE;
	}

	// Removes all items from the list.
	void removeAll()
	{
		while ( mHead )
		{
			Node *node = mHead;
			mHead = mHead->mNext;
			delete node;
		}
	}

	// Adds a new item to the head of the list,
	// removing any existing item with same index.
	void addToHead( const INDEX_TYPE &index, const VALUE_TYPE &value )
	{
		remove(index);
		Node *node = new Node(index, value, mHead);
		mHead = node;
	}

	// Adds a new item to the end of the list,
	// removing any existing item with the same index.
	void addToTail( const INDEX_TYPE &index, const VALUE_TYPE &value )
	{
		remove(index);
		Node *node = new Node(index, value, NULL);
		if (!mHead)
		{
			mHead = node;
			return;
		}
		for (	Node *prev=mHead;
				prev;
				prev=prev->mNext )
		{
			if (!prev->mNext)
			{
				prev->mNext=node;
				return;
			}
		}
	}

	// Sets the value of a specified index.
	// If index does not exist, a new value will be added only if
	// 'addIfNotFound' is set to TRUE.
	// Returns TRUE if successful.
	BOOL setValue( const INDEX_TYPE &index, const VALUE_TYPE &value, BOOL addIfNotFound=FALSE )
	{
		VALUE_TYPE *valueP = getValue(index);
		if (valueP)
		{
			*valueP = value;
			return TRUE;
		}
		if (!addIfNotFound)
			return FALSE;
		addToTail(index, value);
		return TRUE;
	}

	// Sets the ith value in the list.
	// A new value will NOT be addded, if the ith value does not exist.
	// Returns TRUE if successful.
	BOOL setValueAt( U32 i, const VALUE_TYPE &value )
	{
		VALUE_TYPE *valueP = getValueAt(i);
		if (valueP)
		{
			*valueP = value;
			return TRUE;
		}
		return FALSE;
	}

	// Returns a pointer to the value for the specified index,
	// or NULL if no item found.
	VALUE_TYPE *getValue( const INDEX_TYPE &index )
	{
		for (	Node *node = mHead;
				node;
				node = node->mNext )
		{
			if (node->mIndex == index)
				return &node->mValue;
		}
		return NULL;
	}

	// Returns a pointer to the ith value in the list, or
	// NULL if i is not valid.
	VALUE_TYPE *getValueAt( U32 i )
	{
		U32 count = 0;
		for (	Node *node = mHead;
				node;
				node = node->mNext )
		{
			if (count == i)
				return &node->mValue;
			count++;
		}
		return NULL;
	}

	// Returns a pointer to the index for the specified index,
	// or NULL if no item found.
	INDEX_TYPE *getIndex( const INDEX_TYPE &index )
	{
		for (	Node *node = mHead;
				node;
				node = node->mNext )
		{
			if (node->mIndex == index)
				return &node->mIndex;
		}
		return NULL;
	}

	// Returns a pointer to the ith index in the list, or
	// NULL if i is not valid.
	INDEX_TYPE *getIndexAt( U32 i )
	{
		U32 count = 0;
		for (	Node *node = mHead;
				node;
				node = node->mNext )
		{
			if (count == i)
				return &node->mIndex;
			count++;
		}
		return NULL;
	}

	// Returns a pointer to the value for the specified index,
	// or NULL if no item found.
	VALUE_TYPE *operator[](const INDEX_TYPE &index)
	{
		return getValue(index);
	}

	// Returns a pointer to the ith value in the list, or
	// NULL if i is not valid.
	VALUE_TYPE *operator[](U32 i)
	{
		return getValueAt(i);
	}

	// Prints the list contents to the specified stream.
	friend std::ostream &operator<<( std::ostream &os, LLAssocList &map )
	{
		os << "{";
		for (	Node *node = map.mHead;
				node;
				node = node->mNext )
		{
			os << "<" << node->mIndex << ", " << node->mValue << ">";
			if (node->mNext)
				os << ", ";
		}
		os << "}";

		return os;
	}
};

#endif // LL_LLASSOCLIST_H