#include "PlanetViewerApp.h"
extern KODIAK_DEBUG_STREAM KODIAK_DEBUG_COUT;
const string PlanetViewerApp::LIGHT="light1";
const string PlanetViewerApp::HEIGHT_MAP_POSTFIX="_heightMap";

void PlanetViewerApp::mouseWheelEvent( int delta )
{
	this->mouse.wheel = delta;
}

void PlanetViewerApp::setResolution( unsigned int sizeX, unsigned int sizeY )
{
	this->windowRes[0] = sizeX;
	this->windowRes[1] = sizeY;

	if ( this->render!= NULL )
	{
		this->render->setViewport(0,0, this->windowRes[0], this->windowRes[1] );

		this->render->setProjection(	float( this->windowRes[0] ) / float ( this->windowRes[1] ), 
										this->sharedData.externalParams.projection.zNear, 
										this->sharedData.externalParams.projection.zFar,
										this->sharedData.externalParams.projection.FOV );
	}
}

void PlanetViewerApp::mouseMoveEvent( unsigned int posX, unsigned int posY )
{
	this->mouse.setPos( posX, posY );
	
	if ( this->mouse.pressedButtons[ Mouse::LEFT ] )
	{
		QCursor cursor = this->myWidget->cursor();
		QPoint widgetGlobalPos = this->myWidget->mapToGlobal( this->myWidget->pos() );
		cursor.setPos(  widgetGlobalPos.x() -10 + this->myWidget->width() / 2, widgetGlobalPos.y() -10 + this->myWidget->height() / 2 );
	}
}

void PlanetViewerApp::mouseReleaseEvent( unsigned int mouseButton )
{
	this->newClick = false;
	this->mouse.pressedButtons[ mouseButton ] = false;

	if ( mouseButton == Mouse::LEFT )
	{
		//set parent cursor to restore the previous cursor
		this->myWidget->setCursor( this->myWidget->parentWidget()->cursor() );
	}
}

void PlanetViewerApp::mousePressEvent( unsigned int mouseButton )
{
	this->mouse.pressedButtons[ mouseButton ] = true;

	if ( mouseButton == Mouse::LEFT )
	{
		//hide cursor while cursor is centered
		this->myWidget->setCursor( QCursor( Qt::BlankCursor ) );

		if ( this->newClick == false  )	
		{
			this->newClick = true;
			this->mouse.setPos( this->myWidget->width()/2, this->myWidget->height()/2 );
			this->mouse.clearDiff();
		}
	
		QCursor cursor = this->myWidget->cursor();
		QPoint widgetGlobalPos = this->myWidget->mapToGlobal( this->myWidget->pos() );
		cursor.setPos(  widgetGlobalPos.x() -10 + this->myWidget->width() / 2, widgetGlobalPos.y() -10 + this->myWidget->height() / 2 );
	}

}

void PlanetViewerApp::keyPressEvent(unsigned int key)
{
	this->keyboard.pressKey( key );
}

void PlanetViewerApp::keyReleaseEvent(unsigned int key)
{
	this->keyboard.releaseKey( key );
}

void PlanetViewerApp::createModelFromHeightMap( const Texture<unsigned char> &heightTex, unsigned int surfaceTexture, const string &modelName )
{
	float scaleFactor[3] = {1.0, 1.0, 0.2 };

	HeightMapImporter heighMapImporter( scaleFactor[0], scaleFactor[1], scaleFactor[2] );
	heighMapImporter.autoLoad( heightTex.internalData.sizeX, heightTex.internalData.sizeY, &heightTex.internalData.pixelData[0], 3 );
	
	vector<MeshObject> dstMesh;
	uploadHeightMapGeometry( heighMapImporter, this->sharedData.vbo_manager, modelName+HEIGHT_MAP_POSTFIX, dstMesh );

	Model *terrainModel=new Model(dstMesh);
	terrainModel->getMeshes().back().material = NULL;

	float center[3] = { -(heightTex.internalData.sizeX / 2.0)  * scaleFactor[0], 
						-30, //0, //-heightTex.internalData.pixelData[ heightTex.internalData.pixelData.size() / 2] * scaleFactor[2], 
						heightTex.internalData.sizeY / 2.0 *  scaleFactor[1]} ;

	terrainModel->getMeshes()[0].textures.push_back( surfaceTexture );

	terrainModel->translate( center[0], center[1], center[2] );
	terrainModel->rotate( -90,0,0);
	this->sharedData.modelManager.insert( make_pair( modelName,  terrainModel));
}

void PlanetViewerApp::loadModelFromHeightMap( const string &path, unsigned int surfaceTexture, const string &modelName )
{
	Texture<unsigned char> heightTex;
	TGA::readTextureDataTGA( this->sharedData.externalParams.texturesPath+path, heightTex);

	this->createModelFromHeightMap( heightTex, surfaceTexture, modelName );
}

void PlanetViewerApp::onOpenGLInit(void)	//init is called from GLWidget!!!
{
	if ( this->initialized ) return;
	this->sharedData.init();

	CGprogram vs, fs;
	
	if ( this->sharedData.shaderManager != NULL )
	{
		vs = this->sharedData.shaderManager->getShader("GLphongLightingVs");
		fs = this->sharedData.shaderManager->getShader("GLphongLightingFs");
	}
	else
	{
		KODIAK_WARNING<<"CgShaderManager is not initialized!";
	}

	this->render = new SoftProjRender( *this->context, vs, fs);
	cout<<endl<<" INIT::res"<<this->windowRes[0]<<", "<<this->windowRes[1]<<endl;

	this->render->setViewport(0,0, this->windowRes[0], this->windowRes[1] );
	this->render->setProjection(	float( this->windowRes[0] ) / float ( this->windowRes[1] ), 
									this->sharedData.externalParams.projection.zNear, 
									this->sharedData.externalParams.projection.zFar, 
									this->sharedData.externalParams.projection.FOV );

	


	this->spacePlanet = new SpacePlanetGame( *this->render, *this->sharedData.shaderManager );

	this->initialized = true;
}


PlanetViewerApp::PlanetViewerApp( const string appName, Context &context, OpenGlSharedData &sharedData ): AbstractAPP( appName, context ), sharedData( sharedData)
{
	this->newClick = false;
	this->initialized = false;

	this->render = NULL;
	this->spacePlanet = NULL;

	//set some default window res
	this->windowRes[0] = 640;
	this->windowRes[1] = 480;

	
	OmniLightPhong omni;

	omni.attenuationExp=1.0;
	omni.intensity=150.0;
	omni.position = MAKE_POINT<float>( 60, 100,0 );
	omni.color[0] = 1.0;
	omni.color[1] = 1.0;
	omni.color[2] = 1.0;
	this->lights.createOmniLight( LIGHT, omni );

}

PlanetViewerApp::~PlanetViewerApp(void)
{
	if ( this->render != NULL )
	{
		delete this->render;
		this->render = NULL;
	}

	if (this->spacePlanet != NULL )
	{
		delete this->spacePlanet;
		this->spacePlanet = NULL;
	}
}


void PlanetViewerApp::moveLights( float dt )
{
	Vector_3<float> axisY( 0,1,0);
	Point_3<float> pivot(0,0,0);

	// move light
	OmniLightPhong *omni;
	omni=  this->lights.getOmniLight( LIGHT );

	if ( omni == NULL ) return;

	omni->position.rotate_point( pivot, axisY, dt*0.2 );
}

void PlanetViewerApp::simulate( float dt )
{
	if ( !this->initialized )
	{
		return;
	}

	this->moveLights( dt );
	this->spacePlanet->setLights( this->lights.getLightArray() );
	this->spacePlanet->handleKeyboard( this->keyboard );
	this->spacePlanet->handleMouse( this->mouse );
	this->spacePlanet->simulate( 1.0 );

	this->mouse.clearDiff();
}
void PlanetViewerApp::run(void)
{
	if ( !this->initialized )
	{
		KODIAK_WARNING<<"ModelViewerApp cannot render, is not initialized -> ignored";
		return;
	}

	if ( this->sharedData.shaderManager == NULL )
	{
		return;
	}
	
	this->sharedData.shaderManager->bind();
		this->spacePlanet->render();
	this->sharedData.shaderManager->unbind();
}
