//+------------------------------------------------------------
// Codename: Gravity
//+------------------------------------------------------------

// Include gamefiles
#include <stdio.h>
#include <stdarg.h>
#include "game/engine/cgSound.h"
#include "game/engine/studio.h"
#include "game/engine/text.h"
#include "game/engine/texture.h"
#include "game/engine/timer.h"

#include "game/fBackground.h"
#include "game/fDictionary.h"
#include "game/fFeverMeter.h"
#include "game/fMenu.h"
#include "game/fWord.h"

using namespace fingers;
using namespace engine;

#define STATE_MENU		0
#define STATE_NEW_GAME	1
#define STATE_PLAY		2
#define STATE_PAUSE		4
#define STATE_GAME_OVER	8

#define SOUND_CLICK		0
#define SOUND_OPEN		1
#define SOUND_CLOSE		2
#define SOUND_SPEED		3
#define SOUND_FEVER1	4
#define SOUND_FEVER2	5
#define SOUND_FEVER3	6
#define SOUND_FEVER4	7

cgSound	sound;

text_c	fontTitle;
text_c	fontText;
text_c	fontWord;
text_c	fontHuge;
text_c	fontFlash;

timer_c	timer;

fMenu	menu;

unsigned int	background;
unsigned int	fevermeter;

int		state		= STATE_MENU;
int		difficulty	= 0;

float	newgame		= 0.0f;

int		highscore	= 0;
int		score		= 0;
float	speed		= 1.0f;
int		lastfever	= 1;
int		speedupg	= 10;
float	speedupgs	= 0.0f;
float	feverupgs	= 0.0f;

// Stats
float	starttime	= 0.0f;
float	endtime		= 0.0f;
int		wordcount	= 0;
int		wordspm		= 0;
int		lettercount	= 0;
int		errorcount	= 0;
int		keycount	= 0;

float	next		= 0.0f;
float	delay		= 2.0f;
int		currword	= 0;
int		active		= 0;

fBackground	bg;
fDictionary	dict;
fFeverMeter	fever;
fWord*		current;
fWord		words[32];


void glPrint(int x, int y, const char* text)
{
	glColor3f(0.0f, 0.0f, 0.0f);
	fontText.print(x+1, y+1, text);

	glColor3f(1.0f, 1.0f, 1.0f);
	fontText.print(x, y, text);
}

void glPrint(int x, int y, float r, float g, float b, const char* text)
{
	glColor3f(0.0f, 0.0f, 0.0f);
	fontText.print(x+1, y+1, text);

	glColor3f(r, g, b);
	fontText.print(x, y, text);
}

void glPrint(int x, int y, const char* text, bool title)
{
	glColor3f(0.0f, 0.0f, 0.0f);
	fontTitle.print(x+2, y+2, text);

	glColor3f(0.0f, 0.0f, 1.0f);
	fontTitle.print(x, y, text);
}

void glPrintf(int x, int y, const char* fmt, ...)
{
	char		buffer[256];
	va_list		args;

	if ( fmt )
	{
		va_start(args, fmt);
			vsprintf(buffer, fmt, args);
		va_end(args);

		glPrint(x, y, buffer);
	}
}

void glPrintf(int x, int y, float r, float g, float b, const char* fmt, ...)
{
	char		buffer[256];
	va_list		args;

	if ( fmt )
	{
		va_start(args, fmt);
			vsprintf(buffer, fmt, args);
		va_end(args);

		glPrint(x, y, r, g, b, buffer);
	}
}

//+------------------------------------------------------------
//
//+------------------------------------------------------------
HRESULT keyPress(int keyCode)
{
	if ( state == STATE_MENU )
	{
		static int	menures;

		menures = menu.input(keyCode);

		if ( menures )
		{
			switch ( menures )
			{
			case 0x0100:
				dict.load("dictionary/easy.txt");
				difficulty	= 1;
				speed		= 0.5f;
				state		= STATE_NEW_GAME;
				break;

			case 0x0101:
				dict.load("dictionary/normal.txt");
				difficulty	= 2;
				speed		= 1.0f;
				state		= STATE_NEW_GAME;
				break;

			case 0x0102:
				dict.load("dictionary/hard.txt");
				difficulty	= 3;
				speed		= 1.5f;
				state		= STATE_NEW_GAME;
				break;

			case 0x0103:
				dict.load("dictionary/insane.txt");
				difficulty	= 4;
				speed		= 2.0f;
				state		= STATE_NEW_GAME;
				break;
			}

			speedupg = 10;
			speedupgs = 2.0f;
			newgame	= 3.0f;
			score	= 0;

			current->spawn(dict.getWord());
		}

		if ( keyCode == VK_RETURN )
			sound.soundPlay(SOUND_OPEN);
		else if ( keyCode == VK_ESCAPE )
			sound.soundPlay(SOUND_CLOSE);
		else if ( keyCode == VK_UP || keyCode == VK_DOWN )
			sound.soundPlay(SOUND_CLICK);
	}
	else if ( state == STATE_PLAY )
	{
		if ( keyCode == VK_SPACE )
		{
			if ( current->active )
			{
				int ds = current->getScore();
				
				fever.addFever(ds);

				score += ds * speed * difficulty * fever.getFeverLevel();
				speed += 0.01f;
				speedupg -= 1;
				
				if ( speedupg == 0 )
				{
					sound.soundPlay(SOUND_SPEED);
					speedupg = 10;
					speedupgs = 2.0f;
				}

				lettercount	+= current->getStrLenght();
				errorcount	+= current->getErrors();

				current->finish();

				if ( active == 31 )
					active = -1;

				current = &words[++active];

				wordcount++;
			}
		}
		else if ( keyCode == VK_RETURN )
		{
			state = STATE_PAUSE;
		}
		else if ( keyCode == VK_ESCAPE )
		{
			state = STATE_PAUSE;
		}
		else
		{
			if ( current->active )
			{
				if ( keyCode == VK_SHIFT || keyCode == VK_BACK || keyCode >= 'A' || keyCode <= 'Z' )
					keycount++;

				sound.soundPlay(SOUND_CLICK);
				current->input(keyCode);
			}
		}
	}
	else if ( state == STATE_PAUSE )
	{
		if ( keyCode == VK_RETURN )
		{
			state = STATE_PLAY;
		}
		else if ( keyCode == VK_ESCAPE )
		{
			state = STATE_MENU;
			menu.currentMenu = MENU_MAIN;

			sound.musicLoad("music/track02.mp3", 0, 0, 0);
			sound.musicPlay();
		}
	}
	else if ( state == STATE_GAME_OVER )
	{
		if ( keyCode == VK_RETURN )
		{
			state = STATE_MENU;

			sound.musicLoad("music/track02.mp3", 0, 0, 0);
			sound.musicPlay();
		}
		else if ( keyCode == VK_ESCAPE )
		{
			state = STATE_MENU;
			menu.currentMenu = MENU_MAIN;

			sound.musicLoad("music/track02.mp3", 0, 0, 0);
			sound.musicPlay();
		}
	}

	return S_OK;
}

//+------------------------------------------------------------
//
//+------------------------------------------------------------
HRESULT render()
{
	bg.render(background, timer.time);

	if ( state == STATE_MENU )
	{
		menu.render();
	}
	else if ( state == STATE_NEW_GAME )
	{
		glPrint(300, 300, "N E W   G A M E", true);

		glColor3f(0.0f, 0.0f, 0.0f);
		fontHuge.printf(382, 362, "%.0f", newgame);

		glColor3f(1.0f, 1.0f, 1.0f);
		fontHuge.printf(380, 360, "%.0f", newgame);		
	}
	else if ( state == STATE_PLAY )
	{
		if ( speedupgs > 0 )
		{
			glColor3f(0.0f, speedupgs/4, speedupgs/2);
			fontFlash.printf(200, 200, "%.1fx", speed);

			speedupgs -= timer.delta;
		}

		if ( feverupgs > 0 )
		{
			glColor3f(feverupgs/2, feverupgs/4, 0.0f);
			fontFlash.printf(500, 200, "%dx", fever.getFeverLevel());

			feverupgs -= timer.delta;
		}

		for ( int i = 0; i < 32; i++ )
		{
			words[i].render(fontWord);
		}

		if ( current->active )
		{
			int _score = current->getScore() * speed * fever.getFeverLevel();

			glPrintf(current->x, current->y + 15, 0.5f, 0.5f, 0.5f, "%d", active);
			
			if ( _score != 0 )
			{
				if ( _score > 0 )
					glPrintf(current->x, current->y - 18, 0.0f, 0.0f, 1.0f, "%d", _score);
				else
					glPrintf(current->x, current->y - 18, 1.0f, 0.0f, 0.0f, "%d", _score);
			}
		}

		fever.render(fevermeter);

		current->render(fontWord, true);

		glPushMatrix();
		glLoadIdentity();
		gluOrtho2D(0.0f, 800.0f, 600.0f, 0.0f);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(0.0f, 0.0f, 0.0f, 0.5f);

		glBegin(GL_QUADS);
			glVertex2f(  0,  0);
			glVertex2f(800,  0);
			glVertex2f(800, 35);
			glVertex2f(  0, 35);
		glEnd();

		glDisable(GL_BLEND);
		glPopMatrix();

		glPrintf(350, 2, "%08d", score);
		//glPrintf(10, 2, "Speed: %.1fx", speed);

		glPrintf(20, 60, 1.0f, 0.639f, 0.0f, "%dx", fever.getFeverLevel());
	}
	else if ( state == STATE_PAUSE )
	{
		glPrint(300, 300, "P A U S E", true);
		glPrint(300, 325, "Press [ENTER] to pause/resume");
		glPrint(300, 350, "Press [ESC] to quit to main menu");
	}
	else if ( state == STATE_GAME_OVER )
	{
		glPrint(300, 300, "G A M E   O V E R", true);
		glPrint(300, 325, "Press [ENTER] to start a new game");
		glPrint(300, 350, "Press [ESC] to quit to main menu");

		glColor3f(0.0f, 0.0f, 0.0f);
		fontTitle.printf(82, 427, "Your score: %d (%d)", score, highscore);
		glColor3f(0.0f, 1.0f, 0.0f);
		fontTitle.printf(80, 425, "Your score: %d (%d)", score, highscore);


		if ( lettercount > 0 )
		{
			glPushMatrix();
			glLoadIdentity();
			gluOrtho2D(0.0f, 800.0f, 600.0f, 0.0f);
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glColor4f(0.0f, 0.0f, 0.0f, 0.5f);

			glBegin(GL_QUADS);
				glVertex2f( 80, 450);
				glVertex2f(700, 450);
				glVertex2f(700, 500);
				glVertex2f( 80, 500);
			glEnd();

			glDisable(GL_BLEND);
			glPopMatrix();


			glColor3f(1.0f, 1.0f, 1.0f);
			glPrint(100, 450, "Words total:      ");
			glPrintf(240, 450, "%d", wordcount);
			glPrint(290, 450, "Words pr minute:  ");
			glPrintf(440, 450, "%.1f", wordcount/(endtime-starttime)*60);
			glPrint(500, 450, "Error percent:    ");
			glPrintf(640, 450, "%.0f%%", (float)errorcount/lettercount*100);
			glPrint(100, 470, "Letters total:    ");
			glPrintf(240, 470, "%d", lettercount);
			glPrint(290, 470, "Letters pr minute:");
			glPrintf(440, 470, "%.1f", lettercount/(endtime-starttime)*60);
			glPrint(500, 470, "Key presses total:");
			glPrintf(640, 470, "%d", keycount);
		}
	}

	glColor3f(1.0f, 1.0f, 1.0f);
	fontText.print(600, 570, "Copyright 2008 by Unleeb");

	return S_OK;
}

//+------------------------------------------------------------
//
//+------------------------------------------------------------
HRESULT update()
{
	static float amount;

	timer.update();

	if ( state == STATE_MENU )
	{
		menu.update();
	}
	else if ( state == STATE_NEW_GAME )
	{
		newgame -= timer.delta;

		if ( newgame <= 0 )
		{
			state = STATE_PLAY;
			next  = timer.time + delay;

			for ( int i = 0; i < 32; i++ )
			{
				words[i].active = false;
				words[i].x = 900.0f;
			}

			starttime	= timer.time;
			wordcount	= 0;
			wordspm		= 0;
			lettercount	= 0;
			errorcount	= 0;
			keycount	= 0;

			active = 0;
			currword = 0;

			fever.amount = 0;

			current = &words[0];

			sound.musicLoad("music/track01.mp3", 0, 0, 0);
			sound.musicPlay();
		}
	}
	else if ( state == STATE_PLAY )
	{
		amount = timer.delta * speed;
		wordspm = wordcount / (timer.time - starttime);

		static int currfever;

		currfever = fever.getFeverLevel();
		if ( lastfever < currfever )
		{
			if ( currfever == 2 )
				sound.soundPlay(SOUND_FEVER1);
			else if ( currfever == 4 )
				sound.soundPlay(SOUND_FEVER2);
			else if ( currfever == 8 )
				sound.soundPlay(SOUND_FEVER3);
			else if ( currfever == 16 )
				sound.soundPlay(SOUND_FEVER4);
		}
		if ( lastfever != currfever )
			feverupgs = 2.0f;

		lastfever = currfever;

		if ( next <= timer.time )
		{
			if ( currword == 32 )
				currword = 0;

			words[currword++].spawn(dict.getWord());
			next += delay / speed;
		}

		for ( int i = 0; i < 32; i++ )
		{
			words[i].update(amount);

			if ( words[i].x <= - words[i].getLenght() - 10 )
				words[i].active = false;
		}

		fever.update(timer.delta);

		if ( current->x <= -current->getLenght() )
		{
			if ( current->active )
			{
				state = STATE_GAME_OVER;
				endtime = timer.time;
			}
		}
	}
	else if ( state == STATE_PAUSE )
	{
		next += timer.delta;
	}
	else if ( state == STATE_GAME_OVER )
	{
		highscore = (score > highscore) ? score : highscore;
	}

	return S_OK;
}

//+------------------------------------------------------------
//
//+------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrecInstance, LPSTR lpCmdLine, int nShowCmd)
{
	srand((int)GetTickCount());

	studio_c studio("Fingers", 800, 600, 32, 16, 8, true);

	studio.onKeyPress	= &keyPress;
	studio.onRender		= &render;
	studio.onUpdate		= &update;

	fontTitle.create(studio.m_hDC, 34, "Trebuchet MS");
	fontText.create(studio.m_hDC, 22, "Trebuchet MS");
	fontWord.create(studio.m_hDC, 22, "Courier New");
	fontHuge.create(studio.m_hDC, 48, "Trebuchet MS");
	fontFlash.create(studio.m_hDC, 94, "Trebuchet MS");

	current = &words[0];

	background = texloader.loadBMP("textures/background.bmp");
	fevermeter = texloader.loadBMP("textures/fevermeter.bmp", true);

	menu.initialize(studio.m_hDC);

	sound.initialize();
	sound.soundPrecache(SOUND_CLICK, "sounds/click.wav");
	sound.soundPrecache(SOUND_OPEN, "sounds/open.wav");
	sound.soundPrecache(SOUND_CLOSE, "sounds/close.wav");
	sound.soundPrecache(SOUND_SPEED, "sounds/speed.wav");
	sound.soundPrecache(SOUND_FEVER1, "sounds/fever1.wav");
	sound.soundPrecache(SOUND_FEVER2, "sounds/fever2.wav");
	sound.soundPrecache(SOUND_FEVER3, "sounds/fever3.wav");
	sound.soundPrecache(SOUND_FEVER4, "sounds/fever4.wav");
	sound.musicLoad("music/track02.mp3", 0, 0, 0);
	sound.musicPlay();
	sound.musicVolume(75);

	studio.begin();

	sound.musicStop();
	sound.musicUnload();
	sound.soundUnload(SOUND_FEVER4);
	sound.soundUnload(SOUND_FEVER3);
	sound.soundUnload(SOUND_FEVER2);
	sound.soundUnload(SOUND_FEVER1);
	sound.soundUnload(SOUND_SPEED);
	sound.soundUnload(SOUND_CLOSE);
	sound.soundUnload(SOUND_OPEN);
	sound.soundUnload(SOUND_CLICK);
	sound.finalize();

	return 0;
}