#ifndef CAL_READER_H
#define CAL_READER_H

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <cassert>
#include "./exception/Exception.h"
#include "./illumination/Light.h"
#include "./camera/Camera.h"
#include "./math/Matrix.h"

using namespace std;
using namespace MATRIX;

namespace calSpace
{
	

const string CAMERA_TAG="CAMERA";
const string OMNI_TAG="OMNI_LIGHT";
const string RECTANGLE_TAG="RECTANGLE_LIGHT";
const string DIRECTIONAL_TAG="DIRECTIONAL_LIGHT";
const string SPOT_TAG="SPOT_LIGHT";
const string SPOT_VRML_TAG="SPOT_LIGHT_VRML";
const string DTIT_TAG="DTIT_LIGHT";

const string TEXTURE_TAG="TEXTURE";
const string MATERIAL_TAG="MATERIAL";
const string MODEL_TAG="MODEL";

const string SKYBOX_TAG="SKYBOX";
const string FRONT_TEX_TAG="FRONTTEXTURE";
const string BACK_TEX_TAG="BACKTEXTURE";
const string LEFT_TEX_TAG="LEFTTEXTURE";
const string RIGHT_TEX_TAG="RIGHTTEXTURE";
const string TOP_TEX_TAG="TOPTEXTURE";
const string BOTTOM_TEX_TAG="BOTTOMTEXTURE";


const string TYPE_TAG="TYPE";
const string POS_TAG="POS";
const string DIR_TAG="DIR";
const string LOOK_TAG="LOOK";
const string COLOR_TAG="COLOR";
const string INTENSITY_TAG="INTENSITY";
const string RIGHT_TAG="RIGHT";
const string INNER_TAG="INNERANGLE";
const string OUTER_TAG="OUTERANGLE";
const string DIRECTIONAL_EXP_TAG="DIRECTIONAL";
const string NAME_TAG="NAME";
const string ATTENUATION_TAG="ATTENUATION";
const string PATH_TAG="PATH";
const string MATRIX_TAG="MATRIX";
const string DELIMER_TAG=" ";

const string VEC1_TAG="VEC1";
const string VEC2_TAG="VEC2";

const string TANGENT_TAG= "TANGENT";
const string BITANGENT_TAG = "BITANGENT";
const string KEYLIGHT_TAG = "KEYLIGHT";
const string AO_TAG	= "AMBIENT_OCCLUSION";
const string INDIRECT_TAG = "INDIRECT_TAG";
const string SUBTYPE_TAG = "SUBTYPE";
const string SHADOW_TAG = "SHADOW";


const string SURFACE_TAG = "SURFACE";

const string TERRAIN_TAG = "TERRAIN";
const string GEOMETRY_TAG = "GEOMETRYSCRIPT";
const string INNER_SURFACE_TAG = "INNERSURFACE";
const string OUTER_SURFACE_TAG = "OUTERSURFACE";
const string CLOUDS_TAG = "CLOUDS";
const string BASELINE_TYPE_TAG = "BASELINETYPE";

const string GRAPHIC_GENERATOR_DATABASE_TAG ="GRAPHICGENERATORDATABASE";

/// Camera CAL file data
struct CameraCAL
{
	Camera<float> camera;	/**< loaded camera data*/
	string name;			/**< name of loaded camera*/
};

/// Light CAL file data
struct LightCAL
{
	string name;		/**< name of loaded light name*/
	Light *lightPtr;	/**< pointer to loaded light data*/
};

/// Material CAL file data
struct MaterialCAL
{
	string name;	/**< name of loaded material file*/
	string path;	/**< path ( including file name) to the material*/
};

/// Model CAL file data
struct ModelCAL
{
	string name;		/**< name of loaded model*/
	string path;		/**< path ( including file name) to the model*/
	string material;	/**< material name*/
	Matrix4X4<float> matrix;	/**< model matrix*/
};

/// Texture CAL file data
struct TextureCAL
{
	string name;		/**< name of loaded texture*/
	string path;		/**< path (including texture name) to the texture*/
};

/// Skybox CAL file data
struct SkyboxCAL
{
	string name;		/**< name of loaded skybox*/
	string front;		/**< front side texture name*/
	string back;		/**< back side texture name*/
	string left;		/**< left side texture name*/
	string right;		/**< right side texture name*/
	string top;			/**< top side texture name*/
	string bottom;		/**< bottom side texture name*/
};

/// Terrain CAL file data
struct TerrainCAL
{
	std::string name;				/**< name of loaded terrain data*/
	std::string geometryScript;		/**< script generatring the terrain*/
	std::string surfaceTexName;		/**< surface texture of terrain*/
	std::string materialName;		/**< material name of terrain*/
	std::string skyboxName;			/**< skybox name of terrain*/
	std::string cloudsTexName;		/**< clouds texture name of terrain*/
};

/// GraphicGenerator CAL file data
struct GraphicGeneratorCAL
{
	std::string name;							/**< name od database*/
	std::vector< unsigned int > baselineTypes;	/**< types of baselines which could be used*/
	std::vector< string > cloudNames;			/**< name of clouds*/
	std::vector< string > materialNames;		/**< material of the planet*/
	std::vector< string > skyboxNames;			/**< name of skybox which should be used */
	std::vector< string > innerSurfaceTexNames;	/**< texture of the planet which is visible from planet*/
	std::vector< string > terrainScripts;		/**< script generatring the terrain*/
	std::vector< string > outerSurfaceTexNames;	/**< texture of the planet which is visible from space*/
};

typedef vector<LightCAL>	LightContainer;
typedef vector<CameraCAL>	CameraContainer;
typedef vector<MaterialCAL>	MaterialContainer;
typedef vector<ModelCAL>	ModelContainer;
typedef vector<TextureCAL>	TextureContainer;
typedef vector<SkyboxCAL>	SkyboxContainer;
typedef vector<TerrainCAL>	TerrainContainer;
typedef vector<GraphicGeneratorCAL> GraphicGeneratorContainer;

///Reads and parse data from CAL files. 
/**
*	CALreader class reads data from *.CAL files ( CAL files contain informations about lights, cameras, models and their materials.
*/
class CALReader
{
private:
	fstream file;

	void parseCamera( fstream &file, CameraCAL &dstCam );			/**< Camera*/
	void parseOmni( fstream &file, LightCAL &dstLight );			/**< Omni light*/
	void parseSpot( fstream &file, LightCAL &dstLight );			/**< Spot light*/
	void parseSpotVRML( fstream &file, LightCAL &dstLight );		/**< VRML spot light*/
	void parseRectangle( fstream &file, LightCAL &dstLight );		/**< Rectangle light*/
	void parseDirectional( fstream &file, LightCAL &dstLight );		/**< Directional light*/
	void parseMaterial(  fstream &file, MaterialCAL &dstMaterial );	/**< Material*/
	void parseModel( fstream &file, ModelCAL& dstModel );			/**< Model*/
	void parseTexture( fstream &file, TextureCAL& dstTexture );		/**< Texture*/
	void parseSkybox( fstream &file, SkyboxCAL& dstSkybox );		/**< Skybox */
	void parseTerrain( fstream &file, TerrainCAL& dstTerrain );		/**< Terrain */
	void parseGraphicGenerator(  fstream &file, GraphicGeneratorCAL &dstGraphic );	/**<GraphicGenerator	*/

	//pointers to extern structures, resources are not managed by this class!!!
	CameraContainer *dstCamera;
	LightContainer *dstLight;
	MaterialContainer *dstMaterial;
	ModelContainer *dstModel;
	TextureContainer *dstTexture;
	SkyboxContainer *dstSkybox;
	TerrainContainer *dstTerrain;
	GraphicGeneratorContainer *dstGraphicGeneratorContainer;

public:
	CALReader(const string &fileName);

	void setCameraContainer( CameraContainer &dstCamera );
	void setLightContainer( LightContainer &dstLight );
	void setMaterialContainer( MaterialContainer &dstMaterial );
	void setModelContainer( ModelContainer &dstModel );
	void setTextureContainer( TextureContainer &dstTexture );
	void setSkyboxContainer( SkyboxContainer &dstSkybox );
	void setTerrainContainer( TerrainContainer &dstTerrain );
	void setGraphicGeneratorContainer( GraphicGeneratorContainer &dstGraphicGeneratorContainer);

	void parseFile( void );	/**< Parse given file. */
};


/// Exports given data into CAL file format.
/**
*	CALexporter class writes data to *.CAL files ( CAL files contain informations about lights, cameras, models and their materials.
*/

class CALexporter
{
public:
	static void exportLight( ofstream &file, LightContainer &srcLight );
	static void exportCamera( ofstream &file, CameraContainer &srcCamera );
	static void exportMaterial( ofstream &file, MaterialContainer &srcMaterial );
	static void exportModel( ofstream &file, ModelContainer &srcModel );

	static void exportToCAL( ofstream &file, CameraContainer &srcCamera, LightContainer &srcLight, MaterialContainer &srcMaterial, ModelContainer &srcModel ); /**< Store data to file */
	static void exportToCAL(const string &fileName, CameraContainer &srcCamera, LightContainer &srcLight, MaterialContainer &srcMaterial, ModelContainer &srcModel ); /**< Store data to file */
};

}


#endif