#include "LevelState.h"
#include "MatrixManager.h"
#include "ShaderManager.h"
#include "ModelManager.h"
#include "TextureManager.h"
#include "BulletManager.h"
#include "Actor.h"
#include "RenderState.h"
#include "EndState.h"

LevelState::LevelState()
{
	glShadeModel(GL_SMOOTH);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
	glEnable(GL_NORMALIZE);
	glDisable(GL_CULL_FACE);
	glEnable(GL_TEXTURE_2D);

	m_view = new View();
	//m_frustum = new Frustum();

	curLevel = 0;
	numLevels = 5;
	m_time = 0;
	pulseCtr = 0;
	loadLevel(0);

	gBuffer = new GBuffer(1280, 720);
	edgeBuffer = new EdgeBuffer(1280, 720);
	edgeLightBuffer = new EdgeLightBuffer(1280, 720);
	finalBuffer = new FinalBuffer(1280, 720);
	finalBlurBuffer = new BlurBuffer(1280, 720);

	device = new AudioDevicePtr(OpenDevice());
	pulse = new OutputStreamPtr(OpenSound(*device,"Data/Sound/pulse.wav", false));
	
}

void LevelState::resize(int nWidth, int nHeight)
{
	if(nHeight == 0)
	{
		nHeight = 1;
	}
	GLfloat nAspect = GLfloat(nWidth) / nHeight;
	m_view->viewport(0, 0, nWidth, nHeight);
	m_view->set3D(45.0f,nAspect,0.01,50);
	m_view->set2D(0,1,0,1,0,1);
}

void LevelState::tick(int nFps)
{
	m_time += 1.0f/nFps;

	m_camera->move(30.0/(float)nFps);

	for (int i=0; i<m_edgeLights.size(); i++)
	{
		m_edgeLights[i][0][3] += 0.2/(float)nFps;
	}
	
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	gBuffer->drawToBuffer(m_view, m_camera, m_level);
	edgeBuffer->drawToBuffer(gBuffer->getNormalTex(), gBuffer->getDepthTex(), m_view);
	edgeLightBuffer->drawToBuffer(gBuffer->getDepthTex(), m_view, m_camera, m_edgeLights);
	finalBuffer->drawToBuffer(gBuffer->getColorTex(), edgeBuffer->getEdgeTex(), edgeLightBuffer->getLightTex(), m_view);
	finalBlurBuffer->drawToBuffer(finalBuffer->getFinalTex(), m_view);
	finalBlurBuffer->drawToBuffer(finalBlurBuffer->getBlurTex(), m_view);
	finalBlurBuffer->drawToBuffer(finalBlurBuffer->getBlurTex(), m_view);

	m_view->use3D(false);

	glActiveTexture(GL_TEXTURE0); 

	if (RenderStateManager::RENDERSTATE == FINAL)
	{
		finalBlurBuffer->bindBlurTex();
	}
	if (RenderStateManager::RENDERSTATE == COLOR)
	{
		gBuffer->bindColorTex();
	}
	if (RenderStateManager::RENDERSTATE == NORMALS)
	{
		gBuffer->bindNormalTex();
	}
	if (RenderStateManager::RENDERSTATE == EDGE)
	{
		edgeBuffer->bindEdgeTex();
	}
	if (RenderStateManager::RENDERSTATE == LIGHTING)
	{
		edgeLightBuffer->bindLightTex();
	}
	
	glLoadIdentity();

	glBegin(GL_QUADS);
		glTexCoord2f(0,0);		 glVertex2f(-1,-1);
		glTexCoord2f(1.0f,0);	 glVertex2f(1,-1);
		glTexCoord2f(1.0f,1.0f); glVertex2f(1,1);
		glTexCoord2f(0,1.0f);	 glVertex2f(-1,1);
	glEnd();

	drawText();

	glutSwapBuffers();

	checkLevelEnd();
}

void LevelState::drawText()
{
	char buffer[10];
	glClear(GL_DEPTH_BUFFER_BIT);
	glColor3f(0.0f, 0.0f, 0.0f);
	
	glRasterPos2f(-0.95f, 0.9f);
	glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (const unsigned char *)"WASD to move, Click to pulse.");

	glRasterPos2f(-0.95f, 0.83f);
	_itoa(curLevel+1, buffer, 10);
	char lvlbuffer[10];
	_itoa(numLevels, lvlbuffer, 10);
	string sLevel = string("Level: " + string(buffer) + "/" + string(lvlbuffer));
	glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (const unsigned char *)sLevel.c_str());

	glRasterPos2f(-0.95f, 0.76f);
	_itoa(pulseCtr, buffer, 10);
	string sPulse = string("Pulse: " + string(buffer) + "/30");
	glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (const unsigned char *)sPulse.c_str());

	glRasterPos2f(-0.95f, 0.69f);
	_itoa(m_time, buffer, 10);
	string sTime = string("Time: " + string(buffer) + "/200");
	glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (const unsigned char*)sTime.c_str());

	glColor3f(1.0f, 1.0f, 1.0f);
	glLoadIdentity();
}

void LevelState::onclick()
{
	Vector4 *newLight = new Vector4(m_camera->getEyeX(), m_camera->getEyeY(), m_camera->getEyeZ(), 7.0f/50.0f);
	m_edgeLights.push_back(newLight);
	if (m_edgeLights.size() > 30)
	{
		m_edgeLights.erase(m_edgeLights.begin());
	}
    
	if((*pulse)->isPlaying())
	{
		(*pulse)->stop();
		(*pulse)->reset();
	}
	(*pulse)->setRepeat(false);
	(*pulse)->setVolume(1.0f);
	(*pulse)->play();
	pulseCtr++;
}

void LevelState::checkLevelEnd()
{
	Vector3 endPos = m_level->getEndPos();
	if (curLevel < (numLevels) && (endPos - m_camera->getEyeV()).length() < 2.0)
	{
		curLevel++;
		loadLevel(curLevel);
	}
	if (m_time > 200 || pulseCtr > 30)
	{
		loadLevel(curLevel);
	}
}

void LevelState::loadLevel(int levelNum)
{
	string levelNames[] = { "Level1.txt", "Level2.txt", "Level3.txt", "Level4.txt", "Level5.txt" };
	if (levelNum >= numLevels)
	{
		GameState::GAMESTATE = new EndState(this);
		return;
	}

	m_camera = new Camera();

	m_level = new Level("Data/Levels/" + levelNames[levelNum]);
	m_level->initCamera(m_camera);

	m_time = 0;
	pulseCtr = 0;

	m_edgeLights.clear();
	Vector4 *startLight = new Vector4(m_camera->getEyeX(), m_camera->getEyeY(), m_camera->getEyeZ(), 1.5f);
	m_edgeLights.push_back(startLight);
}