#ifndef SPACE_MAP_H
#define SPACE_MAP_H

#include "./renderer/softProjRender.h"
#include "./math/Mathematics.h"
#include "./softProj/Render/SpaceStructures.h"
#include "./uiSupport/controls.h"
#include "./softProj/Render/ShipEmittor.h"
#include "./softProj/Render/SpaceSky.h"
#include "./effects/brokenScreenEffect.h"
#include "./effects/animationEffect.h"

using namespace GEOMETRY;
using namespace ANALYTICAL_GEOMETRY;


typedef map< ShipType, ShipEmittorInterface* > ParticleEmittorMap;
typedef list< AnimationEffect > AnimationContainer;

typedef map< MissileType, Model* > MissilesPatternMap;


struct MissileInfo
{
	SpaceMissile missileData;
	MissileTarget target;

	MissileInfo( const SpaceMissile & missileData, const MissileTarget &target ): missileData( missileData ), target( target ) {};
};


typedef list< MissileInfo > MissileContainer;

struct MapFunctionality
{
private:
	const int PICK_PLANE_SIZE;
	const int VISIBLE_SIZE;
	const int CAMERA_BOUNDARY; 
	const float EXPLOSION_RADIUS;
	const float PARTICLE_GARBAGE_TIME_LIMIT;

	const unsigned int CIRCLE_SEGMENT_COUNT;
	const float LINE_WIDTH;
	const Vector_3<float> CIRCLE_AXIS;

	const AnimationEffect EXPLOSION_PROTOTYPE; //is cloned to make new explosion
	const AnimationEffect WARP_PROTOTYPE; //is cloned to make new explosion

	const float EPSILON_DISTANCE;
	const float SELECTION_CIRCLE_SIZE;

	const float NEAR_CAMERA_ZOOM;
	const float FAR_CAMERA_ZOOM;

	const float PLANET_HIGHLIGHT_MAX_SIZE;
	const float PLANET_MAX_SIZE_BEFORE_HIGHLIGHT;
	const float	PLANET_HIGHLIGHT_SCALE;

	const float SHIP_HIGHLIGHT_SCALE;
	const float SHIP_HIGHLIGHT_MAX_SIZE;

	const float MISSILE_HIGHLIGHT_SCALE;

	const float MOUSE_SENSITIVITY;
	const float KEYBOARD_SENSITIVITY;

	bool lockedCamera;
	bool newDstPoint;
	int dstPoint[2];

	Signalizer signalizer;
	
	bool highlightPlanets; ///highlight planets during render?
	bool highlightShips; ///highlight ships during render?


	float particleTimeCounter;
	float circleSize;

	// render issues -------------------------------------------------------------
	void renderLodGrid( SoftProjRender &render, const Point_3<double> &center, float zoom );
	void renderMapGrid( SoftProjRender &render,  const Point_3<double> &center, const float gridSize, const float cellSize );
	void renderInvisiblePickPlane( SoftProjRender &render,  const Point_3<double> &center, const float planeSize );
	void renderFog( SoftProjRender &render, const Point_3<double> &center, const float visibleSize, const float totalSize );
	void renderSpacePlanets( SoftProjRender &render, PlanetDatabase &spacePlanets );
	void renderSpaceShips( SoftProjRender &render, ShipDatabase &spaceShips );
	void renderMissiles( SoftProjRender &render );
	void renderAnimations( SoftProjRender &render );
	void renderSelectionFlag( SoftProjRender &render, const Point_3<double> &pos );
	void renderDestinationFlag( SoftProjRender &render, const Point_3<double> &pos );
	void renderPathFlag( SoftProjRender &render, const Point_3<double> &from, const Point_3<double> &to );
	void renderParticles( SoftProjRender &render );
	void renderGizmo( SoftProjRender &render, const Point_3<double> &gizmoPosition, const Point_3<double> &destinationPoint );
	void renderBackground( SoftProjRender &render );
	void renderScreenEffect( SoftProjRender &render );
	void renderSignalizer( SoftProjRender &render );

	void renderShipName( SoftProjRender &render, SpaceShip &ship, const float fontSize ) const;
	void renderPlanetName( SoftProjRender &render, BasePlanetClass &planet, const float fontSize ) const;
	void renderHighlightDisc( SoftProjRender &render, const Point_3<double> &position );

	void renderHiglightPlanet( SoftProjRender &render, BasePlanetClass &planetToHighlightRender  );
	void renderHiglightShip( SoftProjRender &render, SpaceShip &shipToHighlightRender  );
	void renderHiglightMissiles( SoftProjRender &render, SpaceMissile &missileToHighlightRender  );

	// simulation issues -------------------------------------------
	void simulateMissiles( PlanetDatabase &planetDatabase, ShipDatabase &shipDatabase, float dt );
	void simulateAnimations( float dt );
	void simulateParticles( PlanetDatabase &planetDatabase, ShipDatabase &shipDatabase, float dt );
	void simulateShips( ShipDatabase &shipDatabase, float dt );
	void simulatePlanets( PlanetDatabase &shipDatabase, float dt );
	void simulateNoisyScreen(  float dt );
	void simulateSignalizer( float dt );
	// --------------------------------------------------------------
	void newExplosion( const Point_3<double> &pos );  /**< Creates new explosion on given position */
	

	void newMissile( const Point_3<double> &fromPos, const Point_3<double> &toPos, const MissileTarget& target );

	/// Set camera to given position iff the distance between camera pivot and given position is not greater than CAMERA_BOUNDARY limit.
	void clampCamera( const Point_3<double> &position, bool autoCenter );


	void calculateProgressiveZoom( SoftProjRender &render ); ///Prepares OpenGL to render according to the current zoom distance

	SpaceSkyPlane spaceSkyPlane;	// procedural space sky
	SKYBOX::StandardSkyPlane skyPlane;

	int calculatePlanetLevelOfDetail( float distance ) const;
	
	
public:
	Camera<double> camera;
	Point_3<double> cameraPivot; // init pos (0,0,0)

	float getCameraZoom( void ) const;

	unsigned int fogTextureId;
	unsigned int discTextureId;
	unsigned int hintTextureId;
	
	MissilesPatternMap missilesPaternMap;

	BrokenScreenEffect noisyScreenEffect;
	ParticleEmittorMap particleEmittor;
	AnimationContainer animations;


	MissileContainer missiles;

	~MapFunctionality();

	void signalize( const Point_3<double> &center, const float maxSignalRadius, const float radiusOffset );
	void newWarpEffect( const Point_3<double> &pos );  /**< Creates new warp effect on given position */

	void handleKeyboard( Keyboard &keyboard );
	void handleMouse( Mouse &mouse );
	void zoomCamera( float zoom );

	void render( SoftProjRender &render, PlanetDatabase &spacePlanets, ShipDatabase &spaceShips, SpaceShip *selectedShip = NULL );
	void simulate( PlanetDatabase &planetDatabase, ShipDatabase &shipDatabase, float dt );

	void setBackground(  unsigned int backgroundTexID );

	MapFunctionality(	unsigned int backgroundTexID, const AnimationEffect &explosionPrototype, 
						const AnimationEffect &warpPrototype,int pickPlaneSize, 
						int maxVisibleAreaSize, int cameraBoundary, int particleGarbageLimit, int nearCameraZoom, int farCameraZoom, 
						float mouseSensitivity, float keyboardSensitivity );

	void (*onShipNewDestinationPos)( Point_3<double> );
};

#endif