#include "StatusBars.h"

#include <FileSystem.h>
#include <Image.h>
#include <XML.h>

#include "Globals.h"

StatusBarsElement::StatusBarsElement()
    : UIMLElement()
{}

//! prüft, ob dieses UIML Element für ein bestimmtes xml Element zuständig
//! ist
bool StatusBarsElement::isApplicableFor(Framework::XML::Element& element)
{
    return element.getName().isEqual("statusBars");
}

//! erstellt eine neue Drawable zu einem gegebenen xml Element
Framework::Drawable* StatusBarsElement::parseElement(
    Framework::XML::Element& element, Framework::UIMLContainer& generalFactory)
{
    return new StatusBarsView(element.getAttributeValue("id"),
        (int)element.getAttributeValue("target"));
}

bool StatusBarsElement::updateElement(Framework::XML::Element& element,
    Framework::Drawable& z,
    Framework::UIMLContainer& generalFactory)
{
    return false;
}

//! wendet die layout parameter zu einer Drawable an
void StatusBarsElement::layout(Framework::XML::Element& element,
    Framework::Drawable& z,
    int pWidth,
    int pHeight,
    Framework::UIMLContainer& generalLayouter)
{
    z.setHeight(54);
    z.setWidth(592);
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

StatusBarsView::StatusBarsView(Framework::Text id, int targetEntity)
    : DrawableBackground(),
      NetworkAPIProcessor(),
      id(id),
      targetEntity(targetEntity)
{
    setStyle(DrawableBackground::Style::Visible
             | DrawableBackground::Style::Border
             | DrawableBackground::Style::Background
             | DrawableBackground::Style::BAlpha);
    setBorderColor(0xA052525E);
    setBackgroundColor(0xA0222222);
    setBorderWidth(2);
    Framework::LTDBFile file;
    file.setFile(new Framework::Text("data/images/gui_icons.ltdb"));
    file.readData(0);
    healthIcon = file.load(0, new Framework::Text("health.png"));
    energyIcon = file.load(0, new Framework::Text("energy.png"));
    hungerIcon = file.load(0, new Framework::Text("food.png"));
    thirstIcon = file.load(0, new Framework::Text("water.png"));
    health = 0.f;
    hunger = 0.f;
    thirst = 0.f;
    energy = 0.f;
    tr.setFontZ(dynamic_cast<Font*>(uiFactory.initParam.font->getThis()));
    tr.setFontSize(12);
    char* msg = new char[id.getLength() + 6];
    msg[0] = 0; // request status bar state
    msg[1] = (char)id.getLength();
    memcpy(msg + 2, id.getText(), id.getLength());
    *(int*)(msg + 2 + id.getLength()) = NetworkAPIProcessor::getId();
    World::INSTANCE->zClient()->entityAPIRequest(
        targetEntity, msg, id.getLength() + 6);
    delete[] msg;
}

StatusBarsView::~StatusBarsView()
{
    char* msg = new char[id.getLength() + 6];
    msg[0] = 1; // remove status bar observer
    msg[1] = (char)id.getLength();
    memcpy(msg + 2, id.getText(), id.getLength());
    *(int*)(msg + 2 + id.getLength()) = NetworkAPIProcessor::getId();
    World::INSTANCE->zClient()->entityAPIRequest(
        targetEntity, msg, id.getLength() + 6);
    delete[] msg;
    healthIcon->release();
    energyIcon->release();
    hungerIcon->release();
    thirstIcon->release();
}

void StatusBarsView::api(char* message)
{
    switch (message[0])
    {
    case 0: // initialisation
        {
            float maxHealth = *(float*)(message + 1);
            float health = *(float*)(message + 5);
            float maxStamina = *(float*)(message + 9);
            float stamina = *(float*)(message + 13);
            float maxHunger = *(float*)(message + 17);
            float hunger = *(float*)(message + 21);
            float maxThirst = *(float*)(message + 25);
            float thirst = *(float*)(message + 29);
            this->health = health / maxHealth;
            this->energy = stamina / maxStamina;
            this->hunger = hunger / maxHunger;
            this->thirst = thirst / maxThirst;
            writeLock().lock();
            healthText = (int)ceil(health);
            energyText = (int)ceil(stamina);
            hungerText = (int)ceil(hunger);
            thirstText = (int)ceil(thirst);
            writeLock().unlock();
            break;
        }
    case 1: // update health
        {
            float maxHealth = *(float*)(message + 1);
            float health = *(float*)(message + 5);
            this->health = health / maxHealth;
            writeLock().lock();
            healthText = (int)ceil(health);
            writeLock().unlock();
            break;
        }
    case 2: // update stamina
        {
            float maxStamina = *(float*)(message + 1);
            float stamina = *(float*)(message + 5);
            this->energy = stamina / maxStamina;
            writeLock().lock();
            energyText = (int)ceil(stamina);
            writeLock().unlock();
            break;
        }
    case 3: // update hunger
        {
            float maxHunger = *(float*)(message + 1);
            float hunger = *(float*)(message + 5);
            this->hunger = hunger / maxHunger;
            writeLock().lock();
            hungerText = (int)ceil(hunger);
            writeLock().unlock();
            break;
        }
    case 4: // update thirst
        {
            float maxThirst = *(float*)(message + 1);
            float thirst = *(float*)(message + 5);
            this->thirst = thirst / maxThirst;
            writeLock().lock();
            thirstText = (int)ceil(thirst);
            writeLock().unlock();
            break;
        }
    }
    setRender();
}

void StatusBarsView::render(Framework::Image& rObj)
{
    DrawableBackground::render(rObj);
    if (!rObj.setDrawOptions(pos.x + getBorderWidth(),
            pos.y + getBorderWidth(),
            gr.x - getBorderWidth() * 2,
            gr.y - getBorderWidth() * 2))
        return;
    rObj.alphaImage(0, 0, 20, 20, *healthIcon);
    rObj.alphaImage(gr.x - getBorderWidth() * 2 - 20, 10, 20, 20, *energyIcon);
    rObj.alphaImage(0, 20, 20, 20, *hungerIcon);
    rObj.alphaImage(gr.x - getBorderWidth() * 2 - 20, 30, 20, 20, *thirstIcon);
    readLock().lock();
    tr.renderText(25, 4, healthText, rObj, 0xFFFFFFFF);
    tr.renderText(25, 24, hungerText, rObj, 0xFFFFFFFF);
    int leftTxtBr
        = MAX(tr.getTextWidth(healthText), tr.getTextWidth(hungerText));
    int rightTxtBr
        = MAX(tr.getTextWidth(energyText), tr.getTextWidth(thirstText));
    tr.renderText(gr.x - getBorderWidth() * 2 - 25 - rightTxtBr,
        14,
        energyText,
        rObj,
        0xFFFFFFFF);
    tr.renderText(gr.x - getBorderWidth() * 2 - 25 - rightTxtBr,
        34,
        thirstText,
        rObj,
        0xFFFFFFFF);
    readLock().unlock();
    int leftWidth = gr.x - 62 - leftTxtBr - getBorderWidth() * 2 - rightTxtBr;
    if (leftWidth > 0)
    {
        rObj.drawLineVAlpha(30 + leftTxtBr, 0, gr.y, 0xA052525E);
        rObj.drawLineVAlpha(
            gr.x - getBorderWidth() * 2 - 31 - rightTxtBr, 0, gr.y, 0xA052525E);

        for (int i = 0; i <= 6; i++)
            rObj.drawLineHAlpha(30 + leftTxtBr + 1, i, leftWidth, 0xA052525E);
        for (int i = 13; i <= 16; i++)
            rObj.drawLineHAlpha(30 + leftTxtBr + 1, i, leftWidth, 0xA052525E);
        for (int i = 23; i <= 22; i++)
            rObj.drawLineHAlpha(30 + leftTxtBr + 1, i, leftWidth, 0xA052525E);
        for (int i = 23; i <= 32; i++)
            rObj.drawLineHAlpha(30 + leftTxtBr + 1, i, leftWidth, 0xA052525E);
        for (int i = 33; i <= 42; i++)
            rObj.drawLineHAlpha(30 + leftTxtBr + 1, i, leftWidth, 0xA052525E);
        for (int i = 43; i <= 49; i++)
            rObj.drawLineHAlpha(30 + leftTxtBr + 1, i, leftWidth, 0xA052525E);
        for (int i = 0; i < 6; i++)
        {
            rObj.drawLineH(30 + leftTxtBr + 1,
                7 + i,
                (int)((float)leftWidth * health),
                0xFFB9180C);
            rObj.drawLineHAlpha(
                30 + leftTxtBr + 1 + (int)((float)leftWidth * health),
                7 + i,
                leftWidth - (int)((float)leftWidth * health),
                0xA052525E);
            rObj.drawLineH(30 + leftTxtBr + 1,
                17 + i,
                (int)((float)leftWidth * energy),
                0xFFF0C800);
            rObj.drawLineHAlpha(
                30 + leftTxtBr + 1 + (int)((float)leftWidth * energy),
                17 + i,
                leftWidth - (int)((float)leftWidth * energy),
                0xA052525E);
            rObj.drawLineH(30 + leftTxtBr + 1,
                27 + i,
                (int)((float)leftWidth * hunger),
                0xFF008300);
            rObj.drawLineHAlpha(
                30 + leftTxtBr + 1 + (int)((float)leftWidth * hunger),
                27 + i,
                leftWidth - (int)((float)leftWidth * hunger),
                0xA052525E);
            rObj.drawLineH(30 + leftTxtBr + 1,
                37 + i,
                (int)((float)leftWidth * thirst),
                0xFF0018FF);
            rObj.drawLineHAlpha(
                30 + leftTxtBr + 1 + (int)((float)leftWidth * thirst),
                37 + i,
                leftWidth - (int)((float)leftWidth * thirst),
                0xA052525E);
        }
    }
    rObj.releaseDrawOptions();
}
