#include <Display/WidgetDisplay/WorldDisplay/WorldDisplay.hpp>
#include <Item/IEquipment.hpp>
#include <Widget/Builder/Builder.hpp>
#include <Widget/Button/Button.hpp>
#include <Widget/IconLabel/IconLabel.hpp>
#include <Widget/Label/Label.hpp>
#include <Widget/Layout/Center/Center.hpp>
#include <Widget/Layout/Column/Column.hpp>
#include <Widget/Layout/CompoundWidget/CompoundWidget.hpp>
#include <Widget/Layout/CompoundWidget/Deck/Deck.hpp>
#include <Widget/Layout/CompoundWidget/ListView/ListView.hpp>
#include <Widget/Layout/CompoundWidget/MapMenu/MapMenu.hpp>
#include <Widget/Layout/CompoundWidget/MapToolBox/MapToolBox.hpp>
#include <Widget/Layout/Frame/Frame.hpp>
#include <Widget/Layout/Margin/Margin.hpp>
#include <Widget/Layout/Row/Row.hpp>
#include <Widget/Layout/ScrollPanel/ScrollPanel.hpp>
#include <Widget/MapView/MapView.hpp>
#include <Widget/Panel/Panel.hpp>
#include <Widget/Switch/Switch.hpp>
#include <Widget/TabList/TabList.hpp>

Material& MapMenu::getLevelIcon(IEquipment::MapLevel level)
{
    switch (level)
    {
        case IEquipment::MapLevel::None:                return Material::alert;
        case IEquipment::MapLevel::CarvedMap:           return Material::carvedMap;
        case IEquipment::MapLevel::PaperMap:            return Material::paperMap;
        case IEquipment::MapLevel::Cheat:               return Material::cheatMap;
    }
}

Widget* MapMenu::makePinRow(size_t index)
{
    return new Deck<Row, Center>(
        new Switch(
            player.mapPins[index].switchedOn,
            [this, index](bool value)
            {
                remoteMap.setPinSwitch(index, value);
            }
        ),
        new Margin<0, 2>(
            new IconLabel(Material::mapPin)
        ),
        new Builder<std::string>(
            [this, index]()
            {
                return player.mapPins[index].label;
            },
            [](std::string label) -> Widget*
            {
                return new Label(label);
            }
        ),

        Layout::WithProportion<1>(),
        new Panel(),

        (new Button("", [this, index](){ remoteMap.deletePin(index); }))
            ->withIcon(Material::trash)
            ->withFaceColor(Color::danger)
            ->withToolTip("Delete pin")
    );
}

TabList::Page* MapMenu::makePinsPage(IEquipment::MapLevel level)
{
    if (level < IEquipment::MapLevel::PaperMap)
    {
        return nullptr;
    }

    return new TabList::Page(
        Material::mapPin,
        "Pins",
        new ScrollPanel(
            300,
            new Builder<size_t>(
                [this]() { return player.mapPins.size(); },
                [this](size_t) -> Widget *
                {
                    std::vector<Widget*> rows;

                    for (size_t i = 0; i < player.mapPins.size(); i++)
                    {
                        rows.push_back(makePinRow(i));
                    }

                    return new ListView(rows);
                }
            )
        )
    );
}

MapMenu::MapMenu(
    WorldDisplay &worldDisplay,
    IEquipment::MapLevel level,
    RemoteMap &remoteMap
) : remoteMap(remoteMap),
    player(*worldDisplay.getPlayer())
{
    addChildren(
        new Column(
            Layout::WithProportion<1>(),
            new Panel(),

            Layout::WithProportion<8>(),
            new Row(
                Layout::WithProportion<1>(),
                new Panel(),

                Layout::WithProportion<5>(),
                new Frame(
                    new Column(
                        new Deck<Row, Center>(
                            (new Button("<<", [&worldDisplay](){ worldDisplay.requestGuiClose(); }))
                                ->withFaceColor(Color::back),
                            new Label("Map")
                        ),

                        Layout::WithProportion<1>(),
                        new TabList(
                            "/map/tab-list",
                            new TabList::Page(
                                getLevelIcon(level),
                                "Map",
                                new Row(
                                    new Margin<0, 2>(
                                        new Deck<Column, Margin<0, 0, 2, 0>>(
                                            new MapToolBox(tool, level)
                                        )
                                    ),

                                    Layout::WithProportion<1>(),
                                    new MapView(worldDisplay, remoteMap, *worldDisplay.getPlayer(), tool)
                                )
                            ),

                            makePinsPage(level)
                        )
                    )
                ),

                Layout::WithProportion<1>(),
                new Panel()
            ),

            Layout::WithProportion<1>(),
            new Panel()
        )
    );
}