/**
 *  Triangles
 *  Copyright (C) 2016 POSITIVE MENTAL ATTITUDE
 *
 *  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, version 3 of the License.
 *
 *  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 <string>
#include <fstream>
#include <sstream>
#include "MenuState.hpp"
#include "Triangles.hpp"
#include "Utility.hpp"

MenuState::MenuState(): State(), _padSelection(0) {}

void MenuState::init()
{
	for(unsigned int i = 0; i < 30; ++i)
	{
		//_crazyTriangles[i].setColor(50, rand() % 50 + 125, rand() % 50 + 200, rand() % 150 + 105);
		_crazyColors[i][3] = rand() % 150 + 105;
		_crazyTriangles[i].setSize(rand() % 384 + (rand() % 20 == 0 ? 900 : 300));
		_crazyTriangles[i].setRotation(rand() % 360);
	}

	std::ifstream ifs("data/credits.txt");
	std::ostringstream oss;
	oss << ifs.rdbuf();
				
	_credits.setString(sf::String(oss.str()));
	_credits.setFont(_context->assets->loadFont("data/ttf/canonical/Ubuntu-L.ttf"));
	_credits.setColor(sf::Color::Black);
	
	_music.openFromFile("data/audio/Past the Edge.ogg");
	_music.play();
	
	_waterSine.loadFromFile("data/shaders/water.vs", sf::Shader::Fragment);
	_waterMap.create(1920, 1080);

	_waterFrag.loadFromFile("data/shaders/water.frag", sf::Shader::Fragment);
	_waterFrag.setParameter("heightmap", _waterMap.getTexture());
	
	_subStatus = Main;
	
	_logo.bind([this]()
	{
		_subStatus = Credits;
		_quit.setTexture(_context->assets->loadTexture("data/menu/Back.png"));
	});
	_logo.setRotation(97.5f);
	_logo.setTexture(_context->assets->loadTexture("data/menu/Logo.png"));
	
	_play.bind([this]()
	{
		_status = State::Ingame;
	});
	_play.setRotation(80.f);
	_play.setTexture(_context->assets->loadTexture("data/menu/Play.png"));
	
	_settings.bind([this]()
	{ 
		_subStatus = Settings;
		_quit.setTexture(_context->assets->loadTexture("data/menu/Back.png"));
	});
	_settings.setRotation(260.f);
	_settings.setTexture(_context->assets->loadTexture("data/menu/Settings.png"));
	
	_quit.bind([this]()
	{
		switch(_subStatus)
		{
			case Main:
				_context->running = false;
				break;
			case Settings:
				_context->window->recreate();
				// move on
			default:
				_quit.setTexture(_context->assets->loadTexture("data/menu/Quit.png"));
				_subStatus = Main;
		}
	});
	_quit.setRotation(100.f);
	_quit.setTexture(_context->assets->loadTexture("data/menu/Quit.png"));
	
	_status = State::Ongoing;
}

void MenuState::refresh()
{
	_crazy.create(_context->window->getSize().x, _context->window->getSize().y);
	
	for(unsigned int i = 0; i < 30; ++i)
	{
		for(unsigned int j = 0; j < 3; ++j)
			_crazyColors[i][j] = rand() % 50 - 25;
		_crazyTriangles[i].setPosition(rand() % _context->window->getSize().x, rand() % _context->window->getSize().y);
	}
		
	float u = 1.f; // GUI size essentially; halves when screen size drops below 1024x768.
	if(_context->window->getSize().x < 1024)
		u = 0.5f;
	
	/*
	 * SETTINGS
	 */
	_shaders.create(_context->assets->loadFont("data/ttf/canonical/Ubuntu-L.ttf"), "Shaders", &_context->shaders);
	_shaders.setSize(250.f * u);
	_shaders.setPosition(_context->window->getSize().x / 2.f + 250.f * u, 
						 _context->window->getSize().y / 2.f - 200.f * u);
	_shaders.setCharacterSize(40 * u);
	
	_fullscreen.create(_context->assets->loadFont("data/ttf/canonical/Ubuntu-L.ttf"), "Fullscreen", &_context->fullscreen);
	_fullscreen.flip(true);
	_fullscreen.setSize(250.f * u);
	_fullscreen.setPosition(_context->window->getSize().x / 2.f - 250.f * u, 
						 _context->window->getSize().y / 2.f - 200.f * u);
	_fullscreen.setCharacterSize(40 * u);
	
	/*
	 * CREDITS
	 */
	_credits.setCharacterSize(32.f * u);
	_credits.setPosition(_context->window->getSize().x / 2.f - _credits.getLocalBounds().width / 2.f, _context->window->getSize().y / 2.f - _credits.getLocalBounds().height / 2.f);

	/*
	 * MAIN MENU
	 */
	_logo.setSize(325.f * u);
	_play.setSize(225.f * u);
	_settings.setSize(225.f * u);
	_quit.setSize(175.f * u);
	_logo.setPosition(_context->window->getSize().x / 2.f - 110.f * u, _context->window->getSize().y / 2.f - 200.f * u);
	_play.setPosition(_context->window->getSize().x / 2.f + 260.f * u, _context->window->getSize().y / 2.f - 60.f * u);
	_settings.setPosition(_context->window->getSize().x / 2.f - 260.f * u, _context->window->getSize().y / 2.f + 30.f * u);
	_quit.setPosition(_context->window->getSize().x / 2.f + 260.f * u, _context->window->getSize().y / 2.f + 260.f * u);
}

void MenuState::coreThink(const sf::Event& event)
{
	if(event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left)
	{
		sf::Vector2i xy = _context->window->getMousePosition();
		switch(_subStatus)
		{
			case Main:
				_logo.click(xy);
				_play.click(xy);
				_settings.click(xy);
				break;
			case Settings:
				_shaders.click(xy);
				_fullscreen.click(xy);
				break;
			case Credits:
				break;
		}
		
		_quit.click(xy);
	}
	
	if(event.type == sf::Event::Closed || (event.type == sf::Event::KeyPressed and event.key.code == sf::Keyboard::Escape))
		_context->running = false;
	if(event.type == sf::Event::JoystickMoved && event.joystickMove.axis == sf::Joystick::Axis::PovX)
	{
		if(event.joystickMove.position == -100)
			switch(_padSelection)
			{
				case 1: _padSelection = 2; break;
				default: break;
			}
		if(event.joystickMove.position == 100)
			switch(_padSelection)
			{
				case 0: _padSelection = 1; break;
				case 2: _padSelection = 1; break; 
				default: break;
			}
	}
	if(event.type == sf::Event::JoystickMoved && event.joystickMove.axis == sf::Joystick::Axis::PovY)
	{
		if(event.joystickMove.position == -100)
			switch(_padSelection)
			{
				case 1: _padSelection = 0; break;
				case 2: _padSelection = 0; break;
				case 3: _padSelection = 1; break;
				default: break;
			}
		if(event.joystickMove.position == 100)
			switch(_padSelection)
			{
				case 0: _padSelection = 2; break;
				case 1: _padSelection = 3; break;
				case 2: _padSelection = 3; break;
				default: break;
			}
	}
}
void MenuState::coreInput()
{

}
void MenuState::coreUpdate(sf::Time delta)
{
	float seconds = delta.asSeconds();
	
	{
		static float r = rand() % 256, g = rand() % 256, b = rand() % 256;
		static int rInc = 1, gInc = 1, bInc = 1;
		r += (rand() % 40) * seconds * rInc;
		g += (rand() % 30) * seconds * gInc;
		b += (rand() % 20) * seconds * bInc;
		if(r >= 225.f)
		{
			r = 225.f;
			rInc = -1;
		}
		if(g >= 225.f)
		{
			g = 225.f;
			gInc = -1;
		}
		if(b >= 225.f)
		{
			b = 225.f;
			bInc = -1;
		}
		if(r <= 60)
		{
			r = 60;
			rInc = 1;
		}
		if(g <= 60)
		{
			g = 60;
			gInc = 1;
		}
		if(b <= 60)
		{
			b = 60;
			bInc = 1;
		}
		_color = sf::Color(r, g, b);
		_logo.setColor(_color);
		_quit.setColor(_color);
		_settings.setColor(_color);
		_play.setColor(_color);
		_shaders.setColor(_color);
		_fullscreen.setColor(_color);
		for(unsigned i = 0; i < 30; ++i)
			_crazyTriangles[i].setColor(sf::Color(r + _crazyColors[i][0] , g + _crazyColors[i][1], b + _crazyColors[i][2], _crazyColors[i][3]));
	}
	
	static bool ongoing = false;
	static int k = -1;
	static float d = 0;
	static float direction = 0.f;
	static float speed = 0.f;
	static float r = 0;

	if(!ongoing)
	{
		r = rand() % 2 + 1.f;
		k = rand() % 30;
		ongoing = true;
		rand() % 2 == 0 ? direction = 1.f : direction = -1.f;
		speed = 0.1f;
	}
	if(k != -1)
	{
		float x = delta.asSeconds() * 60.f * speed * direction;
		_crazyTriangles[k].rotate(x);
		d += delta.asSeconds();
		2 * d < r ? speed += delta.asSeconds() * 3.5f : speed -= delta.asSeconds() * 3.5f;
		if(d > r)
		{
			k = -1;
			ongoing = false;
			d = 0;
		}
	}
	
	static sf::Clock clock;
	_waterSine.setParameter("time", clock.getElapsedTime().asSeconds());
	
	if(sf::Joystick::isConnected(0))
	{
		sf::Vector2f v;
		switch(_padSelection)
		{
			case 0:
				v = _logo.getPosition();
				break;
			case 1:
				v = _play.getPosition();
				break;
			case 2:
				v = _settings.getPosition();
				break;
			case 3:
				v = _quit.getPosition();
				break;
				
		}
		_context->window->lockMouse(sf::Vector2i(v));
	}
	
	_logo.update(_context->window->getMousePosition(), delta);
	_play.update(_context->window->getMousePosition(), delta);
	_settings.update(_context->window->getMousePosition(), delta);
	_quit.update(_context->window->getMousePosition(), delta);
}

void MenuState::coreRender(const bool shaders)
{
	//_crazy.clear(sf::Color(100, 150, 220));
	_crazy.clear(_color);
	for(unsigned int i = 0; i < 30; ++i)
		_crazy.draw(_crazyTriangles[i]);
	sf::Sprite crazy(_crazy.getTexture());

	_waterMap.clear();
	sf::RectangleShape rect(sf::Vector2f(1920.f, 1080.f));
	if(shaders)
		_waterMap.draw(rect, &_waterSine);
	else
		_waterMap.draw(rect);
	_waterMap.display();

	if(shaders)
		_context->window->draw(crazy, &_waterFrag);
	else
		_context->window->draw(crazy);
		
	switch(_subStatus)
	{
		case Main:
			_context->window->draw(_logo);
			_context->window->draw(_play);
			_context->window->draw(_settings);
			break;
		case Settings:
			_context->window->draw(_shaders);
			_context->window->draw(_fullscreen);
			break;
		case Credits:
			_context->window->draw(_credits);
			break;
	}
	_context->window->draw(_quit);
}