/* Copyright (C) 2007  Mikko Sysikaski <mikko.sysikaski@gmail.com>
 * This program is free software distributed under GNU General Public License
 * version 3 or (at your option) any later version.
 * No warranty of any kind is provided. See the accompanying file COPYING for details.
 */

#include "gameloop.h"
#include "physics.h"
#include "board.h"
#include "renderer.h"
#include "eventhandler.h"
#include "gameapp.h"
#include "ingamemenu.h"
#include "besttimes.h"
#include "sound.h"
#include "glscreen.h"

//#define COUNTFPS
#include "idler.h"
//#undef COUNTFPS

GameLoop::GameLoop(const char* boardFile):
	m_board(*(new Board(boardFile))), m_times(&BestTimes::getInstance().getTimes(boardFile)),
	m_next(0), m_freeBoard(1)
{
}

GameLoop::GameLoop(Board& board):
	m_board(board), m_times(0), m_next(0), m_freeBoard(0)
{
}

GameLoop::~GameLoop()
{
	if (m_freeBoard)
		delete &m_board;
}

bool GameLoop::start(bool pack)
{
	bool next = 0;
	GameApp& game = GameApp::getInstance();
	EventHandler& events = game.getEventHandler();
	Physics& physics = game.getPhysics();
	Renderer& renderer = game.getRenderer();

	events.resetMouse();
	physics.setBoard(&m_board);
	renderer.setBoard(&m_board, &physics);
	renderer.init();
	
	Idler idler(100);
	while(!m_next) {
		uint frameTime = idler.idle();
		renderer.render();
		physics.updateCounter();
		SDL_GL_SwapBuffers();
		
		int maxTime = m_board.getMinTime();
		LCDCounter& counter = physics.getCounter();
		if (maxTime >= 0 && counter.getTime() > maxTime) {
			counter.stop();
			if (!handleMenu(Physics::DIE, next))
				return 0;
			idler.reset();
		}
		
		switch (events.processEvents()) {
			case EventHandler::QUIT:
				return 0;
			case EventHandler::MENU:
				if (!handleMenu(Physics::NORMAL, next))
					return 0;
				idler.reset();
				break;
			case EventHandler::RESET:
				physics.resetBoard();
				events.resetMouse();
			default:
				break;
		}
		Physics::UpdateState state;
		if ((state=physics.update(frameTime)) != Physics::NORMAL) {
			if (state == Physics::WIN && pack)
				next = 1;
			if (!handleMenu(state, next))
				return 0;
			idler.reset();
		}
	}
	SDL_ShowCursor(SDL_ENABLE);
	return 1;
}

bool GameLoop::handleMenu(Physics::UpdateState state, bool nextAvail)
{
	bool running = state==Physics::NORMAL?1:0;
	bool winState = state==Physics::WIN?1:0;
	GameApp& game = GameApp::getInstance();

	int place = -1;
	if (winState && m_times) {
		place = m_times->insert(game.getPhysics().getCounter().getTime());
		if (place >= 0)
			BestTimes::getInstance().save("times.dat");
	}

	game.getPhysics().getCounter().stop();
	InGameMenu menu(running, nextAvail, winState, place, m_times);
	switch (menu.exec()) {
		case InGameMenu::RESET:
			game.getPhysics().resetBoard();
			game.getEventHandler().resetMouse();
			return 1;
			break;
		case InGameMenu::QUIT:
			return 0;
		case InGameMenu::NEXT:
			m_next = 1;
			break;
		default:
			break;
	}
	game.getPhysics().getCounter().start();
	return 1;
}

void GameLoop::init()
{
	Sound::getInstance().playGame();
}
void GameLoop::deInit()
{
	Sound::getInstance().playMenu();
	GLScreen::set2D();
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);
}
