//	Challenge.cpp - The main Challenge game mode.
//  ----------------------------------------------------------------------------
//	This file is part of 'GameTemplate', template code for a game.
//	Copyright (C) 2011  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#include "generators/PickupGenerator.h"
#include "drawing/Drawer.h"
#include "TonesSounder.h"
#include "PitchFactory.h"
#include "DebugHeaders.h"
#include "Challenge.h"

#include <sstream>
#include <algorithm>

using namespace std;

//------------------------------------------------------------------------------
GameStateCreator<Challenge> Challenge::creator;

//------------------------------------------------------------------------------
Challenge::Challenge(Application&app, SounderPtr& sound):
GameState(app, sound),
gameCore(dynamic_pointer_cast<TonesSounder>(sound)),
numLives(3),
gameOverCount(30),
paused(false),
sounder(dynamic_pointer_cast<TonesSounder>(sound))
{
	globalData = dynamic_pointer_cast<TonesGlobalData>(getGlobalData());

	gameCore.setPure(globalData->getPure());
	gameCore.setZen(globalData->getZen());
	gameCore.setGameCounter(globalData->getCounter());

	globalData->getCounter()->reset();
	globalData->getCounter()->incrementCount(L"Lives", 3, false);

	sounder->setPitches(PitchFactory::getInstance().getPitches(5));
	gameCore.setNumRails(5);

	gameCore.setCallback(this);
}

//------------------------------------------------------------------------------
Challenge::~Challenge()
{
	sounder->setGlobalPitch(1.0f);
	globalData->getCounter()->unregisterNotification(L"NearMisses", 6, this);
}

//------------------------------------------------------------------------------
void Challenge::update()
{
	if(!paused)
	{
		if(numLives > 0)
			gameCore.tick();
		else if(gameOverCount)
		{
			if(gameOverCount == 30)
				gameCore.setPause(true, true);

			--gameOverCount;
		}
	}
}

//------------------------------------------------------------------------------
void Challenge::draw(DrawerPtr& d, float timestepInterp)
{
	wstringstream tempstr;

	//Draw the core of the game.
	gameCore.draw(d, timestepInterp);

	//Draw the score.
	tempstr << globalData->getCounter()->getScore();
	d->drawText(L"Score:",
				L"Font0",
				textLayouts[0],
				TwoFloats(20.0f, 50.0f),
				512.0f,
				TextLayout::Left,
				1.0f,
				ThreeFloats(0.5f));
	d->drawText(tempstr.str(),
				L"Font0",
				TwoFloats(175.0f, 52.0f),
				512.0f,
				TextLayout::Left,
				1.0f,
				ThreeFloats(0.75f));

	//Draw the player's remaining lives.
	d->drawText(L"Lives:",
				L"Font0",
				textLayouts[1],
				TwoFloats(940.0f, 50.0f),
				512.0f,
				TextLayout::Left,
				1.0f,
				ThreeFloats(0.5f));
	if(numLives > 0)
	{
		d->drawImage(L"crash",
					 TwoFloats(1075.0f, 5.0f),
					 TwoFloats(0.5f),
					 ThreeFloats(0.75f));
	}
	if(numLives > 1)
	{
		d->drawImage(L"crash",
					 TwoFloats(1140.0f, 5.0f),
					 TwoFloats(0.5f),
					 ThreeFloats(0.75f));
	}
	if(numLives > 2)
	{
		d->drawImage(L"crash",
					 TwoFloats(1205.0f, 5.0f),
					 TwoFloats(0.5f),
					 ThreeFloats(0.75f));
	}

	//Draw the game over text.
	if(!numLives)
	{
		std::wstringstream scoreText;

		d->drawImage(L"gameOver", TwoFloats(246.0f, 299.0f));

		if(globalData->getChallengeLastScore() == globalData->getChallengeHighScore())
			scoreText << L"New High Score!\n\n";

		scoreText << L"High Score: " << globalData->getChallengeHighScore();
		d->drawText(scoreText.str(),
					L"Font0",
					TwoFloats(0.0f, 100.0f),
					d->getDrawingAreaSize().x,
					TextLayout::Centre,
					1.0f,
					0.5f);
	}

	//Draw paused text.
	if(paused)
	{
		d->drawText(L"(Paused)",
					L"Font0",
					textLayouts[2],
					TwoFloats(0.0f, 120.0f),
					d->getDrawingAreaSize().x,
					TextLayout::Centre,
					1.0f,
					ThreeFloats(0.5f));
	}
}

//------------------------------------------------------------------------------
void Challenge::toneCollision()
{
	float speed = gameCore.getGlobalSpeed();

	if(zen)
	{
		speed *= 0.75f;
		if(speed < 0.5f)
			speed = 0.5f;

		gameCore.setGlobalSpeed(speed);
	}

	if(numLives > 2)
		globalData->getCounter()->resetCount(L"NearMisses");
	--numLives;
	globalData->getCounter()->incrementCount(L"Lives", -1, false);
	globalData->getCounter()->registerNotification(L"NearMisses", 6, this);

	if(numLives < 1)
		globalData->updateChallengeScores(globalData->getCounter()->getScore());
}

//------------------------------------------------------------------------------
void Challenge::countReached(const wstring& counter, int value)
{
	if(numLives < 3)
	{
		++numLives;
		globalData->getCounter()->incrementCount(L"Lives", 1, false);
		//if(numLives < 3)
			globalData->getCounter()->resetCount(L"NearMisses");
	}
	//globalData->getCounter()->unregisterNotification(L"NearMisses", 6, this);
}

//------------------------------------------------------------------------------
void Challenge::keyDown(const wstring& action,
						const wstring& keyPressed,
						int keyModifier)
{
	if(action == L"Escape")
	{
		if((gameOverCount>0) && !paused)
		{
			paused = true;
			gameCore.setPause(paused);
		}
		else
			nextState(L"TitleScreen");
	}
	else if(paused)
	{
		paused = false;
		gameCore.setPause(paused);
	}
}

//------------------------------------------------------------------------------
void Challenge::mouseDown(int button, const TwoFloats& pos)
{
	if(numLives > 0)
	{
		if(paused)
		{
			paused = false;
			gameCore.setPause(paused);
		}
		else
			gameCore.mouseDown(button, pos);
	}
	else if(!gameOverCount)
		nextState(L"TitleScreen");
}

//------------------------------------------------------------------------------
void Challenge::mouseUp(int button, const TwoFloats& pos)
{
	gameCore.mouseUp(button, pos);
}

//------------------------------------------------------------------------------
void Challenge::mouseMove(const TwoFloats& pos)
{
	gameCore.mouseMove(pos);
}
