#include "Dialog.h"

#include <DateiSystem.h>
#include <InMemoryBuffer.h>
#include <TastaturEreignis.h>
#include <TextFeld.h>
#include <XML.h>

#include "CraftingGrid.h"
#include "CraftingRecipies.h"
#include "Equipment.h"
#include "Globals.h"
#include "InventoryView.h"
#include "ListView.h"
#include "QuestGraph.h"
#include "RecipieIngredient.h"
#include "RecipieOutput.h"
#include "ShapedRecipie.h"
#include "UnshapedRecipie.h"

using namespace Framework;

UIMLDialog::UIMLDialog(
    Framework::Text uiml, std::function<void(UIMLDialog* self)> onClose)
    : Fenster()
{
    XML::Element* xml = new XML::Element(uiml);
    view = new UIMLView("<v/>", uiFactory);
    view->setStyle(UIMLView::Style::Erlaubt | UIMLView::Style::Sichtbar
                   | UIMLView::Style::GlobalMouseEvent);
    view->setMausEreignis(_ret1ME);
    view->addKnownElement(new InventoryElement());
    view->addKnownElement(new EquipmentElement());
    view->addKnownElement(new CraftingGridElement());
    view->addKnownElement(new CraftingRecipiesElement());
    view->addKnownElement(new RecipieIngredientElement());
    view->addKnownElement(new RecipieOutputElement());
    view->addKnownElement(new ShapedRecipieElement());
    view->addKnownElement(new UnshapedRecipieElement());
    view->addKnownElement(new ListViewElement());
    view->addKnownElement(new QuestGraphElement());
    view->addKnownElement(new QuestGraphItemElement());
    view->setOnMemberMouseEvent([](Framework::XML::Element& element,
                                    Framework::Zeichnung& z,
                                    MausEreignis me) {
        if (me.id == ME_RLinks)
        {
            Framework::Text onClick = element.getAttributeValue("onClick");
            if (onClick.getLength() == 0)
            {
                return !element.hasAttribute("onClick");
            }
            Framework::Text* dialogName
                = onClick.getTeilText(0, onClick.positionVon(";"));
            Framework::Text* tail
                = onClick.getTeilText(onClick.positionVon(";") + 1);
            Framework::InMemoryBuffer buffer;
            buffer.schreibe("\0", 1); // element message
            while (tail->getLength() > 0)
            {
                Framework::Text* current = 0;
                if (tail->positionVon(";") >= 0)
                {
                    current = tail->getTeilText(0, tail->positionVon(";"));
                    Framework::Text* tmp
                        = tail->getTeilText(tail->positionVon(";") + 1);
                    tail->release();
                    tail = tmp;
                }
                else
                {
                    current = new Text(*tail);
                    tail->setText("");
                }
                if (current->positionVon("(char)") == 0)
                {
                    current->ersetzen("(char)", "");
                    char d = (char)(int)*current;
                    buffer.schreibe(&d, 1);
                }
                else if (current->positionVon("(short)") == 0)
                {
                    current->ersetzen("(short)", "");
                    short d = (short)(int)*current;
                    buffer.schreibe((char*)&d, 2);
                }
                else if (current->positionVon("(int)") == 0)
                {
                    current->ersetzen("(int)", "");
                    int d = (int)*current;
                    buffer.schreibe((char*)&d, 4);
                }
                else if (current->positionVon("(__int64)") == 0)
                {
                    current->ersetzen("(__int64)", "");
                    __int64 d = (__int64)*current;
                    buffer.schreibe((char*)&d, 8);
                }
                else if (current->positionVon("(float)") == 0)
                {
                    current->ersetzen("(float)", "");
                    float d = (float)*current;
                    buffer.schreibe((char*)&d, 4);
                }
                else if (current->positionVon("(double)") == 0)
                {
                    current->ersetzen("(double)", "");
                    double d = (double)*current;
                    buffer.schreibe((char*)&d, 8);
                }
                else
                {
                    unsigned char len = (unsigned char)current->getLength();
                    buffer.schreibe((char*)&len, 1);
                    buffer.schreibe(*current, len);
                }
                current->release();
            }
            char* message = new char[buffer.getSize()];
            buffer.lese(message, (int)buffer.getSize());
            World::INSTANCE->zClient()->uiRequest(
                *dialogName, message, (int)buffer.getSize());
            delete[] message;
            dialogName->release();
            tail->release();
        }
        return (bool)1;
    });
    view->setUIML(xml);
    view->setSize((int)xml->getAttributeValue("width"),
        (int)xml->getAttributeValue("height"));
    name = xml->getAttributeValue("id");
    view->layout();
    if (!xml->hasAttribute("width"))
    {
        view->setSize(view->calculateContentSize().x, view->getHeight());
    }
    if (!xml->hasAttribute("height"))
    {
        view->setSize(view->getBreite(), view->calculateContentSize().y);
    }
    bool notifyOnClose = 0;
    int notifyOnCloseDimension = -1;
    Vec3<int> notifyOnCloseBlock;
    if (xml->hasAttribute("notifyOnClose"))
    {
        notifyOnClose = 1;
        Text value = xml->getAttributeValue("notifyOnClose");
        if (value.hat(","))
        {
            Text* first = value.getTeilText(0, value.positionVon(",", 0) + 1);
            Text* second = value.getTeilText(
                value.positionVon(",", 0) + 1, value.positionVon(",", 1));
            Text* third = value.getTeilText(
                value.positionVon(",", 1) + 1, value.positionVon(",", 2));
            Text* forth = value.getTeilText(value.positionVon(",", 2) + 1);
            notifyOnCloseDimension = (int)*first;
            notifyOnCloseBlock.x = (int)*second;
            notifyOnCloseBlock.y = (int)*third;
            notifyOnCloseBlock.z = (int)*forth;
            first->release();
            second->release();
            third->release();
            forth->release();
        } // TODO: else entity id
    }
    addMember(view);

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

    setStyle(
        Fenster::Style::Sichtbar | Fenster::Style::Erlaubt
        | Fenster::Style::Rahmen | Fenster::Style::BodyHAlpha
        | Fenster::Style::Beweglich | Fenster::Style::Titel
        | Fenster::Style::TitelHAlpha | Fenster::Style::Closable
        | Fenster::Style::ClosingHAlpha | Fenster::Style::ClosingKlickBuffer
        | Fenster::Style::TitelHintergrund | Fenster::Style::BodyHintergrund
        | Fenster::Style::ClosingHintergrund | Fenster::Style::MEIgnoreInside
        | Style::ClosingBuffer | Style::ClosingHBild);
    setKBgFarbe(0xA0000000);
    setTBgFarbe(0xA0000000);
    setSBgFarbe(0xA0000000);
    setSize(view->getBreite() + 4, view->getHeight() + 24);
    setPosition(window->zBildschirm()->getBackBufferSize() / 2 - getSize() / 2);
    setRBreite(2);
    this->onClose = [onClose,
                        notifyOnClose,
                        notifyOnCloseDimension,
                        notifyOnCloseBlock,
                        this](UIMLDialog* self) {
        if (notifyOnClose)
        {
            if (notifyOnCloseDimension >= 0)
            {
                char* msg = new char[name.getLength() + 3];
                msg[0] = 1; // dialog closed
                *(short*)(msg + 1) = (short)name.getLength();
                memcpy(msg + 3, name.getText(), name.getLength());
                World::INSTANCE->zClient()->blockAPIRequest(
                    notifyOnCloseDimension,
                    notifyOnCloseBlock,
                    msg,
                    name.getLength() + 3);
                delete[] msg;
            } // TODO: else entity notification
        }
        onClose(this);
    };
    setClosingMe(
        [notifyOnClose, notifyOnCloseDimension, notifyOnCloseBlock, this](
            void* p, void* o, MausEreignis me) {
            if (me.id == ME_RLinks)
            {
                this->close();
            }
            return 1;
        });
    setRFarbe(0xFF52525E);
    setTitel(xml->getAttributeValue("title"));
    setTSchriftZ(
        dynamic_cast<Schrift*>(uiFactory.initParam.schrift->getThis()));
    zTTextFeld()->setSize(0, 20);
    zTTextFeld()->addStyle(TextFeld::Style::Center);
    setTastaturEreignis(_ret1TE);
    setSAfStrength(10);
    setSAfFarbe(0x5F9C0A0A);
    setSBgBildZ(iconsDat.laden(0, new Text("close.png")));
    setSKAfFarbe(0xFF9C0A0A);
    setSKAfStrength(10);
}

UIMLDialog::~UIMLDialog() {}

void UIMLDialog::api(char* message)
{
    short idLen = *(short*)message;
    char* id = new char[idLen + 1];
    memcpy(id, message + 2, idLen);
    id[idLen] = 0;
    NetworkAPIProcessor* processor
        = dynamic_cast<NetworkAPIProcessor*>(view->zZeichnungById(id));
    if (processor) processor->api(message + 2 + idLen);
    delete[] id;
}

const Framework::Text& UIMLDialog::getName() const
{
    return name;
}

void UIMLDialog::updateUIML(const char* uiml)
{
    XML::Element* xml = new XML::Element(uiml);
    view->setSize((int)xml->getAttributeValue("width"),
        (int)xml->getAttributeValue("height"));
    view->setUIML(uiml);
    view->layout();
    if (!xml->hasAttribute("width"))
    {
        view->setSize(view->calculateContentSize().x, view->getHeight());
    }
    if (!xml->hasAttribute("height"))
    {
        view->setSize(view->getBreite(), view->calculateContentSize().y);
    }
    Punkt oldSize = getSize();
    setSize(view->getBreite() + 4, view->getHeight() + 24);
    setPosition(getPosition() + (oldSize - getSize()) / 2);
}

void UIMLDialog::close()
{
    World::INSTANCE->zClient()->uiRequest(name, "\1", 1);
    onClose(this);
}