/*
	Copyright 2014 Michele "King_DuckZ" Santullo

	This file is part of CloonelJump.

	CloonelJump 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, either version 3 of the License, or
	(at your option) any later version.

	CloonelJump 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 CloonelJump.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "gameplaysceneclassic.hpp"
#include "character.hpp"
#include "moversine.hpp"
#include "sdlmain.hpp"
#include "inputbag.hpp"
#include "key.hpp"
#include "moverleftright.hpp"
#include "moverworld.hpp"
#include "tiledwallpaper.hpp"
#include "texture.hpp"
#include "platformsystem.hpp"
#include "CloonelJumpConfig.h"
#include <algorithm>
#include <SDL2/SDL_scancode.h>
#include <ciso646>

namespace cloonel {
	namespace {
		enum GameActionType {
			GameAction_Left,
			GameAction_Right
		};
	} //unnamed namespace

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	GameplaySceneClassic::GameplaySceneClassic (SDLMain* parSdlMain) :
		GameplayScene(parSdlMain)
	{
		//TODO: replace the hardcoded bindings with something more customizable.
		InputBag& input = *InputBagObject();
		input.AddAction(GameAction_Left, Key(InputDevice_Keyboard, SDL_SCANCODE_LEFT), "Move left");
		input.AddAction(GameAction_Right, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right");
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	GameplaySceneClassic::~GameplaySceneClassic() noexcept {
		Destroy();
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	void GameplaySceneClassic::Prepare() {
		const float halfRefHeight = static_cast<float>(REFERENCE_HEIGHT) / 2.0f;

		std::unique_ptr<MoverSine> moverSine(new MoverSine());
		std::unique_ptr<Character> player(new Character("resources/graphics/player.png", SDLObject(), float2(80.0f, 120.0f)));
		std::unique_ptr<MoverLeftRight> moverLeftRight(new MoverLeftRight(1.5f, 5.0f, 40.0f));
		std::unique_ptr<MoverWorld> moverWorld(new MoverWorld(halfRefHeight));
		std::unique_ptr<TiledWallpaper> wallpaper(new TiledWallpaper("resources/graphics/background_tile.png", SDLObject()));
		std::unique_ptr<PlatformSystem> platforms(new PlatformSystem("resources/graphics/platform.png", SDLObject(), this, halfRefHeight * 0.9f));

		player->Prepare();
		platforms->Prepare();
		moverSine->RegisterPlaceable(player.get());
		moverSine->RegisterPlaceable(moverWorld.get()); //Keep an invisible mover
		moverLeftRight->RegisterPlaceable(player.get());
		moverWorld->RegisterPlaceable(player.get()); //It compensates the position when the chara goes over the mid
		moverWorld->RegisterPlaceable(moverWorld.get()); //The mover has to be in sync with the character
		moverWorld->RegisterPlaceable(platforms.get());
		wallpaper->Reload();

		std::swap(moverSine, m_moverSine);
		std::swap(player, m_player);
		std::swap(moverLeftRight, m_moverLeftRight);
		std::swap(moverWorld, m_moverWorld);
		std::swap(wallpaper, m_wallpaper);
		std::swap(platforms, m_platforms);

		AddMover(m_moverSine.get());
		AddMover(m_moverLeftRight.get());
		AddDrawable(m_wallpaper.get());
		AddMover(m_moverWorld.get());
		m_platforms->AddDrawables();
		AddDrawable(m_player.get());

		const float jumpPower = halfRefHeight * 1.29f;
		m_moverSine->SetPower(jumpPower);
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	void GameplaySceneClassic::Destroy() noexcept {
		//Destroy in reverse creation order
		m_platforms = std::move(std::unique_ptr<PlatformSystem>(nullptr));
		m_wallpaper = std::move(std::unique_ptr<TiledWallpaper>(nullptr));
		m_moverWorld = std::move(std::unique_ptr<MoverWorld>(nullptr));
		m_moverLeftRight = std::move(std::unique_ptr<MoverLeftRight>(nullptr));
		m_player = std::move(std::unique_ptr<Character>(nullptr));
		m_moverSine = std::move(std::unique_ptr<MoverSine>(nullptr));
	}

	///--------------------------------------------------------------------------
	///--------------------------------------------------------------------------
	void GameplaySceneClassic::OnPreUpdate() {
		InputBag& input = *InputBagObject();
		if (IsPressed(input, GameAction_Left)) {
			m_moverLeftRight->SetMovement(MoverLeftRight::MovementDirection_Left);
		}
		else if (IsPressed(input, GameAction_Right)) {
			m_moverLeftRight->SetMovement(MoverLeftRight::MovementDirection_Right);
		}
		else {
			m_moverLeftRight->SetMovement(MoverLeftRight::MovementDirection_Still);
		}

		m_platforms->SpawnPlatforms();
	}
} //namespace cloonel
