#ifndef __CONTROLLERC_H__
#define __CONTROLLERC_H__


#include "PajaTypes.h"
#include "DataBlockI.h"
#include "EditableI.h"
#include "UndoC.h"
#include "KeyC.h"
#include "ColorC.h"
#include "Vector2C.h"
#include "Vector3C.h"
#include "FileIO.h"


namespace Composition {

	//! Controller out of range types.
	enum ControllerOrtE {
		CONT_ORT_NONE = 0,
		CONT_ORT_CONSTANT,	//!< The out of range curve
		CONT_ORT_REPEAT,	//!< The curve is repeated.
		CONT_ORT_LOOP,		//!< The curve is looped.
	};

	//! Controller type.
	enum ControllerTypeE {
		CONT_TYPE_NONE = 0,
		CONT_TYPE_INT,		//!< Controller is used to interpolate integer values (1 channel).
		CONT_TYPE_FLOAT,	//!< Controller is used to interpolate floating point values (1 channel).
		CONT_TYPE_VECTOR2,	//!< Controller is used to interpolate 2D vector values (2 channel).
		CONT_TYPE_VECTOR3,	//!< Controller is used to interpolate 3D vector values (3 channel).
		CONT_TYPE_COLOR,	//!< Controller is used to interpolate color values (4 channel).
	};


	//! Value controller class.
	/*!	Controller class is used to control the animated parameter values in Demopaja.
		For user and coder the use of controllers are invisible. The parameter takes care
		of using the controller. In some cases it may be useful to use the controller directly.

		Controller provides methods to add and delete keys, interpolate between set of keys,

		This class is implemented by the system.

		\see KeyC
	*/
	class ControllerC : public Edit::EditableI
	{
	public:
		//! Creates new controller.
		/*!	\param eType Type of controller to create.

			This method creates new controller. The type defines
			the number of channels to use.
		*/
		static ControllerC*			create_new( ControllerTypeE eType );

		//! Creates new controller.
		/*!	Use set_type() to set number of channels and the type of the
			controller.
		*/
		virtual Edit::DataBlockI*	create();
		//! Creates new controller (used internally), see Edit::EditableI::create().
		virtual Edit::DataBlockI*	create( Edit::EditableI* pOriginal );
		//! Deep copy from a data block, see Edit::DataBlockI::copy().
		virtual void				copy( Edit::DataBlockI* pBlock );
		//! Shallow copy from a editable, see Edit::EditableI::restore().
		virtual void				restore( Edit::EditableI* pBlock );


		//! Returns the number of keys inside the controller.
		virtual PajaTypes::int32	get_key_count();

		//! Returns pointer to a key pointed by the argument.
		virtual KeyC*				get_key( PajaTypes::int32 i32Index );

		//! Deletes a key pointed by the argument.
		virtual void				del_key( PajaTypes::int32 i32Index );

		//! Returns a key at specified time, else NULL.
		virtual KeyC* 				get_key_at_time( PajaTypes::int32 i32Time );

		//! Creates a new key at specified time and returns it.
		virtual KeyC*				add_key_at_time( PajaTypes::int32 i32Time );

		//! Sets the start (time before the first key) out of range type.
		virtual void				set_start_ort( PajaTypes::uint32 ui32Ort );

		//! Sets the end (time after last key) out of range type.
		virtual void				set_end_ort( PajaTypes::uint32 ui32Ort );

		//! Returns the start out fo range type.
		virtual PajaTypes::uint32	get_start_ort();

		//! Returns the end out fo range type.
		virtual PajaTypes::uint32	get_end_ort();

		//! Sorts keys by time.
		/*! This method has to be called after a new key is added to the controller,
			or the result of other methods may be incorrect.
		*/
		virtual void				sort_keys();

		//! Prepares controller for interpolation.
		/*! This method has to be called after a new key is added to the controller,
			or the result of other methods may be incorrect.

			If the controller contains smooth keys the tangents are calculated by this
			method, else it does nothing.
		*/
		virtual void				prepare();

		//! Returns the interpolated value of the controller at specified time.
		/*!	This method calculates the interpolated value based in the keys
			inside the controller. If no keys are present the return value will be
			zero for all channels.

			Maximum of KEY_MAXCHANNELS (currently 4) values are stored in the array pointed by
			the pValues parmeter.

			For easier access should one of the other get_value() methods be used.
		*/
		virtual void				get_value( PajaTypes::float32* pValues, PajaTypes::int32 i32Time );

		//! Returns the interpolated value of the controller at specified time as a integer value.
		virtual void				get_value( PajaTypes::int32& i32Val, PajaTypes::int32 i32Time );
		//! Returns the interpolated value of the controller at specified time as a floating point values.
		virtual void				get_value( PajaTypes::float32& f32Val, PajaTypes::int32 i32Time );
		//! Returns the interpolated value of the controller at specified time as a 3D vector.
		virtual void				get_value( PajaTypes::Vector2C& rVal, PajaTypes::int32 i32Time );
		//! Returns the interpolated value of the controller at specified time as a 3D vector.
		virtual void				get_value( PajaTypes::Vector3C& rVal, PajaTypes::int32 i32Time );
		//! Returns the interpolated value of the controller at specified time as a color.
		virtual void				get_value( PajaTypes::ColorC& rVal, PajaTypes::int32 i32Time );

		//! Returns the minimum value of the controller.
		/*! The value is checked on keyframes and the result
			is minimum of the all channels.

			This method is mainly used internally.
		*/
		virtual PajaTypes::float32	get_min_val();

		//! Returns the maximum value of the cotnroller.
		/*! The value is checked on keyframes and the result
			is maximum of the all channels.

			This method is mainly used internally.
		*/
		virtual PajaTypes::float32	get_max_val();

		//! Returns the time of the first key.
		virtual PajaTypes::int32	get_min_time();

		//! Returns the time of the last key.
		virtual PajaTypes::int32	get_max_time();

		//! Returns the type of the controller.
		virtual PajaTypes::uint32	get_type();

		//! Sets the type of the controller.
		/*!	This method should only be called for a controller which does not
			have any keys. It doesn't convert the keys and will lead in serious
			trouble if misused.
		*/
		virtual void				set_type( PajaTypes::uint32 ui32Type );

		//! Returns number of channels this cintroller controls.
		/*! The channel count depends on the controller type.
			\see ControllerTypeE */
		virtual PajaTypes::uint32	get_num_channels();

		// Serialize editable to a Demopaja output stream.
		virtual PajaTypes::uint32	save( FileIO::SaveC* pSave );
		// Serialize editable from a Demopaja input stream.
		virtual PajaTypes::uint32	load( FileIO::LoadC* pLoad );

	protected:
		//! Default constructor.
		ControllerC( ControllerTypeE eType );
		//! Default constructor with reference to the original.
		ControllerC( Edit::EditableI* pOriginal );
		//! Default destructor.
		~ControllerC();

	private:

		// Tool methods used internally by the controller class. Standard stuff.
		void						compute_hermite_basis( PajaTypes::float32 f32U, PajaTypes::float32* pV );
		PajaTypes::float32			ease( PajaTypes::float32 f32U, PajaTypes::float32 f32A, PajaTypes::float32 f32B );
		void						comp_first_deriv( PajaTypes::uint32 ui32CurIndex, PajaTypes::uint32 ui32NextIndex );
		void						comp_last_deriv( PajaTypes::uint32 ui32CurIndex, PajaTypes::uint32 ui32NextIndex );
		void						comp_2key_deriv( PajaTypes::uint32 ui32CurIndex, PajaTypes::uint32 ui32NextIndex );
		void						comp_middle_deriv( PajaTypes::uint32 ui32PrevIndex, PajaTypes::uint32 ui32Index, PajaTypes::uint32 ui32NextIndex );
		void						copy_value( PajaTypes::float32* pOut, PajaTypes::float32* pIn, PajaTypes::uint32 ui32NumCh );

		// Member variables
		std::vector<KeyC*>			m_rKeys;
		PajaTypes::uint32			m_ui32StartOrt;
		PajaTypes::uint32			m_ui32EndOrt;
		PajaTypes::uint32			m_ui32NumChannels;
		PajaTypes::uint32			m_ui32Type;
	};

};

#endif