#include "Menu.h"
#include "List.h"
#include "Parser.h"
#include "Sprite.h"
#include "Game.h"
#include "Control.h"

using namespace std;

int Menu::_textHeight = 50;
int Menu::_leftMargin = 150;
int Menu::_topMargin = 100;
Menu::Menu()
:_selected(0),_background(0)
{
}
Menu::Menu(std::string filename)
:_selected(0),_background(0)
{
	List* menuInfo = Parser::parse(filename);
	load(menuInfo);
	delete menuInfo;
}

Menu::Menu(List* menuInfo)
:_selected(0),_background(0)
{
	load(menuInfo);
}

void Menu::load(List* menuInfo)
{
		
	menuInfo = menuInfo->rest();
		while(!menuInfo->empty())
		{
			List * current = menuInfo->firstList();
			menuInfo = menuInfo->rest();

			if(current->firstString() == "submenu")
			{
				current = current->rest();
				_options.push_back(new Menu(current->firstString()));
			}
			else if(current->firstString() == "menu")
			{
				_options.push_back(new Menu(current));
			}
			else if(current->firstString() == "selectKey")
			{
				_options.push_back(new SelectKeyMenu(current));
			}
			else if(current->firstString() == "newGame")
			{
				_options.push_back(new NewGameMenu(current));
			}
			else if(current->firstString() == "background")
			{
				current = current->rest();
				_background = Sprite::loadSprite(current->firstString());
			}
			else if(current->firstString() == "title")
			{
				current = current->rest();
				_title = current->firstString();
			}
			else if(current->firstString() == "subtitle")
			{
				current = current->rest();
				_subtitles.push_back("    " + current->firstString());
			}
		}

	if(_background)
        _background->setRect(Screen::instance()->getScreenRect());

	_selectedMax = _options.size() - 1;
}

void Menu::drawTitle(int x, int y, bool selected)
{
	if(selected)
		glfuncs::instance()->glPrint( x, y, "> " + _title, false);
	else
		glfuncs::instance()->glPrint( x, y, "  " + _title, false);
}

bool Menu::control(SDL_Event event)
{

	if(event.type == SDL_KEYDOWN) {
		if(event.key.keysym.sym == Control::menuDownKey){
			if(_selected < _selectedMax)
				_selected ++;
		}
		else if(event.key.keysym.sym == Control::menuUpKey){
			if(_selected > 0)
				_selected --;
		}
		else if(event.key.keysym.sym == Control::selectKey){
			return select();
		}
	}
	return false;
}

void Menu::draw()
{
	if(_background)
		_background->draw(0,0,Sprite::SCREEN);

	drawTitle(_leftMargin,_topMargin,false);


	int offset =  _topMargin + _textHeight - _textHeight/4;

	for(int i=0; i<_subtitles.size(); i++){
		glfuncs::instance()->glPrint( _leftMargin, offset, _subtitles[i], true);
		offset+= _textHeight/4;
	}

	offset += _textHeight;
	for(size_t i = 0; i< _options.size(); i++)
		_options[i]->drawTitle(_leftMargin,offset + _textHeight*i, _selected==i);


	// Draw Team Scramble logo
	Screen::drawScramble();
		


}

bool Menu::select()
{
	_options[_selected]->mainLoop();
	return false;
}

void Menu::mainLoop()
{
	SDL_Event event;
	Screen* screen = Screen::instance();
	bool leave = false;
	int ticks = SDL_GetTicks();	// used to limit the frame rate



	while( !leave)
	{
		// Clear OpenGL screen
		glfuncs::instance()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		//This runs if we are trying to run frames in too rapid succession
		while((SDL_GetTicks() - ticks) < 1000/Screen::FRAMERATE)
		{
			//Just wait until we can do a frame again
			Sleep(0);
		}

		//reset for the next time we want to update
		ticks = SDL_GetTicks();

		draw();

		// Clean up
		glfuncs::instance()->glFinish();
		SDL_GL_SwapBuffers();

		// Check that escape key isn't being pressed
		while(SDL_PollEvent(&event))
		{
			leave = control(event);
			if(event.type == SDL_KEYDOWN) {
				if( event.key.keysym.sym == Control::quitKey)
					leave = true;
			}
			//if user has Xed out
			else if( event.type == SDL_QUIT )
            {
                leave = true;
            }
		}

	}
}

Menu::~Menu()
{
	for(size_t i =0 ; i< _options.size(); i++)
		delete (_options[i]);
}



SelectKeyMenu::SelectKeyMenu(List * menuInfo)
:Menu(menuInfo)
{
	_title = "Select Keys";
	_selectedMax = 8;

	_options.clear();
	_subtitles.clear();
	_subtitles.push_back("    Press Esc to return to previous menu.");
	_subtitles.push_back("");
	_subtitles.push_back("    Select a control, then press space followed by the new key to set a key for that action");

	
	_text[0] = "Up: ";
	_text[1] = "Down/Crouch: ";
	_text[2] = "Left: ";
	_text[3] = "Right: ";
	_text[4] = "Jump: ";
	_text[5] = "Primary Fire: ";
	_text[6] = "Primary Fire: ";
	_text[7] = "Alt Fire: ";
	_text[8] = "Alt Fire: ";

	_keys[0] += (string)SDL_GetKeyName(Control::upKey);
	_keys[1] += (string)SDL_GetKeyName(Control::downKey);
	_keys[2] += (string)SDL_GetKeyName(Control::leftKey);
	_keys[3] += (string)SDL_GetKeyName(Control::rightKey);
	_keys[4] += (string)SDL_GetKeyName(Control::jumpKey);
	_keys[5] += (string)SDL_GetKeyName(Control::shoot1Key);
	_keys[6] += (string)SDL_GetKeyName(Control::shoot2Key);
	_keys[7] += (string)SDL_GetKeyName(Control::altShoot1Key);
	_keys[8] += (string)SDL_GetKeyName(Control::altShoot2Key);


}
void SelectKeyMenu::draw()
{
	

	Menu::draw();
	
	int offset = _textHeight*4;

	for(int i=0; i<9; i++)
	{
		if(_selected == i)
			glfuncs::instance()->glPrint( _leftMargin, offset, "> " + _text[i] + _keys[i], false);
		else
			glfuncs::instance()->glPrint( _leftMargin, offset, "  " + _text[i] + _keys[i], false);
		offset += _textHeight;
	}


}

bool SelectKeyMenu::select()
{
	
	_keys[_selected] = "Press a key";
	
	//HACK
	glfuncs::instance()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	draw();
	glfuncs::instance()->glFinish();
	SDL_GL_SwapBuffers();

	SDL_Event event;
	SDLKey keysym;
	while(true)
	{
		SDL_PollEvent(&event);
		if(event.type == SDL_KEYDOWN) {
			keysym = event.key.keysym.sym;
			break;
		}
	}

	_keys[_selected] = SDL_GetKeyName(keysym);

	switch(_selected)
	{
	case 0:
		Control::upKey = keysym;
		break;
	case 1:
		Control::downKey = keysym;
		break;
	case 2:
		Control::leftKey = keysym;
		break;
	case 3:
		Control::rightKey = keysym;
		break;
	case 4:
		Control::jumpKey = keysym;
		break;
	case 5:
		Control::shoot1Key = keysym;
		break;
	case 6:
		Control::shoot2Key = keysym;
		break;
	case 7:
		Control::altShoot1Key = keysym;
		break;
	case 8:
		Control::altShoot2Key = keysym;
		break;

	}
	return false;
}



NewGameMenu::NewGameMenu(List * menuInfo)
:Menu(menuInfo)
{
	
	_title = "New Game";
	_options.clear();
	_selected = 0;
	_totalLevels = 0;
	_selectedMax = 0;

	_won = false;


	List* levelList = Parser::parse("levels/levellist.txt");
	while( !levelList->empty() )
	{
		_levelFile.push_back( levelList->firstList()->firstString() );
		bool inMenu = levelList->firstList()->rest()->firstInt();
		if(inMenu)
			_selectedMax ++;

		_levelInMenu.push_back(inMenu);
		_levelUnLocked.push_back( levelList->firstList()->rest()->rest()->firstInt() );
		_levelName.push_back( levelList->firstList()->rest()->rest()->rest()->firstString() );

		levelList = levelList->rest();
	}
	_selectedMax --;
	_totalLevels = _levelInMenu.size();
}

void NewGameMenu::draw()
{
	Menu::draw();

	int offset = _textHeight*4;
	int select =0;
	for(int i=0; i <= _totalLevels; i++)
	{
		if(_levelInMenu[i]){
			if(_levelUnLocked[i]){
				if(_selected == select)
					glfuncs::instance()->glPrint( _leftMargin, offset, "> " + _levelName[i], false);
				else
					glfuncs::instance()->glPrint( _leftMargin, offset, "  " + _levelName[i], false);
			}else
			{
				if(_selected == select)
					glfuncs::instance()->glPrint( _leftMargin, offset, "> " + (string)"[Locked]", false);
				else
					glfuncs::instance()->glPrint( _leftMargin, offset, "  " + (string)"[Locked]", false);
			}
			offset += _textHeight;
			select ++;
		}
	}
	
}

 bool NewGameMenu::select()
{
	//_game = Game();

	int i=0;
	int selected = _selected;
	for(i=0; selected > 0 ; i++)
	{
		if(_levelInMenu[i])
			selected --;
	}
	for(;!_levelInMenu[i];i++){}

	if(!_levelUnLocked[i])
		return false;

	Screen::drawLoading();

	_game = new Game(i);

	for(;;)
	{
		if( !_game->mainLoop() )
			break;
		else if( _game->wonLevel())
		{
			//you won, unlock the next level, and increment the "selected" level
			// if the next level is in the menu
			
			_levelUnLocked[++i] = true;
			
			if(_levelInMenu[i])
				_selected++;

			Screen::drawLoading();

			if(!_game->nextLevel())
			{
				_won = true;
				break;
			}
		}
		else
			_game->resetLevel();
	}
	
	//we're leaving the menu, write out the levellist.txt file
	ofstream file("levels/levellist.txt");
	file << Parser::open << endl;
	for(int j=0; j< _totalLevels; j++){

		file << Parser::open;
		file << _levelFile[j] << " " 
			 << _levelInMenu[j] << " " 
			 << _levelUnLocked[j] << " "
			 << "\"" <<_levelName[j] << "\"";
		file << Parser::close << endl;
	}
	file << Parser::close;
	file.close();
	


	delete _game;
	_game = NULL;

	return true;
}

TitleScreenMenu::TitleScreenMenu(List * menuInfo)
:Menu(menuInfo)
{}
bool TitleScreenMenu::select()
{
	_options[0]->mainLoop();
	return true;
}
void TitleScreenMenu::draw()
{
	if(_background)
		_background->draw(0,0,Sprite::SCREEN);
	// Draw Team Scramble logo
	Screen::drawScramble();
}