#include "Game.h"

#include <AsynchronCall.h>
#include <Bildschirm.h>
#include <DateiSystem.h>

#include "Globals.h"
#include "Initialisierung.h"
#include "ItemBar.h"
#include "StatusBars.h"

Game::Game(Bildschirm* zScreen)
    : Menu(zScreen),
      recipieVisible(0)
{
    inventoryDragController = new DragController<InventoryDragSource, int>();
    logout = initKnopf(10, 10, 200, 20, Knopf::Style::Normal, "Verlassen");
    logout->setMausEreignis([this, zScreen](void* p, void* o, MausEreignis me) {
        if (me.id == ME_RLinks)
        {
            logout->removeStyle(Knopf::Style::Erlaubt);
            zScreen->postAction([this, zScreen]() {
                World::INSTANCE->zClient()->leaveGame();
                logout->addStyle(Knopf::Style::Erlaubt);
            });
        }
        return 1;
    });
    elements.add(logout);
    debug = initTextFeld(10,
        40,
        500,
        250,
        TextFeld::Style::Text | TextFeld::Style::Mehrzeilig,
        "");
    elements.add(debug);
    guiView = new UIMLView("<v/>", uiFactory);
    guiView->addKnownElement(new ItemBarElement());
    guiView->addKnownElement(new StatusBarsElement());
    guiView->setStyle(UIMLView::Style::Sichtbar);
    guiView->setSize(window->zBildschirm()->getBackBufferSize());
    elements.add(guiView);
    targetUIMLView = new UIMLView("<v/>", uiFactory);
    targetUIMLView->setStyle(
        UIMLView::Style::Hintergrund | UIMLView::Style::HAlpha);
    targetUIMLView->setHintergrundFarbe(0xA0000000);
    elements.add(targetUIMLView);

    filter = initTextFeld(zScreen->getBackBufferSize().x / 2 - 200,
        zScreen->getBackBufferSize().y - 200,
        400,
        20,
        Framework::TextFeld::Style::TextFeld,
        "");
    itemListContainer = new ItemListContainer();
    window->zBildschirm()->addMember(
        dynamic_cast<Zeichnung*>(itemListContainer->getThis()));

    chat = new Chat();
    elements.add(chat);

    LTDBDatei iconsDat;
    iconsDat.setDatei(new Text("data/bilder/gui_icons.ltdb"));
    iconsDat.leseDaten(0);

    chatButton = uiFactory.createKnopf(uiFactory.initParam);
    chatButton->setToolTipText("Chat", zScreen, uiFactory.initParam.schrift);
    chatButton->setAlphaFeldFarbe(0x5F337AB7);
    chatButton->setSize(40, 40);
    chatButton->setPosition(5, zScreen->getBackBufferSize().y - 45);
    chatButton->addStyle(Framework::Knopf::Style::HBild
                         | Framework::Knopf::Style::HAlpha
                         | Framework::Knopf::Style::Hintergrund);
    chatButton->setHintergrundBildZ(iconsDat.laden(0, new Text("chat.png")));
    chatButton->setMausEreignis(
        [this](void* p, void* o, Framework::MausEreignis me) {
            if (me.id == ME_RLinks)
            {
                chat->addStyle(Fenster::Style::Sichtbar);
                chatButton->removeStyle(Knopf::Style::Sichtbar);
            }
            return 1;
        });
    elements.add(chatButton);

    mapWindow = new MapWindow();
    elements.add(mapWindow);
}

Game::~Game()
{
    inventoryDragController->release();
    filter->release();
    itemListContainer->release();
}

void Game::updatePosition(
    Vec3<float> position, bool target, Vec3<int> targetPos)
{
    Text txt = "Position: (";
    txt.setPrecision(2);
    txt += position.x;
    txt += ", ";
    txt += position.y;
    txt += ", ";
    txt += position.z;
    txt += ")";
    if (target)
    {
        txt += "\nTarget: (";
        txt += targetPos.x;
        txt += ", ";
        txt += targetPos.y;
        txt += ", ";
        txt += targetPos.z;
        txt += ")\n";
        Block* b = World::INSTANCE->zBlockAt(targetPos);
        if (b)
        {
            txt += "TargetLight: \n";
            txt += b->printLightInfo();
        }
    }
    debug->setText(txt);
}

void Game::api(char* data)
{
    switch (data[0])
    {
    case 0: // open dialog
        {
            bool exists = 0;
            short len = *(short*)(data + 1);
            char* dialogName = new char[len + 1];
            memcpy(dialogName, data + 3, len);
            dialogName[len] = 0;
            for (UIMLDialog* dialog : dialogs)
            {
                if (dialog->getName().istGleich(dialogName))
                {
                    exists = 1;
                    break;
                }
            }
            delete[] dialogName;
            if (!exists)
            {
                int uimlLen = *(int*)(data + 3 + len);
                char* uiml = new char[uimlLen + 1];
                memcpy(uiml, data + 7 + len, uimlLen);
                uiml[uimlLen] = 0;
                UIMLDialog* dialog
                    = new UIMLDialog(uiml, [this](UIMLDialog* dialog) {
                          window->zBildschirm()->postAction([this, dialog]() {
                              int index = 0;
                              for (UIMLDialog* d : dialogs)
                              {
                                  if (d == dialog)
                                  {
                                      window->zBildschirm()->removeMember(d);
                                      dialogs.remove(index);
                                      World::INSTANCE->zKamera()
                                          ->setControlEnabled(
                                              dialogs.getEintragAnzahl() == 0);
                                      updateRecipieVisibility();
                                      break;
                                  }
                                  index++;
                              }
                          });
                      });
                dialogs.add(dialog);
                updateRecipieVisibility();
                World::INSTANCE->zKamera()->setControlEnabled(0);
                window->zBildschirm()->addMember(dialog);
                delete[] uiml;
            }
            break;
        }
    case 1:
        { // element message
            for (UIMLDialog* dialog : dialogs)
            {
                dialog->api(data + 1);
            }
            short idLen = *(short*)(data + 1);
            char* id = new char[idLen + 1];
            memcpy(id, data + 3, idLen);
            id[idLen] = 0;
            NetworkAPIProcessor* processor = dynamic_cast<NetworkAPIProcessor*>(
                guiView->zZeichnungById(id));
            if (processor) processor->api(data + 3 + idLen);
            delete[] id;
            break;
        }
    case 2:
        { // set gui
            int uimlLen = *(int*)(data + 1);
            char* uiml = new char[uimlLen + 1];
            memcpy(uiml, data + 5, uimlLen);
            uiml[uimlLen] = 0;
            guiView->setUIML(uiml);
            guiView->layout();
            delete[] uiml;
        }
    }
}

void Game::closeCurrentDialog()
{
    if (dialogs.getEintragAnzahl() > 0)
    {
        UIMLDialog* d = dialogs.get(dialogs.getEintragAnzahl() - 1);
        d->close();
    }
}

DragController<InventoryDragSource, int>* Game::zInventoryDragController()
{
    return inventoryDragController;
}

void Game::setTargetUIML(Framework::Text uiml)
{
    if (uiml.getLength())
    {
        window->zBildschirm()->lock();
        targetUIMLView->setUIML(uiml);
        targetUIMLView->layout();
        window->zBildschirm()->unlock();
        targetUIMLView->setSize(targetUIMLView->calculateContentSize());
        targetUIMLView->setPosition(
            window->zBildschirm()->zGraphicsApi()->getBackBufferSize()
            - targetUIMLView->getSize());
        targetUIMLView->addStyle(UIMLView::Style::Sichtbar);
    }
    else
    {
        targetUIMLView->removeStyle(UIMLView::Style::Sichtbar);
    }
}

void Game::updateRecipieVisibility()
{
    if (!recipieVisible)
    {
        if (dialogs.getEintragAnzahl() > 0)
        {
            recipieVisible = 1;
            window->zBildschirm()->addMember(
                dynamic_cast<Zeichnung*>(filter->getThis()));
        }
    }
    else
    {
        if (dialogs.getEintragAnzahl() == 0)
        {
            recipieVisible = 0;
            window->zBildschirm()->removeMember(filter);
            itemListContainer->removeStyle(Fenster::Style::Sichtbar);
        }
    }
}

void Game::showItemList()
{
    itemListContainer->addStyle(Fenster::Style::Sichtbar);
}

bool Game::isItemListVisible()
{
    return itemListContainer->hatStyle(Fenster::Style::Sichtbar);
}

const Text* Game::zFilterText()
{
    return filter->zText();
}

void Game::makeChatButtonVisible()
{
    chatButton->addStyle(Knopf::Style::Sichtbar);
}

Chat* Game::zChat() const
{
    return chat;
}

MapWindow* Game::zMap() const
{
    return mapWindow;
}