#include "TreeTemplate.h"

#include "Game.h"
#include "MultiblockTree.h"

TreeTemplate::TreeTemplate(float propability,
    int woodBlockTypeId,
    int leaveBlockType,
    int minHeight,
    int maxHeight)
    : GenerationTemplate(propability,
        0,
        1,
        Framework::Vec3<int>(-2, -2, 0),
        Framework::Vec3<int>(5, 5, maxHeight)),
      woodBlockTypeId(woodBlockTypeId),
      leaveBlockType(leaveBlockType),
      minHeight(minHeight),
      maxHeight(maxHeight)
{}

GeneratedStructure* TreeTemplate::generateAt(
    Framework::Vec3<int> location, Noise* zNoise, int dimensionId)
{
    double noise = zNoise->getNoise((double)location.x + 40,
        (double)location.y + 70,
        (double)location.z - 20);
    int height = (int)(minHeight + (noise * (maxHeight - minHeight)));
    Dimension* zDim = Game::INSTANCE->zDimension(dimensionId);
    MultiblockStructure* treeStructure = zDim->zStructureByPosition(location);
    if (!treeStructure)
    {
        treeStructure = new MultiblockTree(
            dimensionId, zDim->getNextStructureId(), location);
        zDim->addStructure(treeStructure);
    }
    Framework::Vec3<int> minAffected
        = Framework::Vec3<int>(-2, -2, 0) + location;
    GeneratedStructure* generated
        = new GeneratedStructure(dynamic_cast<GenerationTemplate*>(getThis()),
            location,
            Framework::Vec3<int>(5, 5, height),
            minAffected);
    for (int x = 1; x < 4; x++)
    {
        for (int y = 1; y < 4; y++)
        {
            generated->setBlockAt(
                leaveBlockType, Framework::Vec3<int>(x, y, height - 1));
            generated->setBlockAt(
                leaveBlockType, Framework::Vec3<int>(x, y, height - 5));
        }
    }
    for (int z = height - 2; z >= height - 4; z--)
    {
        for (int x = 1; x < 4; x++)
        {
            generated->setBlockAt(
                leaveBlockType, Framework::Vec3<int>(x, 0, z));
            generated->setBlockAt(
                leaveBlockType, Framework::Vec3<int>(0, x, z));
            generated->setBlockAt(
                leaveBlockType, Framework::Vec3<int>(x, 4, z));
            generated->setBlockAt(
                leaveBlockType, Framework::Vec3<int>(4, x, z));
            for (int y = 1; y < 4; y++)
                generated->setBlockAt(
                    leaveBlockType, Framework::Vec3<int>(x, y, z));
        }
    }
    for (int i = 0; i < height - 1; i++)
        generated->setBlockAt(woodBlockTypeId, Framework::Vec3<int>(2, 2, i));
    generated->addAllBlocksToStructure(
        dynamic_cast<MultiblockStructure*>(treeStructure->getThis()));
    return generated;
}

const BlockType* TreeTemplate::getWoodType() const
{
    return StaticRegistry<BlockType>::INSTANCE.zElement(woodBlockTypeId);
}

const BlockType* TreeTemplate::getLeavesType() const
{
    return StaticRegistry<BlockType>::INSTANCE.zElement(leaveBlockType);
}