#include "cGame.h"
#include "cSoundManager.h"
#include "cTextureManager.h"
#include "cTextManager.h"
#include "cParticleManager.h"
#include "OGLPlatformSpecific.h"

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

cGame* cGame::instance_ = 0;

cGame* cGame::instance()
{
    if(instance_ == 0)
        instance_ = new cGame;
    return instance_;
}

cGame::cGame()
{
    // Nothing to do
}


void cGame::init()
{
	srand ( time(NULL) );
    
	started_ = false;
	cParticleManager::instance(); // make sure particle manager is initializied
	cSoundManager::instance(); // create sound manager if it doesnt exist
    cTextureManager::instance(); // load textures if they havent already been loaded
}

void cGame::startGame()
{
	started_ = true;
    grid_.randomizeDropBlocks();
	
	t_ = 0;
    grid_.mode_ = DROPPING_BLOCKS;
	grid_.reset();
	
	grid_.setTranslation(0);
	if(numPlayers_ == 2)
	{
		grid_.setTranslation(13);
		grid2_.randomizeDropBlocks();
		grid2_.setTranslation(-13);
		grid2_.mode_ = DROPPING_BLOCKS;

		grid2_.reset();
	}
    
	grid_.mode_ = GRID_FALL;
	grid2_.mode_ = GRID_FALL;
	grid_.score_ = 0;
	grid2_.score_ = 0;
	grid_.attackScore_ = 0;
	grid2_.attackScore_ = 0;

    upKeyPressed_ = downKeyPressed_ = leftKeyPressed_ = rightKeyPressed_ = false;
}


void cGame::display()
{      
   // clear color and depth buffers
    glClear(GL_COLOR_BUFFER_BIT);
	
    update();
    
	float size = 100;
	cTextureManager::instance()->bindBGTexture();
	glEnable(GL_TEXTURE_2D);

	glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glLoadIdentity();
    glRotatef(t_, 0, 0, 1);

	glColor3f(1,1,1);
	
	glBegin(GL_TRIANGLE_STRIP);		
		glNormal3f(0,-1,0);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(size, 3, size); 	
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-size, 3, size); 
        glTexCoord2f(1.0f, 0.0f); glVertex3f(size, 3, -size); 
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-size, 3, -size); 	
    glEnd();

    glBegin(GL_TRIANGLE_STRIP);		
		glNormal3f(0,-1,0);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(size, -3, size); 	
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-size, -3, size); 
        glTexCoord2f(1.0f, 0.0f); glVertex3f(size, -3, -size); 
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-size, -3, -size); 	
    glEnd();

	glDisable(GL_TEXTURE_2D);
    cTextureManager::instance()->unbindTexture();
	
	glPopMatrix();
    glMatrixMode(GL_MODELVIEW);

	if(!started_)
	{
		cTextManager::instance()->draw(screenWidth_/7.5 + 75, screenHeight_/2 - 10, "How Many Players? (1 or 2)");
		glutSwapBuffers();
		return;
	}

    grid_.draw();

	char scoreStr[255];

	if(numPlayers_ == 2)
	{
		grid2_.draw();
		itoa(grid2_.score_,scoreStr,10);
		cTextManager::instance()->draw(20,20, scoreStr);
	}
	
	itoa(grid_.score_,scoreStr,10);
	cTextManager::instance()->draw(screenWidth_ - 50,20, scoreStr);
    
	cParticleManager::instance()->draw();


	if(numPlayers_ == 2)
	{
		if(grid_.mode_ == GAME_OVER)
		{
			cTextManager::instance()->draw(screenWidth_ - screenWidth_/3,screenHeight_/2, "GAME OVER");
			cTextManager::instance()->draw(screenWidth_/7.5, screenHeight_/2, "You Win!");

		}

		if(grid2_.mode_ == GAME_OVER)
		{
			cTextManager::instance()->draw(screenWidth_/8,screenHeight_/2, "GAME OVER");
			cTextManager::instance()->draw(screenWidth_ - screenWidth_/4,screenHeight_/2, "You Win!");
		}
	}
	else if(numPlayers_ == 1)
	{
		if(grid_.mode_ == GAME_OVER)
		{
			cTextManager::instance()->draw(screenWidth_/3,screenHeight_/2, "GAME OVER");
		}
	}

	if(paused_)
		cTextManager::instance()->draw(0,screenHeight_ - 20, "PAUSED");

    // flush buffer
    glutSwapBuffers();
}
    
void cGame::update()
{
	if( paused_ )
		return;

    float dt = timer_.update();
    t_ += dt;
    grid_.timeSinceDrop_ += dt;
    grid_.timeSinceMove_ += dt;
    grid_.timeSinceExplode_ += dt;

	grid_.timeToDrop_ -=  .001 * dt;
	if(grid_.timeToDrop_ < .2) grid_.timeToDrop_ = .2;
    
	cParticleManager::instance()->update(dt);
	

	if(grid_.mode_ == GAME_OVER || grid2_.mode_ == GAME_OVER )
		return;

    switch(grid_.mode_)
    {
    case DROPPING_BLOCKS: dropBlocks(); break;
    case EXPLODING: 
		grid_.explode(); 
	break;

    case GRID_FALL: 
		if(grid2_.attackScore_ > 1)
		{	
			grid_.makeAttackRows(grid2_.attackScore_);
			grid2_.attackScore_ = 0;
		}

		grid_.gridFall(); break;
	case GAME_OVER: break;
    }
/////////////////////////////////////////////////////

	if(numPlayers_ != 2) return;

	grid2_.timeSinceDrop_ += dt;
    grid2_.timeSinceMove_ += dt;
    grid2_.timeSinceExplode_ += dt;

	grid2_.timeToDrop_ -=  .001 * dt;
	if(grid2_.timeToDrop_ < .2) grid_.timeToDrop_ = .2;

    switch(grid2_.mode_)
    {
    case DROPPING_BLOCKS: dropBlocks(); break;
    case EXPLODING: 
		grid2_.explode(); 
	break;

    case GRID_FALL: 
		if(grid_.attackScore_ > 1)
		{
			grid2_.makeAttackRows(grid_.attackScore_);
			grid_.attackScore_ = 0;
		}

		grid2_.gridFall(); break;
	case GAME_OVER: break;
    }
}

void cGame::dropBlocks()
{
    if(grid_.timeSinceMove_ >= grid_.timeToMove_)
    {
        grid_.timeSinceMove_ = 0;
        if(key4Pressed_) grid_.moveDroppingBlocks(-1, 0);
        if(key6Pressed_) grid_.moveDroppingBlocks(1, 0);
        if(key5Pressed_ && !grid_.moveDroppingBlocks(0, -1)) grid_.collideBlocks();
    }
    if( grid_.timeSinceDrop_ >= grid_.timeToDrop_)
    {
        grid_.timeSinceDrop_ = 0;
        if(!grid_.moveDroppingBlocks(0,-1)) grid_.collideBlocks();
    } 

	//////////////////////////////////
	if(grid2_.timeSinceMove_ >= grid2_.timeToMove_)
    {
        grid2_.timeSinceMove_ = 0;
        if(jKeyPressed_) grid2_.moveDroppingBlocks(-1, 0);
        if(lKeyPressed_) grid2_.moveDroppingBlocks(1, 0);
        if(kKeyPressed_ && !grid2_.moveDroppingBlocks(0, -1)) grid2_.collideBlocks();
    }
    if( grid2_.timeSinceDrop_ >= grid2_.timeToDrop_)
    {
        grid2_.timeSinceDrop_ = 0;
        if(!grid2_.moveDroppingBlocks(0,-1)) grid2_.collideBlocks();
    } 
 }


void cGame::idle()
{
    glutPostRedisplay();
}



void cGame::keyboard(unsigned char key, int x, int y) 
{
	if( key == 'p')
		paused_ = !paused_;

    if(grid_.mode_ != DROPPING_BLOCKS) return;
    


	
    switch(key)
    {
    case 'z': 
		grid2_.rotateDroppingBlocksL(); 
		cSoundManager::instance()->playMoveBlock();
	break;
    case 'x': 
		grid2_.rotateDroppingBlocksR(); 
		cSoundManager::instance()->playMoveBlock();
		break;
    }
	

	switch (key)
    {
        case 'j': 	jKeyPressed_ = true; break;
		case 'k': 	kKeyPressed_ = true; break;
		case 'l': 	lKeyPressed_ = true; break;

		case '4':	key4Pressed_ = true; break;
		case '5':	key5Pressed_ = true; break;
		case '6':	key6Pressed_ = true; break;
	}
}

void cGame::keyboardUp(unsigned char key, int x, int y) 
{
	if(!started_)
	{
		if(key == '1')
		{
			numPlayers_ = 1;
			startGame();
			
		}

		if(key == '2')
		{
			numPlayers_ = 2;
			startGame();
		}
	}

	switch (key)
    {
        case 'j': 	jKeyPressed_ = false; break;
		case 'k': 	kKeyPressed_ = false; break;
		case 'l': 	lKeyPressed_ = false; break;

		case '4':	key4Pressed_ = false; break;
		case '5':	key5Pressed_ = false; break;
		case '6':	key6Pressed_ = false; break;

		case 'r': grid_.makeAttackRows(3);
	}

	if(grid_.mode_ == GAME_OVER || grid2_.mode_ == GAME_OVER)
	{
		started_ = false;
		//startGame();
		return;
	}
}



void cGame::specialKey(int key, int x, int y)
{	   
	if(grid_.mode_ == GAME_OVER)
	{
		startGame();
		return;
	}

    switch (key)
    {
        case GLUT_KEY_LEFT: 
			grid_.rotateDroppingBlocksL(); 
			cSoundManager::instance()->playMoveBlock(); break;

        case GLUT_KEY_DOWN: 
			grid_.rotateDroppingBlocksR(); 
			cSoundManager::instance()->playMoveBlock();
			break;
    }
}

void cGame::specialKeyUp(int key, int x, int y)
{
}

void cGame::mouseClick(int button, int state, int x, int y) 
{
	
}

void cGame::mouseMove(int x, int y)
{
     
}


