/*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 "MainMenu.hpp"
#include "Engines/GameEngine.hpp"
#include "Graphics/Window.hpp"
#include "Configuration/Configuration.hpp"
#include "Fight/FightRules.hpp"

#include "Graphics/Drawable/Sprite.hpp"
#include "Graphics/Drawable/Text.hpp"
#include "Engines/Resources/TextureManager.hpp"
#include "Engines/Resources/FontManager.hpp"
#include "Engines/Resources/JoystickManager.hpp"
#include "Engines/Resources/SoundBufferManager.hpp"
#include "Engines/Sound/PlaylistPlayer.hpp"
#include "Engines/Sound/SoundEngine.hpp"
#include "Engines/Sound/SoundEffectsList.hpp"
#include "GUI/PlaylistNotifier.hpp"
#include "Tools/ScaledPixel.hpp"

MainMenu::MainMenu(GameEngine &gameEngine) :
m_gameEngine(&gameEngine), m_window(&(gameEngine.getWindow())),
m_configuration(&(gameEngine.getConfiguration()))
{

}

void MainMenu::run()
{
    const Vector viewSize = m_window->getViewSize();
    const Viewport &viewport = m_window->getViewport();
    const ScaledPixel sp(viewSize.x);

    TextureManager textureManager;
    FontManager fontManager;
    SoundBufferManager soundBufferManager;

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

    Sprite title(textureManager.getTexture("gfx/ui/banner.png"),
                 Box(0.f, 0.f, 1783.f / 2048.f, 295.f / 512.f));
    title.setScale(sp.lower(.4f, 1.f));
    title.setPosition((viewSize.x - title.getWidth() * title.getXScale()) / 2.f,
                      sp(30.f));

    //Menu
    SoundEngine soundEngine;
    soundEngine.setManager(soundBufferManager);
    soundEngine.setVolume(m_configuration->outputSoundVolume());

    const Sprite menu_default(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(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(260.f), sp(70.f), menu_default, menu_hover);
    SkinSound sounds(soundEngine, "audio/ui/menuFocus.ogg",
                     "audio/ui/menuClick.ogg");
    TextButtonSkin menuSkin(fontManager.getDisplay(sp(24)),
                            Color(255, 255, 255), skin, sounds);

    MainMenuTab menu(sp(275.f), sp(420.f), sp(12.f),
                     Color(0, 0, 0, 0), menuSkin);
    menu.setXPosition((viewSize.x - menu.getWidth()) / 10.f);
    menu.setYPosition(title.getYPosition() +
                      title.getHeight() * title.getYScale() +
                      viewSize.y * .08f);

    //Start the playlist if not started
    PlaylistNotifier notifier(viewSize.x);
    notifier.setFonts(fontManager.getDefault(sp(20)),
                      fontManager.getDefault(sp(14)));
    notifier.setPosition(viewSize.x - notifier.getWidth() - sp(20.f),
                         viewSize.y - notifier.getHeight() - sp(20.f));

    PlaylistPlayer::start(&notifier, m_configuration->outputMusicVolume());

    //Start screen loop
    SDL_Event event;
    while (1)
    {
        //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
                    menu.mouseRelease(viewport.project(event.button.x,
                                                       event.button.y));
                break;

                case SDL_MOUSEMOTION: //Mouse moved
                    menu.mouseMove(viewport.project(event.motion.x,
                                                    event.motion.y));
                break;

                case SDL_KEYDOWN:
                    // Escape was pressed, reset the menu to its last state
                    if (event.key.keysym.sym == SDLK_ESCAPE)
                        menu.goBack();
                break;

                default:
                break;
            }
        }

        //Update sounds
        soundEngine.update();
        notifier.update();

        if (menu.hasResult()) //Browsing ended
        {
            processResult(menu.getResult(), menu.getFightRules());
            PlaylistPlayer::setNotifier(nullptr);
            return;
        }

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

            //Draw
        background.draw();
        title.draw();
        menu.draw();

            //Notifier
        notifier.draw();

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

void MainMenu::processResult(MainMenuTab::Result result,
                             const FightRules &fightRules)
{
    if (result == MainMenuTab::Result::LocalGame)
    {
        m_gameEngine->confLocalGame_rules(fightRules);
        m_gameEngine->confCharactersMenu_playersNo(fightRules.getPlayerCount());
        m_gameEngine->initCharactersMenu();
    }
    else if (result == MainMenuTab::Result::Multiplayer)
        m_gameEngine->initNetworkedGame();
    else if (result == MainMenuTab::Result::Options)
        m_gameEngine->initOptions();
    else if (result == MainMenuTab::Result::Exit)
        m_gameEngine->exit();
}
