#include "CommandManager.h"

#include "Command.h"
#include "List.h"
#include "Parser.h"
#include "SDL.h"
#include "Screen.h"

#include <fstream>


using namespace std;

CommandManager *CommandManager::_instance = NULL;

CommandManager::CommandManager()
:_recording(false),_playing(false),_flush(false)
{
	_instance = this;
}

void CommandManager::execute(Command *command)
{
	command->execute();
	
	if(_recording) {
		CommandTime demo;
		demo.c = command;
		demo.time = _demoTime;
		_demoCommands.push(demo);
	}
	else
		delete command;
}

void CommandManager::execute(std::queue<Command *> commands)
{
	while(!commands.empty()) {
		commands.front()->execute();
		commands.pop();
	}
}

void CommandManager::startPlaying(std::priority_queue<CommandTime,std::vector<CommandTime>,std::greater<CommandTime> > &commands)
{
	if(!_playing) {
		_playing = true;
		_playTime = 0;
	}

	while(!commands.empty()) {
		commands.top().time += _playTime;
		_playCommands.push(commands.top());
		commands.pop();
	}
}

void CommandManager::startPlaying(List *commands)
{
	priority_queue<CommandTime,std::vector<CommandTime>,std::greater<CommandTime> > newCommands;

	while(!commands->empty()) {
		CommandTime commandTime;
		commandTime.time = atoi(commands->firstString().c_str()) ;//* Screen::FRAMERATE / 1000;
		commands = commands->rest();
		List *command = commands->firstList();
		commandTime.c = Command::loadCommand(command);

		newCommands.push(commandTime);
		commands = commands->rest();
	}

	startPlaying(newCommands);
}

void CommandManager::startPlaying(std::string filename)
{
	ifstream file(filename.c_str());
	List *commands = Parser::parse(filename);
	startPlaying(commands);
	delete commands;
}

void CommandManager::stopPlaying()
{
	_playing = false;
}

CommandManager *CommandManager::instance()
{
	if(!_instance)
		return new CommandManager();
	else
		return _instance;
}

void CommandManager::startRecording()
{
	_demoCommands.empty();
	_recording = true;
	_demoTime = 0;
}

void CommandManager::stopRecording()
{
	_recording = false;
}

void CommandManager::saveRecording(std::string filename)
{
	ofstream file(filename.c_str());
	file << Parser::open << endl;
	priority_queue<CommandTime,std::vector<CommandTime>,std::greater<CommandTime> > writeCommands(_demoCommands);
	while(!writeCommands.empty()) {
		file << writeCommands.top().time  << " ";//* 1000 / Screen::FRAMERATE << " ";
		file << writeCommands.top().c->getString() << endl;
		writeCommands.pop();
	}
	file << Parser::close;
}

void CommandManager::flush()
{
	_flush = true;
}

void CommandManager::startTimestep()
{
	if(_flush) {
		while(!_playCommands.empty()) {
			delete _playCommands.top().c;
			_playCommands.pop();
		}
		//_playCommands.c.clear();
		_playing = false;
		_flush = false;
	}
	if(_recording)
		_demoTime++;
	if(_playing && !_playCommands.empty()) {
		_playTime++;
		CommandTime top = _playCommands.top();
		while(top.time < _playTime) {
			//execute(top.c);
			top.c->execute();
			delete top.c;
			_playCommands.pop();
			if(_playCommands.empty()) {
				_playing = false;
				break;
			}
			else
				top = _playCommands.top();
		}
	}
}