/***************************************************************************
 * movingsprite.h  -  header for the corresponding cpp file
 *
 * Copyright (C) 2003 - 2008 Florian Richter
 ***************************************************************************/
/*
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SMC_MOVINGSPRITE_H
#define SMC_MOVINGSPRITE_H

#include "../objects/sprite.h"

/* *** *** *** *** *** *** *** Movement states *** *** *** *** *** *** *** *** *** *** */

enum Moving_state
{
	STA_STAY	= 0,
	STA_WALK	= 1,
	STA_RUN		= 2,
	STA_FALL	= 3,
	STA_FLY		= 4,
	STA_JUMP	= 5,
	STA_CLIMB	= 6,
	// another object controls this object ( object doesn't update itself )
	STA_OBJ_LINKED = 7
};

/* *** *** *** *** *** *** *** collision check type *** *** *** *** *** *** *** *** *** *** */

enum ColCheckType
{
	// Don't add found collisions to the collision list
	COLLIDE_ONLY_CHECK = 0,
	// Only allow internal collisions
	COLLIDE_ALLOW_INTERNAL = 1,
	// Only allow blocking collisions
	COLLIDE_ALLOW_BLOCKING = 2,
	// Complete collision check
	COLLIDE_COMPLETE = 3
};

/* *** *** *** *** *** *** *** cMovingSprite *** *** *** *** *** *** *** *** *** *** */

class cMovingSprite : public cSprite
{
public:
	// if del_img is set the given image will be deleted on change or class deletion
	cMovingSprite( cGL_Surface *new_image = NULL, float x = 0, float y = 0, bool del_img = 0 );
	// create from stream
	cMovingSprite( CEGUI::XMLAttributes &attributes );
	// destructor
	virtual ~cMovingSprite( void );
	
	// Init defaults
	void Init( void );
	// copy this object
	virtual cMovingSprite *Copy( void );

	/* Sets the image for drawing
	 * if new_start_image is set the default start_image will be set to the given image
	 * if del_img is set the given image will be deleted
	*/
	virtual void Set_Image( cGL_Surface *new_image, bool new_start_image = 0, bool del_img = 0 );

	/* Set the direction
	 * if new_start_direction is set also set the start/editor direction
	*/
	virtual void Set_Direction( ObjectDirection dir, bool new_start_direction = 0 );
	// Sets the direction/velocity from the given angle and speed
	void Set_Direction( float angle, float speed, bool new_start_direction = 0 );

	// automatically slows down until not moving anymore
	void Auto_Slow_Down( float x_speed, float y_speed = 0 );

	/* Moves this object
	 * real : if set the speedfactor is not used
	*/
	virtual void Move( float move_x, float move_y, const bool real = 0 );
	/* Returns the Collision direction if not forced
	 * if real is set the speedfactor will not be used
	 * if force is set no collision detection will be performed
	 * if check_on_ground is set after moving onground will be checked
	*/
	virtual ObjectDirection Col_Move( float move_x, float move_y, bool real = 0, bool force = 0, bool check_on_ground = 1 );

	// Set velocity
	void Set_Velocity( float x, float y );
	// Add Velocity
	void Add_Velocity( float x, float y, bool real = 0 );

	/* Move into the opposite Direction
	 * if col_dir is given only turns around if the collision direction is in front
	 */
	virtual void Turn_Around( ObjectDirection col_dir = DIR_UNDEFINED );

	// update
	virtual void Update( void );
	/* draw
	* if request is NULL automatically creates the request
	*/
	virtual void Draw( cSurfaceRequest *request = NULL );

	/* Check if the current position with the given additional value is valid
	 * uses the collision rect
	*/
	cObjectCollisionType Collision_Check_Relative( const float x, const float y, const float w = 0, const float h = 0, const ColCheckType check_type = COLLIDE_COMPLETE, SpriteList *objects = NULL );
	/* Check if the given position is valid
	 * Creates a collision rect with the given values
	*/
	cObjectCollisionType Collision_Check_Absolute( const float x, const float y, const float w = 0, const float h = 0, const ColCheckType check_type = COLLIDE_COMPLETE, SpriteList *objects = NULL );
	/* Check if the given Position is valid
	 * uses the given rect as new source collision rect
	*/
	cObjectCollisionType Collision_Check( const GL_rect *new_rect, const ColCheckType check_type = COLLIDE_COMPLETE, SpriteList *objects = NULL );

	/* Check if the given movement goes out of the level rect
	 * handle : if set handle out of level if valid
	*/
	bool Check_out_of_Level_Hor( const float move_x, const bool handle = 0 );
	bool Check_out_of_Level_Ver( const float move_y, const bool handle = 0 );
	// Set the ground object
	virtual void Set_on_Ground( cSprite *obj, bool set_on_top = 1 );
	// Check if the Object is onground and sets the state to onground
	virtual void Check_on_Ground( void );
	// object looses onground state
	void Reset_on_Ground( void );
	// Corrects the position if the object got stuck
	void Update_Anti_Stuck( void );

	// default collision and movement handling
	virtual void Collide_Move( void );

	/* Freeze for the given time
	*/
	void Freeze( float freeze_time = speedfactor_fps * 10 );

	/* downgrade state ( if already at weakest state it dies )
	 * force : usually dies or a complete downgrade
	*/
	virtual void DownGrade( bool force = 0 );

	// updates the direction on the current velocity
	void Update_Direction( void );
	/* set the horizontal sprite rotation based on x velocity
	 * if start_rotation is set also set the start/editor rotation
	*/
	void Update_Rotation_Hor_velx( bool start_rotation = 0 );
	/* set the horizontal sprite rotation based on y velocity
	 * if start_rotation is set also set the start/editor rotation
	*/
	void Update_Rotation_Hor_vely( bool start_rotation = 0 );

	/* handle collision with object that moves it with the current velocity
	 * if moved object gets stuck it is downgraded
	*/
	void Handle_Move_Object_Collision( cObjectCollision *collision );

	/* Validate the given collision object
	 * returns 1 if an internal collision with this object is valid
	 * returns 2 if the given object collides with this object (blocking)
	*/
	virtual unsigned int Validate_Collision( cSprite *obj );
	/* Check if colliding with ghost objects
	 * returns -1 if nothing found
	 */
	virtual int Validate_Collision_Ghost( cSprite *obj );
	/* Validate the collision if this could be moving and the object could be on top
	 * returns -1 if nothing found
	*/
	int Validate_Collision_Object_On_Top( cMovingSprite *moving_sprite );
	// send a collision to an object based from the given collision
	virtual void Send_Collision( cObjectCollision *collision );
	// default collision handler
	virtual void Handle_Collision( cObjectCollision *collision );
	// handle moved out of Level
	virtual void Handle_out_of_Level( ObjectDirection dir );

	// velocity
	float velx, vely;

	// current direction
	ObjectDirection direction;
	// start direction
	ObjectDirection start_direction;

	// can be on a ground object
	bool can_be_on_ground;
	// colliding ground object
	cSprite *ground_object;

	/* the different states
	 * look at the definitions
	 */
	Moving_state state;

	// ice resistance
	float ice_resistance;
	// time counter if frozen
	float freeze_counter;
};

/* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */

#endif
