/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
****************************************************************************/

#pragma once

#include "glmAssert.h"

namespace glm
{
	/**
	* \brief Static size array
	*
	* \author Golaem <dev@golaem.com>
	* \ingroup containers
	*/
	template <class Type, unsigned int t_size, bool t_empty = true>
	class StaticArray
	{
	public:

		/** \brief non const iterator on the array elements */
		typedef Type* iterator ;

		/** \brief const iterator on the array elements */
		typedef const Type* const_iterator ;

		/** \brief default constructor */
		StaticArray( unsigned int initialSize = ( t_empty? 0 : t_size ) ) ;

		/** \brief read a value of the static array
		*
		* \param index of the element to read
		* \return the element
		*/
		Type const& operator[]( unsigned int index ) const ;

		/** \brief read a value of the static array
		*
		* \param index of the element to read
		* \return the element
		*/
		Type& operator[]( unsigned int index ) ;

		/** \brief delete the last element	*/
		void pop_back() ;

		/** \brief add an element at the array's end
		*
		* \param value the value to add
		*/
		void push_back(Type const & value) ;

		/** \brief elements count
		*
		* \return the elements count
		*/
		unsigned int size() const ;

		/** \brief find a value in the array
		*
		* \param value the value to find in the array
		* \return the index of the value, size if not found
		*/
		unsigned int find( Type const& value ) const ;

		/** \brief return a non const iterator on the array first element */
		iterator begin() ;

		/** \brief return a non const iterator on the array last element + 1 */
		iterator end() ;

		/** \brief return a const iterator on the array first element */
		const_iterator begin() const ;

		/** \brief return a non const iterator on the array last element + 1 */
		const_iterator end() const ;

		/** 
		* \brief Egality test between two static array.
		*
		* \param array2 the other array.
		* \return True if the two arrays are equal.
		*/
		bool operator==(const StaticArray<Type,t_size,t_empty> & array2) const;

	protected:

		/** \brief array size */
		unsigned int _size ;

		/** \brief array elements */
		Type _array[t_size] ;
	} ;

	//-----------------------------------------------------------------------------
	// default constructor
	//----------------------------------------------------------------------------- 
	template <class Type, unsigned int t_size, bool t_empty>
	StaticArray<Type, t_size, t_empty>::StaticArray( unsigned int initialSize )
		: 
	_size( initialSize )
	{
	}

	//-----------------------------------------------------------------------------
	// operator[]
	//----------------------------------------------------------------------------- 
	template <class Type, unsigned int t_size, bool t_empty>
	inline Type const& 
		StaticArray<Type, t_size, t_empty>::operator[]( unsigned int index ) const
	{
		GLM_DEBUG_ASSERT(index < _size);
		return _array[index] ;
	}

	//-----------------------------------------------------------------------------
	// operator[]
	//----------------------------------------------------------------------------- 
	template <class Type, unsigned int t_size, bool t_empty>
	inline Type& 
		StaticArray<Type, t_size, t_empty>::operator[]( unsigned int index ) 
	{
		GLM_DEBUG_ASSERT(index < _size);
		return _array[index] ;
	}

	//-----------------------------------------------------------------------------
	// pop_back
	//----------------------------------------------------------------------------- 
	template <class Type, unsigned int t_size, bool t_empty>
	inline void 
		StaticArray<Type, t_size, t_empty>::pop_back() 
	{
		GLM_DEBUG_ASSERT( _size > 0 ) ;
		--_size ;
	}

	//-----------------------------------------------------------------------------
	// push_back
	//----------------------------------------------------------------------------- 
	template <class Type, unsigned int t_size, bool t_empty>
	inline void 
		StaticArray<Type, t_size, t_empty>::push_back(Type const & value) 
	{
		if( _size != t_size ) 
		{
			_array[_size] = value ;
			++_size ;
		}
	}

	//-----------------------------------------------------------------------------
	// size
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline unsigned int 
		StaticArray<Type, t_size, t_empty>::size() const
	{
		return _size ; 
	}

	//-----------------------------------------------------------------------------
	// find
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline unsigned int 
		StaticArray<Type, t_size, t_empty>::find( Type const& value ) const
	{
		unsigned int i(0);
		for( ; i < _size ; ++i )
		{
			if( _array[i] == value ) 
			{ 
				return i ; 
			}
		}
		return i ; 
	}

	//-----------------------------------------------------------------------------
	// begin
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline typename StaticArray<Type, t_size, t_empty>::iterator 
		StaticArray<Type, t_size, t_empty>::begin()
	{ 
		return _array ; 
	}

	//-----------------------------------------------------------------------------
	// end
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline typename StaticArray<Type, t_size, t_empty>::iterator 
		StaticArray<Type, t_size, t_empty>::end()
	{ 
		return _array + _size ; 
	}

	//-----------------------------------------------------------------------------
	// begin
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline typename StaticArray<Type, t_size, t_empty>::const_iterator 
		StaticArray<Type, t_size, t_empty>::begin() const
	{ 
		return _array ; 
	}

	//-----------------------------------------------------------------------------
	// end
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline typename StaticArray<Type, t_size, t_empty>::const_iterator 
		StaticArray<Type, t_size, t_empty>::end() const
	{ 
		return _array + _size ; 
	}

	//-----------------------------------------------------------------------------
	// equal operator
	//-----------------------------------------------------------------------------
	template <class Type, unsigned int t_size, bool t_empty>
	inline bool StaticArray<Type, t_size, t_empty>::operator==(const StaticArray<Type,t_size,t_empty> & array2) const
	{
		if (this->_size != array2._size)
		{
			return false;
		}
		else
		{
			for (unsigned int i = 0 ; i < _size ; i++)
			{
				if (this->_array[i] != array2._array[i])
				{
					return false;
				}
			}
			return true;
		}
	}
}
