#include "Block.h"

#include <Shader.h>
#include <Textur.h>

#include "CustomDX11API.h"
#include "Globals.h"

Block::Block(const BlockType* zType,
    Framework::Vec3<int> pos,
    Model3DData* model,
    Model3DTextur* texture,
    int maxHP,
    bool transparent,
    bool needRequestModelInfo)
    : FactoryCraftModel(),
      zType(zType),
      location(pos),
      maxHP((float)maxHP),
      needRequestModelInfo(needRequestModelInfo)
{
    hp = (float)maxHP;
    memset(sideVisible, 0, 6);
    //Model3D::setAlpha(transparent);
    Model3D::setPosition(
        (Framework::Vec3<float>)pos + Framework::Vec3<float>{0.5f, 0.5f, 0.5f});
    setModelDaten(model);
    setModelTextur(texture);
    memset(lightData, 0, 6 * 6);
}

Block::~Block()
{}

void Block::beforeRender(
    GraphicsApi* api, Shader* zVertexShader, Shader* zPixelShader)
{
    if (needRequestModelInfo)
    {
        needRequestModelInfo = 0;
        World::INSTANCE->zClient()->blockAPIRequest(location, "\0", 1);
    }
    FactoryCraftModel::beforeRender(api, zVertexShader, zPixelShader);
}

void Block::api(char* message)
{
    switch (message[0])
    {
    case 0: // hp change
        {
            hp = *(float*)(message + 1);
            setDestroyedState(1 - hp / maxHP);
            Model3D* mdl = World::INSTANCE->getCurrentTarget();
            if (mdl == this)
            {
                if (zBlockType()->getModelInfo().getModelName().istGleich(
                        "cube"))
                {
                    World::INSTANCE->zSelectedEffectModel()->setDestroyedState(
                        1 - hp / maxHP);
                }
            }
            if (mdl) mdl->release();
            break;
        }
    case 1: // model change
        {
            ByteArrayReader reader(message + 1, 10000, 0);
            ModelInfo info(&reader);
            setModelDaten(info.getModel());
            setModelTextur(info.getTexture());
            break;
        }
    case 2: // update fluid fill state
        {
            short fluidAmount = *(short*)(message + 1);
            if (this->skelett)
            {
                float z = (float)fluidAmount / 1000.f;
                Bone* b = this->skelett->zRootBone()->zFirstChild();
                b->setPosition(Vec3<float>(0.f, 0.f, z - 1));
                b = b->zFirstSibling();
                b->setPosition(Vec3<float>(0.f, 0.f, z - 1));
                b = b->zFirstSibling();
                b->setPosition(Vec3<float>(0.f, 0.f, z - 1));
                b = b->zFirstSibling();
                b->setPosition(Vec3<float>(0.f, 0.f, z - 1));
            }
        }
    }
}

void Block::copyLightTo(Block* zB)
{
    memcpy(zB->lightData, lightData, 6 * 6);
    memcpy(zB->sideVisible, sideVisible, 6);
}

void Block::setLightData(Direction dir, unsigned char* data)
{
    memcpy(lightData + getDirectionIndex(dir) * 6, data, 6);
    if (data[0] | data[1] | data[2] | data[3] | data[4] | data[5])
        sideVisible[getDirectionIndex(dir)] = 1;
    else
        sideVisible[getDirectionIndex(dir)] = 0;
    Chunk* zC = World::INSTANCE->zChunk(
        World::INSTANCE->getChunkCenter(location.x, location.y));
    if (zC) zC->setLightChanged();
}

const unsigned char* Block::getLightData(Direction dir) const
{
    return lightData + getDirectionIndex(dir) * 6;
}

bool Block::isVisible() const
{
    return true;
    //return sideVisible[0] || sideVisible[1] || sideVisible[2] || sideVisible[3]
    //    || sideVisible[4] || sideVisible[5];
}

Vec3<int> Block::getLocation() const
{
    return location;
}

const BlockType* Block::zBlockType() const
{
    return zType;
}

Skeleton* Block::zSkeleton() const
{
    return skelett;
}

Text Block::printLightInfo()
{
    Text result = "NORTH[0;-1;0](";
    result += (int)lightData[0];
    result += ",";
    result += (int)lightData[1];
    result += ",";
    result += (int)lightData[2];
    result += ";";
    result += (int)lightData[3];
    result += ",";
    result += (int)lightData[4];
    result += ",";
    result += (int)lightData[5];
    result += ")\n";
    result += "EAST[1;0;0](";
    result += (int)lightData[6];
    result += ",";
    result += (int)lightData[7];
    result += ",";
    result += (int)lightData[8];
    result += ";";
    result += (int)lightData[9];
    result += ",";
    result += (int)lightData[10];
    result += ",";
    result += (int)lightData[11];
    result += ")\n";
    result += "SOUTH[0;1;0](";
    result += (int)lightData[12];
    result += ",";
    result += (int)lightData[13];
    result += ",";
    result += (int)lightData[14];
    result += ";";
    result += (int)lightData[15];
    result += ",";
    result += (int)lightData[16];
    result += ",";
    result += (int)lightData[17];
    result += ")\n";
    result += "WEST[-1;0;0](";
    result += (int)lightData[18];
    result += ",";
    result += (int)lightData[19];
    result += ",";
    result += (int)lightData[20];
    result += ";";
    result += (int)lightData[21];
    result += ",";
    result += (int)lightData[22];
    result += ",";
    result += (int)lightData[23];
    result += ")\n";
    result += "TOP[0;0;1](";
    result += (int)lightData[24];
    result += ",";
    result += (int)lightData[25];
    result += ",";
    result += (int)lightData[26];
    result += ";";
    result += (int)lightData[27];
    result += ",";
    result += (int)lightData[28];
    result += ",";
    result += (int)lightData[29];
    result += ")\n";
    result += "BOTTOM[0;0;-1](";
    result += (int)lightData[30];
    result += ",";
    result += (int)lightData[31];
    result += ",";
    result += (int)lightData[32];
    result += ";";
    result += (int)lightData[33];
    result += ",";
    result += (int)lightData[34];
    result += ",";
    result += (int)lightData[35];
    result += ")\n";
    return result;
}