#ifndef SPACE_STRUCTURES_H
#define SPACE_STRUCTURES_H

#include "./renderer/softProjRender.h"
#include "./math/Mathematics.h"
#include <cassert>

using namespace GEOMETRY;
using namespace ANALYTICAL_GEOMETRY;



///Base class for all space object used in MapFunctionality class
/**
*	Base class for all space object used in MapFunctionality class.
*	All space objects used in MapFunctionality should be inherited by this class.
*/
struct BaseSpaceObject
{
protected:
	virtual void internalSimulate( double dt ) = 0;		/**<Not implemented simulate function, this function must be implemented by inherited objects.*/
	virtual void internalRender( SoftProjRender& render, float levelOfDetail ) = 0;	/**<Not implemented render function, this function must be implemented by inherited objects.*/

public:
	BaseSpaceObject(void):lastSynchronizationTime(0) {};

	double lastSynchronizationTime; /**<total (summed) dt since last synchronization*/

	virtual Point_3<double> getPos(void) =0;	/**<Not implemented function, which returns position of object. This function must be implemented by inherited objects.*/
	virtual void setPos( const Point_3<double>& pos ) =0; /**<Not implemented function, which sets position of object. This function must be implemented by inherited objects.*/
	virtual double getSize(void) = 0;	/**<Not implemented function, which returns size of object. This function must be implemented by inherited objects.*/
	virtual void render( SoftProjRender& render, float levelOfDetail);	/**<Render function, this function render the object.  */
	void simulate( double dt ) {lastSynchronizationTime+= dt; this->internalSimulate( dt ); } /**<Simulate function, this function simulates the object. */
};



//Warning: cal file have to contain graphic mapper with with this this names!!!
const string PLANET_TYPE_0 ("frozenPlanets");
const string PLANET_TYPE_1 ("alienPlanets");
const string PLANET_TYPE_2 ("crystalPlanets");
const string PLANET_TYPE_3 ("desertPlanets");
const string PLANET_TYPE_4 ("greenPlanets");
const string PLANET_TYPE_5 ("mountainPlanets");
const string PLANET_TYPE_6 ("vulcanPlanets");
const string STAR_TYPE ("starPlanets");
const int PLANET_TYPE_COUNT = 7;

enum PlanetClassType
{
	BASIC_PLANET_CLASS
};


enum TARGET_TYPE
{
	NO_TARGET,
	PLANET_TARGET,
	SHIP_TARGET
};

struct MissileTarget
{
	unsigned long enemyTargetId;	/**< Id of the target. */
	TARGET_TYPE targetType;			/**< Type of the target. */
 	MissileTarget(void);
};

///Virtual class for space planets.
/**
* Is pure virtual class which defines 
* interface and common space planets atributes
* which are required for space planet simulation
* and rendering.
*/
struct BasePlanetClass: public BaseSpaceObject
{
protected:
	virtual void internalSimulate( double dt );

public:
	vector< MissileTarget > 	enemyTargetIdContainer;		/**< Container of all enemy targets.  */
	float rateOfFire;									/**< Cadency of the planet weapons. */

	unsigned int fontTexId;			/**< font texture */
	string name;					/**< name of the planet*/
	Point_3<double> center;			/**< pivot - rotation center*/
	Vector_3<double> axis;			/**< axis to rotate around*/
	double radius;					/**< distance from pivot*/
	double speed;					/**< speed of rotation*/
	double angle;					/**< actual rotation angle*/

	virtual Point_3<double> getPos(void);	/**< returns position of the planet*/
	virtual void setPos( const Point_3<double>& pos );	/**<sets position of the planet*/
	virtual void render( SoftProjRender& render, float levelOfDetail );	/**< renders planet*/

	virtual PlanetClassType getPlanetClassType( void ) = 0; /*{ return BASE_PLANET_CLASS; };*/	/**<Returns type of class type */

	BasePlanetClass(void);
};



/// Class used for sphere planets.
/**
*	Basic planet class
*	Can render only sphere planets
*/
struct BasicPlanet: public BasePlanetClass
{
	//static const unsigned int  segmentCount = 15; /**<number of slice and stack segments to aproximate sphere during rendering*/
	double objectSize;		/**< size of the object*/
	CRgbw color;			/**< color of the object*/

	unsigned int coronaTextureId;	/**<texture id of planet aura billboard */
	unsigned int textrureId;	/**<texture id of the planet surface*/

	virtual double getSize(void);	/**<returns size of the planet*/
	virtual PlanetClassType getPlanetClassType( void ) { return BASIC_PLANET_CLASS; };	/**<Returns type of class type */

	BasicPlanet(void);

protected:
	virtual void internalRender( SoftProjRender& render, float levelOfDetail );	//renders planet
};



#if MODEL_PLANET_IMPLEMENTED
/// Class used for general planets.
/**
*	Advanced planet class
*	Can render universal planets, where
*	the geometry is represented by 3d model.
*/
struct ModelPlanet: public BasePlanetClass
{
public:
	Model model;						/**<3D model of planet*/
	ModelPlanet( const Model &model);
	virtual double getSize(void);		/**<returns size of the model*/
	
	virtual PlanetClassType getPlanetClassType( void ) { return MODEL_PLANET_CLASS; };	/**<Returns type of class type */

protected:
	virtual void internalRender( SoftProjRender& render, int levelOfDetail );	/**<renders planet model*/
};
#endif

typedef unsigned long PlanetId;
typedef map< PlanetId, BasePlanetClass* > PlanetDatabase;

//Warning: cal file have to contain models with this this names!!!
const string SHIP_TYPE_0 ("ship0");
const string SHIP_TYPE_1 ("ship1");
const string SHIP_TYPE_2 ("ship2");
const string SHIP_TYPE_3 ("ship3");
const string SHIP_TYPE_4 ("ship4");
const string SHIP_TYPE_5 ("ship5");
const int SHIP_TYPE_COUNT = 6;

enum ShipType
{
	type0,
	type1,
	type2,
	type3,
	type4,
	type5
};


/// Represents galaxy space ship.
/**
*	Represents galaxy space ship used in SpaceMap class.
*/
struct SpaceShip : BaseSpaceObject
{
private:
	Vector_3<double> orientationVector;	/**< actual model orientation*/
	Vector_3<double> externForce;	/**< additional force vector which act on the ship*/

protected:
	virtual void internalSimulate( double dt );
	virtual void internalRender( SoftProjRender& render, float levelOfDetaill =1.0f );
public:
	unsigned int lifePercentage;		/**< lifes ( in range 0% - 100% ) of the ship*/
	unsigned int shieldPercentage;		/**< shields ( in range 0% - 100% )  of the ship*/
	string name;						/**< name of the ship*/
	ShipType type;						/**< type of the ship*/
	
//=================================
	//folowing attributes are used if ship is NOT orbiting

	double speed;						/**< speed of the ship*/
	double accleration;					/**< acceleration of the ship*/
	Point_3<double> destinationPoint;	/**< destination position where the ship is flying on*/
//---------------------------------	
	//folowing attributes are used if ship is ORBITING

	bool isOrbiting;									/**< Flag if the ship is orbiting or not. */
	ANALYTICAL_GEOMETRY::Point_3<double> orbitPivot;	/**< Orbit pivot position if orbiting. */
	double orbitSpeed;									/**<Angular orbit speed if orbiting. */
	bool isMiningFromPlanet;							/**< Flag if the ships is already mining or not. */
	
	MissileTarget	enemyTarget;								/**< Id of enemy object to fight with. */ 
	float rateOfFire;									/**< Cadency of the ship weapon. */
//=================================

	bool inWarp;										/**< Is ship in Warp flag */ 
	bool inBase;										/**< Is ship in Base flag */ 

	Model model;						/**< geometry model of the ship */

	
	Vector_3<double> getDir(void);		/**<returns move direction of the ship*/
	virtual double getSize(void);		/**<returns size of the ship model*/
	Point_3<double> getPos(void);		/**<returns position of the ship model*/
	void setPos( const Point_3<double>& pos );	/**<sets position of the ship model*/
	void setFront( const Vector_3<double> &front );	/**<sets, where is the front of the ship model*/
	virtual void setOrientation( Vector_3<double> &orientation );	/**<sets current ship model orientation*/
	Vector_3<double> getOrientation(void) const;	/**<gets current ship model orientation. */
	void setExternForce( const Vector_3<double> &externForce );	/**<sets extern force vector*/
	Vector_3<double> getExternForce(void) const; /**<returns value of #SpaceShip::externForce*/

	SpaceShip( const Model &model, const Vector_3<double> frontVector = MAKE_VECTOR<double>(0,0,1) );
};


typedef unsigned long  ShipId;
typedef map< ShipId, SpaceShip* > ShipDatabase;




enum MissileType
{
	missile0
};
const unsigned int missilesTypeCount = 1;

/// Represents galaxy space ship.
/**
*	Represents galaxy space ship used in SpaceMap class.
*/
struct SpaceMissile : public BaseSpaceObject
{
private:
	Vector_3<double> orientationVector;	/**< current missile model orientation*/

protected:
	virtual void internalSimulate( double dt );		/**<simulates missile*/
	virtual void internalRender( SoftProjRender& render, float levelOfDetail = 1.0f );	/**<renders missile*/

public:
	Vector_3<double> getDir(void);	/**<returns move direction of the missile model*/
	virtual Point_3<double> getPos(void);	/**<returns position of the missile model*/
	virtual double getSize(void);	/**<returns size of the missile model*/

	void setPos( const Point_3<double>& pos );	/**<sets position of the missile model*/
	void setFront( const Vector_3<double> &front );	/**<sets, where is the front of the missile model*/
	virtual void setOrientation( Vector_3<double> &orientation ); /**<sets current missile model orientation*/
	SpaceMissile( const Model &model, const Point_3<double> &dstPos, const Vector_3<double> frontVector = MAKE_VECTOR<double>(0,0,1) );

	MissileType type;	/**<type of the missile*/
	Model model;		/**<3D model of the missile*/
	double speed;		/**<speed of the missile*/

	//BaseSpaceObject *targetObject;	/**< ptr to target object ( the missile pursues this object ) */
	Point_3<double> dstPos;	/**< Destination position. */
};






//TODO solve data dealocation and alocation in other (better) way
/// Stores relevant galaxy data.
/**
*	Represents galaxy data,
*	this class is initialized with data from outside,
*	but is responsible for data dealocation!!!
*/
struct GalaxyPart
{
friend class SpaceMapGame; 
	
private:
	void releaseResources(void);	/**<release all resources that are stored in this structure*/

	GalaxyPart &operator=( const GalaxyPart & ); /**<cannot be assigned*/
	GalaxyPart( const GalaxyPart & ); /**<cannot be copied*/
	
	PlanetDatabase spacePlanets;	/**<holds database of planets*/
	ShipDatabase spaceShips;		/**<holds database of ships*/

public:

	BasePlanetClass *findPlanet( const unsigned long planetId  );
	SpaceShip *findShip( const unsigned long shipId );
	
	static BasePlanetClass *findPlanet(  const PlanetDatabase& spacePlanet, const unsigned long planetId  );
	static SpaceShip *findShip(  const ShipDatabase& spaceShip, const unsigned long shipId  );

	SpaceShip *insertShip( const unsigned long shipId, const SpaceShip& newShip);
	BasicPlanet *insertPlanet( const unsigned long planetId, const BasicPlanet& newPlanet );

	bool removeShip( const unsigned long shipId, ShipDatabase::iterator &outShipIterator  );
	bool removePlanet( const unsigned long planetId, PlanetDatabase::iterator &outPlanetIterator  );

	static bool removePlanet( PlanetDatabase& spacePlanet, const unsigned long planetId, PlanetDatabase::iterator &outPlanetIterator  );
	static bool removeShip( ShipDatabase& spaceShip, const unsigned long shipId, ShipDatabase::iterator &outShipIterator  );

	GalaxyPart() {};
	~GalaxyPart() { this->releaseResources(); }
};



/// Signalizer
/**
*	Signalize action on given position with growing wave
*/
class Signalizer
{
private:
	float MAX_RADIUS;	/**<Maximal radar wave radius*/
	float RADIUS_OFFSET_DT;	/**<Radar wave size offset*/
	Point_3<double> position;	/**<Position of radar wave*/
	double currentRadius;	/**<Current radius of radar wave*/

public:
	Signalizer( const Point_3<double> &position, const double maxRadius, const double radiusOffsetDt );
	void simulate( const double dt );	/**<Simulates radar wave - change its size according the #Radar::RADIUS_OFFSET_DT*/
	bool isActive(void);	/**<returns true if radar wave is still active, false otherwise*/
	void render( SoftProjRender &render );	/**<render the radar wave according the position and size*/
};

#endif