/*
   client/client.cc
   This file is part of the Osirion project and is distributed under 
   the terms and conditions of the GNU General Public License version 2 
*/

#include "client/chat.h"
#include "client/client.h"
#include "client/video.h"
#include "client/camera.h"
#include "client/console.h"
#include "client/input.h"
#include "client/view.h"
#include "core/core.h"

// SDL headers
#include <SDL/SDL.h>

// C++ headers
#include <iostream>
#include <cmath>

namespace client 
{

core::Cvar *cl_framerate = 0;

//--- private definition ------------------------------------------
/// client application implementation
class Client : public core::Application
{
public:
	/// initialize the client Client
	virtual void init();

	/// run the client Client
	virtual void run();

	/// shutdown the client Client
	virtual void shutdown();

	/// quit the client Client
	virtual void quit(int status);
};

Client app;

//--- engine functions --------------------------------------------

void func_r_restart(std::stringstream &args)
{
	video::shutdown();
	console::flush();

	if (!video::init()) {
		console::flush();
		app.quit(1);
	}
}

//--- public ------------------------------------------------------

void main(int count, char **arguments)
{
	std::cout << core::name() << " " << core::version() << std::endl;

	for (int i =0; i < count; i++)
		std::cout << arguments[i] << " ";
	std::cout << std::endl;

	app.init();
	app.run();
	app.shutdown();
}

//--- private -----------------------------------------------------

void Client::quit(int status)
{
	SDL_Quit();
	core::Application::quit(status);
}

void Client::init()
{
	con_print << "Initializing client..." << std::endl;
	
	// initialize core
	core::Cvar::sv_dedicated = core::Cvar::set("sv_private", "0");
	core::Application::init();

	// client variables
	core::Cvar::get("cl_name", "Player", core::Cvar::Archive);
	core::Cvar::get("cl_color", "1.0 1.0 1.0", core::Cvar::Archive);
	cl_framerate = core::Cvar::get("cl_framerate", "120", core::Cvar::Archive);

	// initialize SDL, but do not initialize any subsystems
	SDL_Init(0);

	// Initialize the video subsystem
	if (!video::init()) {
		console::flush();
		quit(1);
	}

	// initialize console
	console::init();
	chat::init();
	
	// initialize input
	input::init();
	
	// add engine functions
	core::Func::add("r_restart", (core::FuncPtr) func_r_restart);
}

void Client::run()
{
	con_print << "Running client..." << std::endl;

	Uint32 client_framerate =  (Uint32)(1000/120);
	Uint32 elapsed = 0;

	while (true) {
		if (cl_framerate->value())
			client_framerate = (Uint32) (1000.0f / cl_framerate->value());

		Uint32 chrono = SDL_GetTicks();

		core::Application::frame((float)elapsed / 1000.0f);
		video::frame((float)elapsed / 1000.0f);
		input::frame((float)elapsed / 1000.0f);
		
		// sleep
		Uint32 current = SDL_GetTicks();

		elapsed = current - chrono;

		if (elapsed < client_framerate) {
			SDL_Delay(client_framerate - elapsed);
			elapsed = client_framerate;
		}
	}

}

void Client::shutdown()
{
	con_print << "Shutting down client..." << std::endl;
	console::flush();

	// remove engine functions
	core::Func::remove("r_restart");

	chat::shutdown();

	console::shutdown();
	console::flush();

	input::shutdown();
	console::flush();

	video::shutdown();
	console::flush();

	core::Application::shutdown();
	console::flush();

	quit(0);
}

} // namespace client