#ifndef LIGHT_H
#define LIGHT_H

#include "./../../lib/GLee/GLee.h"
#include <GL/glu.h>
#include "./math/Mathematics.h"
#include "./illumination/tricol.h"
#include <vector>
#include <map>
#include <string>
#include <iostream>


using namespace std;
using namespace ANALYTICAL_GEOMETRY;

enum LightType
{
	SPOT_PHONG = 1,
	SPOT_PHONG_VRML = 2,
	OMNI_PHONG = 3,
	RECTANGLE_PHONG = 4,
	DIRECTIONAL_PHONG = 5,

	WRAPPER_LIGHT=8,
	SHADER_LIGHT = 9,
};



///Basic light interface
struct Light
{
	virtual LightType getLightType() const=0;

	virtual ~Light(void) {};
	Light(void) {};
};


/**
*
*			--------H--------
*							|
*							|
*					X		O
*							|
*							
*	Legend: X .....position
*			O.....vec1
*			H.....vec2
*/

///Rectangle attributes
struct Rectangle
{
	Point_3<float> position;
	Vector_3<float> vec1;
	Vector_3<float> vec2;

	virtual ~Rectangle(void) {};
	Rectangle(void) {};
};

///Phong attributes
struct Phong
{
	float color[3];
	float attenuationExp;
	float intensity;
	Phong( const Phong& );
	Phong(void) {};
};

///Phong light attributes
struct PhongLight :public Phong, Light
{
	virtual ~PhongLight(void) {};
	PhongLight(void) {};
};




//VYSLEDNA POUZITELNA SVETLA----------------------------------

///Omni phong light 
struct OmniLightPhong : public PhongLight
{
	Point_3<float> position;
	LightType getLightType() const {return OMNI_PHONG; }

	virtual ~OmniLightPhong(void) {};
	OmniLightPhong(void) {};
};


///Abstract spot light class
struct SpotLightPhongAbstract:  public PhongLight
{
	Point_3<float> position;
	Vector_3<float> direction;

	virtual LightType getLightType() const =0;

	virtual ~SpotLightPhongAbstract(void) {};
	SpotLightPhongAbstract(void) {};
};


///Spotlight with cosinus falloff
struct SpotLightPhong:  public SpotLightPhongAbstract
{
	float directionalExp;
	LightType getLightType() const {return SPOT_PHONG; }

	virtual ~SpotLightPhong(void) {};
	SpotLightPhong(void) {};
};



///VRML 97 compatible spot light
struct SpotLightPhongVRML:  public SpotLightPhongAbstract
{
	float innerConeCos;
	float outerConeCos;

	LightType getLightType() const {return SPOT_PHONG_VRML; }

	virtual ~SpotLightPhongVRML(void) {};
	SpotLightPhongVRML(void) {};
};



///Abstract rectangular light
struct RectangleLightPhongAbstract: public PhongLight, public Rectangle
{
};


///Rectangular phong light
struct RectangleLightPhong : public RectangleLightPhongAbstract
{
	float directionalExp;

	LightType getLightType() const {return RECTANGLE_PHONG; }

	virtual ~RectangleLightPhong(void) {};
	RectangleLightPhong(void) {};
};


///Directinanal and rectangular phong light
struct DirectionalLightPhong : public RectangleLightPhongAbstract
{
	//NOTE: add attributes if needed

	LightType getLightType() const {return DIRECTIONAL_PHONG; }

	virtual ~DirectionalLightPhong(void) {};
	DirectionalLightPhong(void) {};
};



///Wrapper with universal interface - every light can be inserted 
class LightWrapper: public Light
{
protected:
	Light *light;

public:
	virtual LightType getLightSubType() const;
	virtual LightType getLightType() const;
	virtual ~LightWrapper(void);
	LightWrapper(const LightWrapper& light);
	LightWrapper& operator=(const LightWrapper& light);
	LightWrapper( const Light& light );

	LightWrapper( void );
	Light* getRealLightPtr(void);
};

void renderRectangleLight(const RectangleLightPhong* light, const CTriCol *color=NULL, bool wire = false);
void renderDirectionalLight(const DirectionalLightPhong* light, const CTriCol *color=NULL, bool wire = true);
void renderSpotLight( const SpotLightPhongAbstract *light, const CTriCol *color=NULL);
void renderOmniLight( const OmniLightPhong *light, const CTriCol *color=NULL );
void renderLight(const Light* light, const CTriCol *color=NULL );

///Manages various light types.
class LightManager
{
private:
	map<string, Light* > lights;

public:
	typedef map<string, Light* >::iterator iterator;
	typedef map<string, Light* >::const_iterator const_iterator;

	LightManager(const LightManager& );	/**< Deep copy constructor */
	LightManager& operator=(const LightManager& ); //TODO!!!

	LightManager(void) {};
	~LightManager(void);
	bool insertLight( const string &name, Light* light );							/**< Insert new light to database. WARNING: The Lightmanager adapt the responsibility for dealocation. */

	
	OmniLightPhong* createOmniLight( const string &name, const OmniLightPhong& omniLight);		/**< Create new OmniLight and insert it into the database. */
	SpotLightPhong* createSpotLight( const string &name, const SpotLightPhong& spotLight);		/**< Create new SpotLight and insert it into the database. */
	SpotLightPhongVRML* createSpotLightVRML( const string &name, const SpotLightPhongVRML& spotLight);		/**< Create new SpotLight according to VRML spec and insert it into the database. */
	RectangleLightPhong* createRectangleLight( const string &name, const RectangleLightPhong& rectangleLight);	/**< Create new Rectangle light and insert int into the database. */

	//MARTIN: WE WILL USE OTHER SOLUTION THAN getActiveLight ( not modular - such method is total useless for other projects */
	// Return the selected light to which the manipulator is connected to.
	//const Light* getActiveLight() const { assert(false); return NULL; }

	Light*	getLight( const string &name );
	PhongLight*	getPhongLight( const string &name );

	OmniLightPhong*	getOmniLight( const string &name );
	SpotLightPhong* getSpotLight( const string &name );
	SpotLightPhongVRML* getSpotLightVRML( const string &name );
	RectangleLightPhong* getRectangleLight( const string &name );

	vector< Light* > getLightArray(void);

	iterator begin(void);
	const_iterator begin(void) const;

	iterator end(void);
	const_iterator end(void) const;

	bool LightManager::empty(void) const;
	unsigned int LightManager::size(void) const;
};


#endif