//////////////////////////////////////////////////////////////////////////////
// This file is part of the Journey MMORPG client                           //
// Copyright © 2015-2016 Daniel Allendorf                                   //
//                                                                          //
// This program is free software: you can redistribute it and/or modify     //
// it under the terms of the GNU Affero General Public License as           //
// published by the Free Software Foundation, either version 3 of the       //
// License, or (at your option) any later version.                          //
//                                                                          //
// 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 Affero General Public License for more details.                      //
//                                                                          //
// You should have received a copy of the GNU Affero General Public License //
// along with this program.  If not, see <http://www.gnu.org/licenses/>.    //
//////////////////////////////////////////////////////////////////////////////
#include "UIWorldSelect.h"
#include "../../Constants.h"

#include "../../Configuration.h"
#include "../../Graphics/Sprite.h"
#include "../../IO/UI.h"
#include "../../IO/Components/MapleButton.h"

#include <string>
#include "../../IO/Components/TwoSpriteButton.h"
#include "../../Net/Packets/LoginPackets.h"

#include "nlnx/nx.hpp"

namespace jrc
{
    UIWorldSelect::UIWorldSelect(std::vector<World> worlds, uint8_t worldcount)
        : UIElement({ 0, 0 }, { 800, 600 }) {
        // The login-stage screens are laid out for an 800x600 canvas.
        // Centre them so a wider viewport does not strand them in a corner.
        position = Point<int16_t>((Constants::VIEWWIDTH - 800) / 2,
                                  (Constants::VIEWHEIGHT - 600) / 2);



        worldid = Setting<DefaultWorld>::get().load();
        channelid = Setting<DefaultChannel>::get().load();

        nl::node back = nl::nx::map["Back"]["login.img"]["back"];
        nl::node wsel = nl::nx::ui["Login.img"]["WorldSelect"];
        nl::node btworld = wsel["BtWorld"];
        nl::node worldsrc = btworld["release"];
        nl::node channelsrc = wsel["BtChannel"];
        nl::node frame = nl::nx::ui["Login.img"]["Common"]["frame"];

        // v83 UI.wz has no WorldSelect/BtChannel at all: the channel buttons live
        // under WorldSelect/channel and the enter button under WorldSelect/BtGoworld.
        // Without this branch the whole screen builds from null nodes and renders
        // nothing, which looks like the client hanging after login.
        const bool legacy_ui = !static_cast<bool>(channelsrc);

        sprites.emplace_back(back["11"], Point<int16_t>(370, 300));
        if (!legacy_ui)
            sprites.emplace_back(worldsrc["layer:bg"], Point<int16_t>(650, 45));
        sprites.emplace_back(frame, Point<int16_t>(400, 290));

        if (legacy_ui)
        {
            // v83 keeps the panel at BtWorld/chBackgrn; v153 moved it up to
            // WorldSelect/chBackgrn. Take whichever this UI.wz actually has.
            nl::node chbg = wsel["chBackgrn"];
            if (!chbg)
            {
                chbg = btworld["chBackgrn"];
            }
            sprites.emplace_back(chbg, Point<int16_t>(400, 300));

            buttons[BT_ENTERWORLD] = std::make_unique<MapleButton>(
                wsel["BtGoworld"], Point<int16_t>(347, 372));

            if (worldcount <= 0)
                return;

            const World& world = worlds.front();

            buttons[BT_WORLD0] = std::make_unique<MapleButton>(
                btworld["0"], Point<int16_t>(228, 208));
            buttons[BT_WORLD0]->set_state(Button::PRESSED);

            if (channelid >= world.channelcount)
                channelid = 0;

            nl::node channels = wsel["channel"];
            for (uint8_t i = 0; i < world.channelcount; ++i)
            {
                nl::node chnode = channels[std::to_string(i)];
                buttons[BT_CHANNEL0 + i] = std::make_unique<TwoSpriteButton>(
                    chnode["normal"], chnode["disabled"],
                    Point<int16_t>(228 + (i % 5) * 96, 268 + (i / 5) * 34));
                if (i == channelid)
                    buttons[BT_CHANNEL0 + i]->set_state(Button::PRESSED);
            }
            return;
        }

        buttons[BT_ENTERWORLD] = std::make_unique<MapleButton>(
            channelsrc["button:GoWorld"],
            Point<int16_t>(200, 170)
            );

        if (worldcount <= 0)
            return;

        const World& world = worlds.front();

        buttons[BT_WORLD0] = std::make_unique<MapleButton>(worldsrc["button:15"], Point<int16_t>(650, 20));
        buttons[BT_WORLD0]->set_state(Button::PRESSED);

        sprites.emplace_back(channelsrc["layer:bg"], Point<int16_t>(200, 170));
        sprites.emplace_back(channelsrc["release"]["layer:15"], Point<int16_t>(200, 170));

        if (channelid >= world.channelcount)
            channelid = 0;

        for (uint8_t i = 0; i < world.channelcount; ++i)
        {
            nl::node chnode = channelsrc["button:" + std::to_string(i)];
            buttons[BT_CHANNEL0 + i] = std::make_unique<TwoSpriteButton>(
                chnode["normal"]["0"], chnode["keyFocused"]["0"],
                Point<int16_t>(200, 170)
                );
            if (i == channelid)
                buttons[BT_CHANNEL0 + i]->set_state(Button::PRESSED);
        }
    }

    void UIWorldSelect::draw(float alpha) const
    {
        UIElement::draw(alpha);
    }

    uint8_t UIWorldSelect::get_world_id() const
    {
        return worldid;
    }

    uint8_t UIWorldSelect::get_channel_id() const
    {
        return channelid;
    }

    Button::State UIWorldSelect::button_pressed(uint16_t id)
    {
        if (id == BT_ENTERWORLD)
        {
            UI::get().disable();

            CharlistRequestPacket(worldid, channelid)
                .dispatch();

            return Button::PRESSED;
        }
        else if (id >= BT_WORLD0 && id < BT_CHANNEL0)
        {
            buttons[BT_WORLD0 + worldid]->set_state(Button::NORMAL);
            worldid = static_cast<uint8_t>(id - BT_WORLD0);
            return Button::PRESSED;
        }
        else
        {
            buttons[BT_CHANNEL0 + channelid]->set_state(Button::NORMAL);
            channelid = static_cast<uint8_t>(id - BT_CHANNEL0);
            return Button::PRESSED;
        }
    }
}
