#include "oglSharedData.h"
#include "texture\TextureComposer.h"
#include "mathParser\mathParser.h"
#include "mathParser\mathStringParser.h"
#include "mathParser\textureOperationParser.h"
#include "..\gameSettings.h"

unsigned int GameConstants::FONT_TEXTURE_ID;

void OpenGlSharedData::init(void)
{
	if ( this->initialized) return;

	//TEXTURES LOADING
	KODIAK_PROGRESS<<"Textures loading";

	Texture<unsigned char> texData;
	TextureManager::getInstance().readTexture<unsigned char>( this->externalParams.texturesPath+"noTexture.tga",texData);
	TextureManager::getInstance().createTexture("noTexture", texData);

	for ( int i=0; i< this->textureContainer.size(); ++i)
	{
		bool ok =TextureManager::getInstance().readTexture< unsigned char>( this->externalParams.texturesPath + this->textureContainer[i].path, texData );

		if ( ! ok )
		{
			KODIAK_ERROR<<"Texture not found! Texture name:"+this->textureContainer[i].name+", texure path: "+ this->externalParams.texturesPath + this->textureContainer[i].path;
		}

		TextureManager::getInstance().createTexture( this->textureContainer[i].name, texData );
	}




	KODIAK_PROGRESS<<"Materials loading";
	//MATERIALS LOADING
	// Material comment
	// kazdy jednotlivy soubor s material je ulozen v samostatnem PhongMaterialManager (=manager materialu v ramci 1 souboru)
	// tato struktura je potom spravovana v mape
	// tzn pro pristup ke konrektnimu materialu je potreba znat nazev souboru a nazev materialu v souboru
	for (int i=0; i<this->materialContainer.size(); ++i)
	{
		PhongMaterialManager* materials= new PhongMaterialManager();
		MTLreader materialReader( this->externalParams.modelsPath + this->materialContainer[i].path);
		initMaterialAndTextures( materialReader, *materials, TextureManager::getInstance(),"", this->externalParams.texturesPath );
		this->materialManager.insert(make_pair(materialContainer[i].name, materials));
	}
	
	KODIAK_PROGRESS<<"Meshes loading";
	//MODELS LOADING
	for (int i=0; i<this->modelContainer.size(); ++i)
	{
		vector<MeshObject> meshes;
		
		std::map<string,PhongMaterialManager*>::iterator it;
		it=this->materialManager.find( this->modelContainer[i].material );

		if (it==this->materialManager.end())
		{
			KODIAK_ERROR<<" MTL file for OBJ model was not found. Required material name: " + this->modelContainer[i].material;
		}

		ModelOBJ<PhongMaterial> objModel(  this->externalParams.modelsPath + this->modelContainer[i].path, this->vbo_manager, this->modelContainer[i].name, *(it->second), "", TextureManager::getInstance());
		
		
		Model *model=new Model( objModel.getFinalMeshes() );
		model->setModelMatrix( modelContainer[i].matrix); //set model matrix
		this->modelManager.insert( make_pair( this->modelContainer[i].name,  model));

	}
	
	this->shaderManager = new ShaderManager();

	if ( this->externalParams.useShaders )
	{
		try
		{
			const string SHADER_NAME = "phongShaderSoftProj.cg";
			KODIAK_PROGRESS<<"PhongShader loading: "+ this->externalParams.shadersPath+SHADER_NAME;

			cout<<endl<<"Best supported fragment shader profile:"<< this->shaderManager->getVertexProfile();
			cout<<endl<<"Best supported vertex shader profile:"<< this->shaderManager->getFragmentProfile();

			if ( this->shaderManager->getVertexProfile() < CG_PROFILE_ARBVP1 ||
				  this->shaderManager->getFragmentProfile() < CG_PROFILE_ARBFP1 )
			{
				KODIAK_WARNING<< string("Shaders cannot be compiled. Your graphic card does not support required shaders profile");
			}
			else
			{
				this->shaderManager->insertVertexShader(	this->externalParams.shadersPath+SHADER_NAME , "GLphongLightingVs" , "GLphongLightingVs");
				this->shaderManager->insertFragmentShader(	this->externalParams.shadersPath+SHADER_NAME , "GLphongLightingFs" , "GLphongLightingFs");
			}
		}
		catch ( ShaderException &e)
		{
			KODIAK_WARNING<< string("Shaders cannot be compiled. Reason:") + e.what();
		}
	}

	this->modelContainer.clear();
	this->materialContainer.clear();

	//----------------------------------------------------------
	//font2 texture must be defined in CAL file!!!
	unsigned int fontTexId = TextureManager::getInstance().getTexture( "font2" );
	GameConstants::FONT_TEXTURE_ID = fontTexId;
	if ( fontTexId == 0 ) throw exception( (string("Texture with name: font2 was not found")).c_str() );
	//-----------------------------------------------------------


	this->initialized = true;
}

OpenGlSharedData::OpenGlSharedData( const string &appPath, const string& resourcePath, Environment &env )
{
	this->shaderManager = NULL;
	this->initialized = false;

	this->externalParams.projection.zNear = env.getFloat("frustrumNearPlane");
	this->externalParams.projection.zFar = env.getFloat("frustrumFarPlane");
	this->externalParams.projection.FOV = env.getFloat("frustrumFOV");

	this->externalParams.CALpath = resourcePath+"/" + env.getString("CALpath");
	this->externalParams.texturesPath = resourcePath + env.getString("texturesPath");
	this->externalParams.modelsPath = resourcePath + env.getString("modelsPath");
	this->externalParams.shadersPath = resourcePath + env.getString("shadersPath");
	this->externalParams.terrainResourcesPath = resourcePath + env.getString("terrainResourcesPath");
	
	this->externalParams.useShaders = env.getBool("useShaders" );
	try
	{
		calSpace::CALReader calSpace( this->externalParams.CALpath );

		//set destination containers where to store parsed data
		calSpace.setMaterialContainer( this->materialContainer );
		calSpace.setModelContainer( this->modelContainer );
		calSpace.setTextureContainer( this->textureContainer );
		calSpace.setSkyboxContainer( this->skyboxContainer );
		calSpace.setTerrainContainer( this->terrainContainer );
		calSpace.setGraphicGeneratorContainer( GraphicMapper::getInstance()->graphicGeneratorDatabase );
		calSpace.parseFile();
	}
	catch ( exception &e)
	{
		KODIAK_ERROR<< "CAL file parsing failed. CAL file path: "+externalParams.CALpath+"<<";
	}
}

OpenGlSharedData::~OpenGlSharedData()
{
	if ( this->shaderManager != NULL )
	{
		delete this->shaderManager;
		shaderManager = NULL;
	}
}