#include "Game.h"

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

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

Game::Game(Bildschirm* zScreen)
    : Menu(zScreen)
{
    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);
            new AsynchronCall([this, zScreen]() {
                // TODO
                /*if (World::INSTANCE->zClient()->leaveGame())
                {
                    World::INSTANCE->release();
                    World::INSTANCE = 0;
                    zScreen->lock();
                    hide();
                    menuRegister->get("directConnect")->show();
                    zScreen->unlock();
                }*/
                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);
}

Game::~Game()
{
    inventoryDragController->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) {
                          logout->postAction([this, dialog]() {
                              int index = 0;
                              for (UIMLDialog* d : dialogs)
                              {
                                  if (d == dialog)
                                  {
                                      dialogs.remove(index);
                                      window->zBildschirm()->removeMember(d);
                                      World::INSTANCE->zKamera()
                                          ->setControlEnabled(
                                              dialogs.getEintragAnzahl() == 0);
                                      break;
                                  }
                                  index++;
                              }
                          });
                      });
                dialogs.add(dialog);
                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);
        window->zBildschirm()->removeMember(d);
        dialogs.remove(dialogs.getEintragAnzahl() - 1);
        World::INSTANCE->zKamera()->setControlEnabled(
            dialogs.getEintragAnzahl() == 0);
    }
}

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);
    }
}