/*
	Lan Wars.
	Copyright (c) 2009, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef SPRITE_ANIMATION_H
#define SPRITE_ANIMATION_H

//=====================================================================================================================
//=====================================================================================================================

#include "Graphics/Sprite.h"

class TiXmlElement;

//=====================================================================================================================
//=====================================================================================================================

namespace Game
{	
	//=================================================================================================================
	//=================================================================================================================
	
	class Camera3D;
	class SpriteRenderer;

	//=================================================================================================================
	/// @brief		Represents a 3D sprite that is animated. 3D is meant loosely because different orientations are 
	///				stored as different sprites. Diffferent sequences are supported also.
	//=================================================================================================================

	class SpriteAnimation
	{
		public:
		
			//=========================================================================================================
			// Enums
			//=========================================================================================================
			
				/// Enum representing the direction the sprite is facing in
				
				enum Direction
				{
					/// Sprite is facing south
					
					DIR_SOUTH = 0	,
					
					/// Sprite is facing south east
				
					DIR_SOUTH_EAST = 1 ,
					
					/// Sprite is facing east
					
					DIR_EAST = 2 ,
					
					/// Sprite is facing north east
					
					DIR_NORTH_EAST = 3 ,
					
					/// Sprite is facing north
					
					DIR_NORTH = 4 ,
					
					/// Sprite is facing north west: north east frame flipped
					
					DIR_NORTH_WEST = 5 , 
					
					/// Sprite is facing west: east frame flipped
					
					DIR_WEST = 6 , 
					
					/// Sprite is facing south west: west frame flipped
					
					DIR_SOUTH_WEST = 7
				};

			//=========================================================================================================
			// Functions
			//=========================================================================================================

				/// Constructor: creates the sprite animation from the settings stored in the given xml file

				SpriteAnimation( const char * xml_file );
				
				/// Copy constructor. Creates from another sprite animation
				
				SpriteAnimation( const SpriteAnimation & other );
				
				/// Assignment operator. Assigns the other sequence to this sequence.
				
				SpriteAnimation & operator = ( const SpriteAnimation & other );
				
				/// Animates the sprite
				
				void Animate( float time_delta , bool stop_at_end = false );
				
				/// Tells if sprite flipping is disabled for this sprite. Needed for uni-directional sprites.
				
				bool IsFlippingDisabled() const { return m_no_flip; }
				
				/// Sets if sprite flipping is disabled for this sprite. Needed for uni-directional sprites.
				
				void SetFlippingDisabled( bool disable ){ m_no_flip = disable; }
				
				/// Tells if the animation is at the end of the current sequence
				
				bool IsSequenceFinished() const;
				
				/// Tells if the sprite is additively blended: default is false
				
				bool IsAdditivelyBlended() const { return m_additive_blend; }
								
				/// Sets the current frame number we are on in the current animation sequence
				
				void SetFrame( unsigned frame );
				
				/// Sets the progress for the current frame
				
				void SetFrameProgress( float progress );
				
				/// Sets the amount of time each frame lasts for
				
				void SetFrameTime( float frame_time );
				
				/// Sets the current animation sequence
				
				void SetSequence( unsigned sequence , bool reset_frame_timings = true );
				
				/// Sets the current direction we are using
				
				void SetDirection( Direction direction );
				
				/// Sets the current direction we are using
				
				void SetDirection( Vec3f cam_pos , Vec3f obj_pos , float obj_rot );
				
				/// Sets whether the sprite is additively blended: default is false
				
				void SetAdditivelyBlended( bool additive ){ m_additive_blend = additive; }
				
				/// Gets the color for the sprite
				
				const Vec4f & GetColor() const { return m_color; }
				
				/// Sets the color for the sprite
				
				void SetColor( const Vec4f & color ){ m_color = color; }
				
				/// Draws the sprite animation
				
				void Draw( Camera3D * cam , SpriteRenderer * renderer );
				
				//=====================================================================================================
				/// @brief		Returns the current frame number we are on in the current animation sequence
				/// @returns	The current animation frame we are on in the sequence.
				//=====================================================================================================
				
				inline unsigned GetFrame() const { return m_frame; }

				//=====================================================================================================
				/// @brief		Returns the progress through the current frame, from 0-1
				/// @returns	The progress through the current frame from 0-1
				//=====================================================================================================
				
				inline float GetFrameProgress() const { return m_frame_progress; }
				
				//=====================================================================================================
				/// @brief		Returns the current animation sequence number we are on
				/// @returns	The current animation sequence we are on
				//=====================================================================================================
				
				inline unsigned GetSequence() const { return m_sequence; }
				
				//=====================================================================================================
				/// @brief		Returns the current amount of time that each frame is set to run for
				/// @returns	Amount of time that each frame is set to run for
				//=====================================================================================================
				
				inline float GetFrameTime() const { return m_frame_time; }
				
				//=====================================================================================================
				/// @brief		Returns the position to draw the sprite in
				/// @returns	Position to draw the sprite in
				//=====================================================================================================
				
				inline const Vec3f & GetPosition(){ return m_position; }

				//=====================================================================================================
				/// @brief		Sets the position to draw the sprite in
				/// @param		position - position to draw the sprite in
				//=====================================================================================================
				
				inline void SetPosition( const Vec3f & position ){ m_position = position; }
				
		private:			
		
			//=========================================================================================================
			// Structures
			//=========================================================================================================
				
				//=====================================================================================================
				/// @brief		Structure representing a particular sequence in an animation
				//=====================================================================================================
				
				struct Sequence
				{
					//=================================================================================================
					// Functions
					//=================================================================================================
					
						//=============================================================================================
						/// @brief		Constructor. Creates an empty sequence with arrays for the 5 main directions.
						//=============================================================================================
						
						Sequence(){ m_frames.resize(5); }
						
						//=============================================================================================
						/// @brief		Copy constructor. Creates from another sequence.
						/// @param		other - other sequence to construct from
						//=============================================================================================
						
						Sequence( const Sequence & other )
						{
							m_frames	= other.m_frames;
							m_size		= other.m_size;
						}
						
						//=============================================================================================
						/// @brief		Assignment operator. Assigns the other sequence to this sequence.
						/// @param		other - other sequence to assign from
						/// @returns	This sequence
						//=============================================================================================
						
						Sequence & operator = ( const Sequence & other )
						{
							m_frames	= other.m_frames;
							m_size		= other.m_size;
							
							return * this;
						}						
					
					//=================================================================================================
					// Variables
					//=================================================================================================
															
						//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
						/// This array holds the frames for directions 0-4. Or for south to north. Other frames are
						/// got through flipping the sprite.
						//'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
						
						std::vector< std::vector<Sprite> > m_frames;
						
						/// This is the size of the sprites for the sequence
						
						Vec2f m_size;					
				};

			//=========================================================================================================
			// Functions
			//=========================================================================================================
			
				/// Gets the names of all the frames of animation stored underneath a direction identifier in the xml
				
				std::vector<std::string> GetDirectionFrames( TiXmlElement * direction_element );
				
				/// Gets the size for a given sequence from the xml file:
				
				Vec2f GetSequenceSize( TiXmlElement * sequence_element );
		
			//=========================================================================================================
			// Variables
			//=========================================================================================================

				/// This is the array of animation sequences
				
				std::vector<Sequence> m_sequences;
				
				/// This is the current direction that the animation is facing in
				
				Direction m_direction;
				
				/// This is the current amount of time that each frame lasts for in seconds
				
				float m_frame_time;
				
				/// This is the current time through the current frame, from 0-1
				
				float m_frame_progress;

				/// This is the number of the current animation sequence
				
				unsigned m_sequence;				
				
				/// This is the current animation frame
				
				unsigned m_frame;
				
				/// If true then we use additive blending for the sprite
				
				bool m_additive_blend;
				
				/// Color to draw the sprite with
				
				Vec4f m_color;
				
				/// If true then the animation sequence is valid. If false then some frames failed to load
				
				bool m_is_valid;
				
				/// If true then we do not flip the sprite horizontally depending on the relative camera orientation
				
				bool m_no_flip;
				
				/// Position to draw the sprite in
				
				Vec3f m_position;
	};
};

#endif
