/*Copyright (C) 2010-2023 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu 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.

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

#include "CharactersMenu.hpp"
#include "Engines/GameEngine.hpp"
#include "Graphics/Window.hpp"
#include "Configuration/Configuration.hpp"

#include "CharacterChooser.hpp"
#include "Graphics/Drawable/Sprite.hpp"
#include "Engines/Resources/JoystickManager.hpp"
#include "Engines/Sound/PlaylistPlayer.hpp"
#include "Engines/Sound/SoundEngine.hpp"
#include "GUI/SectionHeader.hpp"
#include "GUI/PlaylistNotifier.hpp"
#include "Tools/ScaledPixel.hpp"
#include "Tools/Timer.hpp"
#include "Tools/I18n.hpp" ///< _ macro for i18n
#include <sstream>

CharactersMenu::CharactersMenu(GameEngine &gameEngine) : m_selectionIx(0),
m_gameEngine(&gameEngine), m_window(&(gameEngine.getWindow())),
m_configuration(&(gameEngine.getConfiguration())), m_playersNo(2)
{

}

void CharactersMenu::characterSelected()
{
    if (m_selectionIx < m_playersNo &&
        m_selectionPreview.readyCharacter(m_selectionIx))
        m_selectionIx++;
}

void CharactersMenu::characterFocused(const Character &character)
{
    m_selectionPreview.setCharacter(m_selectionIx, character, m_textureManager);
}

void CharactersMenu::cleanPreview()
{
    m_selectionIx = 0;

    /// Character selection preview
    const Vector viewSize = m_window->getViewSize();

    m_selectionPreview = CharacterSelectionPanel(
        m_fontManager.getDisplay(ScaledPixel{viewSize.x}(24)),
        m_playersNo, viewSize.x);

    m_selectionPreview.setPosition(
        (viewSize.x - m_selectionPreview.getWidth()) / 2.f,
        viewSize.y * .45f);
}


void CharactersMenu::setPlayersNo(std::size_t playersNo)
{
    m_playersNo = playersNo;
}

//Screen virtual method
void CharactersMenu::run()
{
    cleanPreview();

    const Vector viewSize = m_window->getViewSize();
    const Viewport &viewport = m_window->getViewport();
    const ScaledPixel sp(viewSize.x);

    SoundEngine soundEngine;
    soundEngine.setManager(m_soundBufferManager);
    soundEngine.setVolume(m_configuration->outputSoundVolume());

    //Background + Header
    Sprite background(m_textureManager.getTexture("gfx/ui/nikko.png"),
                      Box(0.f, 0.f, 1920.f / 2048.f, 1080.f / 2048.f));
    background.setScale(viewSize.x / background.getWidth(),
                        viewSize.y / background.getHeight());

    SectionHeader header(_(CharacterSelectionTitle),
                         _(CharacterSelectionSubtitle),
                         m_textureManager, m_fontManager,
                         soundEngine, viewSize);
    //Menu
    const Sprite menu_default(m_textureManager.getTexture("gfx/ui/ui.png"),
        Box(266.f / 512.f, 0.f, 246.f / 512.f, 71.f / 512.f));
    const Sprite menu_hover(m_textureManager.getTexture("gfx/ui/ui.png"),
        Box(266.f / 512.f, 75.f / 512.f, 246.f / 512.f, 71.f / 512.f));

    SkinBox skin(sp(225.f), sp(60.f), menu_default, menu_hover);
    SkinSound sounds(soundEngine, "audio/ui/menuFocus.ogg",
                     "audio/ui/menuClick.ogg");

    CharacterChooser chooser(m_fontManager.getDisplay(sp(24)),
                             skin, sounds, sp(5.f));
    chooser.setPosition((viewSize.x - chooser.getWidth()) / 2.f,
                        viewSize.x * .1255f);

    chooser.initialize((*this));

    //Playlist handling
    PlaylistNotifier notifier(viewSize.x);
    notifier.setFonts(m_fontManager.getDefault(sp(20)),
                      m_fontManager.getDefault(sp(14)));
    notifier.setPosition(viewSize.x - notifier.getWidth() - sp(20.f),
                         viewSize.y - notifier.getHeight() - sp(20.f));

    PlaylistPlayer::setNotifier(&notifier);

    //Start screen loop
    Timer time;
    SDL_Event event;
    while (1)
    {
        //Manage time
        float frameTime = time.getElapsed();
        time.reset();

        //Manage events
        while (m_window->pollEvent(event))
        {
            switch (event.type)
            {
                case SDL_QUIT: //Application closed
                    m_gameEngine->exit();
                    PlaylistPlayer::setNotifier(nullptr);
                    return;
                break;

                case SDL_WINDOWEVENT:
                    if (event.window.event == SDL_WINDOWEVENT_RESIZED)
                        m_window->resizeView();
                break;

                case SDL_JOYDEVICEADDED:
                    m_gameEngine->getJoystickManager()
                                 .loadJoystick(event.jdevice.which);
                break;

                case SDL_JOYDEVICEREMOVED:
                    m_gameEngine->getJoystickManager()
                                 .removeJoystick(event.jdevice.which);
                    m_configuration->updatePlayerDevices(event.jdevice.which);
                break;

                case SDL_MOUSEBUTTONUP: //Mouse released
                {
                    const Vector mouseCoords = viewport.project(event.button.x,
                                                                event.button.y);
                    if (header.backRelease(mouseCoords))
                    {
                        m_gameEngine->initMainMenu();
                        PlaylistPlayer::setNotifier(nullptr);
                        return;
                    }

                    chooser.mouseRelease(mouseCoords);
                    chooser.mouseMove(mouseCoords); //Update the panel with
                                                    //the new selection
                }
                break;

                case SDL_MOUSEMOTION: //Mouse moved
                {
                    const Vector mouseCoords = viewport.project(event.button.x,
                                                                event.button.y);
                    header.backMove(mouseCoords);
                    chooser.mouseMove(mouseCoords);
                }
                break;

                case SDL_KEYDOWN:
                    //Escape was pressed, undo last character selection
                    //if possible, or quit
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                    {
                        if (m_selectionIx == 0) //Back to the main menu
                        {
                            m_gameEngine->initMainMenu();
                            PlaylistPlayer::setNotifier(nullptr);
                            return;
                        }
                        else if (m_selectionIx < m_playersNo)
                        {
                            m_selectionPreview.resetCharacter(m_selectionIx);
                            m_selectionPreview.unreadyCharacter(--m_selectionIx);
                        }
                    }

                break;

                default:
                break;
            }
        }

        soundEngine.update();
        notifier.update();
        m_selectionPreview.update(frameTime);

        if (m_selectionIx == m_playersNo) //Selection ended
        {
            std::vector<Character> selectedPlayers;
            selectedPlayers.reserve(m_selectionPreview.getSize());

            for (std::size_t i = 0; i < m_selectionPreview.getSize(); i++)
                selectedPlayers.push_back(m_selectionPreview.getCharacter(i));

            m_gameEngine->confLocalGame_players(selectedPlayers);
            m_gameEngine->initArenaMenu();

            PlaylistPlayer::setNotifier(nullptr);
            return;
        }

        //Display
            //Clear
        m_window->clear();

            //Draw
        background.draw();
        header.draw();

        m_selectionPreview.draw();
        chooser.draw();

            //Playlist notifier
        notifier.draw();

            //Render
        m_window->flush();
    }
}
