/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__NARRAYLIST__
#define	__NARRAYLIST__


		#include "container/narray.h"
		#include "log/log.h"


namespace GS {

/*!
	@short	Array list.

	A flexible structure with faster access time (both linear and random) and
	tighter memory usage than lists.

	Especially suited for small types such as pointers.

	@author Emmanuel Julien (ejulien@gsworks.fr)
*/
template <class T> class ArrayList
{
		Array <T>		array;
		Array <uint>	usage_map;

		uint			usage;		///< Array usage.
		uint			grow_step;

		//----------------------------------------------------------------------
inline	bool			Grow()
		{
			if	(int(usage) >= int(array.GetCount() - 1))
				return Resize(array.GetCount() + grow_step);
			return true;
		}
inline	bool			Shrink()
		{
			if	(((int)array.GetCount() - 1) > (int)grow_step)
				if	((int)usage < ((int)array.GetCount() - 1 - (int)grow_step))
					return Resize(array.GetCount() - grow_step);
			return true;
		}
		//----------------------------------------------------------------------

public:

		//----------------------------------------------------------------------
		class Iterator
		{
				const ArrayList <T> &list;
				uint			i;

		public:

		inline	void			Reset(uint from = 0) { i = from; }
		inline	bool			IsOver() const { return i < list.GetCount() ? false : true; }

		inline	void			operator++() { ++i; }

		inline	T				&Object() { return list[i]; }
		inline	T				ObjectPtr() { return list[i]; }

				Iterator(const ArrayList <T> &_list, uint from = 0) : list(_list), i(from) {}
		};
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
inline	uint			GetCount() const
		{	return usage;	}

inline	T				&ObjectAt(int n) const
		{	return array[usage_map[n]];	}
inline	T				&ObjectAt(uint n) const
		{	return array[usage_map[n]];	}

inline	T				&operator [] (int n) const
		{	return array[usage_map[n]];	}
inline	T				&operator [] (uint n) const
		{	return array[usage_map[n]];	}

inline	void			SetGrowStep(uint step)
		{	grow_step = step;	}
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
		/// Insert a new value in the list.
virtual	bool			Insert(const T &v, uint at)
		{
			Grow();

			// Claim entry...
			uint claimed = usage_map[usage];

			// ...and shift usage map.
			for (int n = (int)usage - 1; n >= (int)at; --n)
				usage_map[n + 1] = usage_map[n];

			usage_map[at] = claimed;
			usage++;

			array[claimed] = v;
			array[usage_map[usage]] = 0;	// enforce terminator
			return true;
		}
		/// Add a new value to the end of the list.
		bool			Add(const T &v)
		{
			return Insert(v, usage);
		}
		/// Return the index at which a value is first found in the list.
		int				IndexOf(const T &v, uint from = 0)
		{
			for	(uint i = from; i < usage; ++i)
				if	(array[usage_map[i]] == v)
					return i;
			return -1;
		}
		/// Remove an entry from the list.
virtual	bool			RemoveAt(uint i)
		{
			if	(usage == 0)
				return false;

			// Reclaim entry...
			 uint reclaimed = usage_map[i];

			// ...and shift usage map.
			for	(uint n = i + 1; n < usage; ++n)
				usage_map[n - 1] = usage_map[n];

			usage_map[usage - 1] = reclaimed;
			usage--;

			array[reclaimed] = 0;	// enforce terminator

			Shrink();
			return true;
		}
		bool			Remove(const T &v)
		{
			int i = IndexOf(v);
			return i != -1 ? RemoveAt(i) : false;
		}
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
		ArrayList <T>	&operator = (const T &v)
		{
			if	(this != &v)
			{
				Clear();
				for (uint n = 0; n < v.GetCount(); ++n)
					Add(v[n]);
			}
			return *this;
		}
		ArrayList <T>	&operator << (const T &v)
		{
			Add(v);
			return *this;
		}
		//----------------------------------------------------------------------

		//----------------------------------------------------------------------
		bool			Resize(uint new_size)
		{
			if	((int)new_size == (int)array.GetCount() - 1)
				return true;

			Array <T> _array(new_size + 1);
			if	(_array.IsNull())
				__ERR__(__LOG_E__ << "Failed to allocate new array.\n", false)

			for	(uint n = 0; n < usage; ++n)
				_array[n] = array[usage_map[n]];
			array.Transfer(_array);

			if	(!usage_map.Allocate(new_size + 1))
				__ERR__(__LOG_E__ << "Failed to allocate array bookkeeping structures.\n", false)

			for	(uint n = 0; n < (new_size + 1); ++n)
				usage_map[n] = n;

			array[usage_map[usage]] = 0;	// enforce terminator
			return true;
		}
		/*!
			@short	Clear the container.

			Pass false to prevent the internal structures from being released,
			the array list will keep its current capacity and only its usage map
			will be reset.
		*/
virtual	void		Clear(bool free_internals = true)
		{
			usage = 0;

			if	(free_internals)
				Resize(0);
			else
			{
				for	(uint n = 0; n < array.GetCount(); ++n)
					usage_map[n] = n;
				array[0] = 0;	// enforce terminator
			}
		}
		//----------------------------------------------------------------------

		ArrayList(uint initial_size = 0, uint step = 64) : usage(0), grow_step(step) { Resize(initial_size); }
virtual	~ArrayList() {}
};

/*
	@short	Shared object array list.
	@author	Emmanuel Julien (ejulien@gsworks.fr)
*/
template <class T> struct SharedArrayList : public ArrayList <T>
{
virtual	bool			Insert(const T &v, uint at)
		{
			v->AddRef();
			return ArrayList <T> ::Insert(v, at);
		}
virtual	bool			RemoveAt(uint i)
		{
			(*this)[i]->RemoveRef();
			return ArrayList <T> :: RemoveAt(i);
		}
virtual	void		Clear(bool free_internals = true)
		{
			for (uint n = 0; n < this->GetCount(); ++n)
				(*this)[n]->RemoveRef();
			return ArrayList <T> ::Clear(free_internals);
		}
virtual	~SharedArrayList()
		{	Clear();	}
};

//------------------------------------------------------------------------------
		// Delete all list entries.
#define	ArrayListDeleteAllPtr(T, L)	{ for (uint __n = 0; __n < (L).GetCount(); ++__n) delete (L)[__n]; (L).Clear(); }
		// Iterate over a list of pointers.
#define	ArrayListForeachPtr(T, V, L) \
		for	(ArrayList <T> ::Iterator iterator(L); T V = iterator.ObjectPtr(); ++iterator)
		// Iterate over a list of objects.
#define	ArrayListForeach(T, V, L) \
		for	(ArrayList <T> ::Iterator V(L); V.IsOver() == false; ++V)

		/// Find item by using a template identification class.
template <typename T, typename F, typename P> T	ArrayListFindEx(const ArrayList <T> &list, F filter, const P &what)
{
	for (uint __n = 0; __n < list.GetCount(); ++__n)
		if	(filter(list[__n], what))
			return list[__n];
	return 0;
}
//------------------------------------------------------------------------------

} // GS


#endif	// __NARRAYLIST__
