#include "JsonExpression.h"

#include "Dimension.h"
#include "DimensionGenerator.h"
#include "Game.h"

JExpressionMemory::JExpressionMemory()
    : ReferenceCounter(),
      currentChunk(0)
{}

JExpressionMemory::~JExpressionMemory()
{
    if (currentChunk) currentChunk->release();
}

void JExpressionMemory::lock()
{
    cs.lock();
}

void JExpressionMemory::unlock()
{
    cs.unlock();
}

float JExpressionMemory::getNoise(
    Framework::Text name, float x, float y, float z) const
{
    Noise* currentNoise = noises.z(name, name.getLength());
    if (currentNoise)
        return (float)currentNoise->getNoise((double)x, (double)y, (double)z);
    return 0.f;
}

void JExpressionMemory::setNoise(Framework::Text name, Noise* noise)
{
    noises.set(name, name.getLength(), noise);
}

void JExpressionMemory::setCurrentChunk(Chunk* chunk)
{
    if (currentChunk) currentChunk->release();
    currentChunk = chunk;
}

float JExpressionMemory::getFloatVariable(const Framework::Text& name) const
{
    return floatVariables.get(name, name.getLength());
}

void JExpressionMemory::setFloatVariable(
    const Framework::Text& name, float value)
{
    floatVariables.set(name, name.getLength(), value);
}

bool JExpressionMemory::getBoolVariable(const Framework::Text& name) const
{
    return boolVariables.get(name, name.getLength());
}

void JExpressionMemory::setBoolVariable(const Framework::Text& name, bool value)
{
    return boolVariables.set(name, name.getLength(), value);
}

Chunk* JExpressionMemory::zCurrentChunk()
{
    return currentChunk;
}

JFloatExpression::JFloatExpression()
    : ReferenceCounter()
{}

JBoolExpression::JBoolExpression()
    : ReferenceCounter()
{}

JVariableFloatExpression::JVariableFloatExpression()
    : JFloatExpression()
{}

float JVariableFloatExpression::getValue(JExpressionMemory* zMemory)
{
    return zMemory->getFloatVariable(name);
}

void JVariableFloatExpression::setName(Framework::Text name)
{
    this->name = name;
}

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

JVariableFloatExpressionFactory::JVariableFloatExpressionFactory()
    : SubTypeFactory()
{}

JVariableFloatExpression* JVariableFloatExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JVariableFloatExpression* result = new JVariableFloatExpression();
    result->setName(zJson->zValue("name")->asString()->getString());
    return result;
}

Framework::JSON::JSONObject* JVariableFloatExpressionFactory::toJsonObject(
    JVariableFloatExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue(
        "name", new Framework::JSON::JSONString(zObject->getName()));
    return result;
}

JSONObjectValidationBuilder* JVariableFloatExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredString("name")->finishString();
}

const char* JVariableFloatExpressionFactory::getTypeToken() const
{
    return "variable";
}

JVariableBoolExpression::JVariableBoolExpression()
    : JBoolExpression()
{}

bool JVariableBoolExpression::getValue(JExpressionMemory* zMemory)
{
    return zMemory->getBoolVariable(name);
}

void JVariableBoolExpression::setName(Framework::Text name)
{
    this->name = name;
}

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

JVariableBoolExpressionFactory::JVariableBoolExpressionFactory()
    : SubTypeFactory()
{}

JVariableBoolExpression* JVariableBoolExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JVariableBoolExpression* result = new JVariableBoolExpression();
    result->setName(zJson->zValue("name")->asString()->getString());
    return result;
}

Framework::JSON::JSONObject* JVariableBoolExpressionFactory::toJsonObject(
    JVariableBoolExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue(
        "name", new Framework::JSON::JSONString(zObject->getName()));
    return result;
}

JSONObjectValidationBuilder* JVariableBoolExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredString("name")->finishString();
}

const char* JVariableBoolExpressionFactory::getTypeToken() const
{
    return "variable";
}

JConstantFloatExpression::JConstantFloatExpression()
    : JFloatExpression(),
      value(0)
{}

float JConstantFloatExpression::getValue(JExpressionMemory* zMemory)
{
    return value;
}

void JConstantFloatExpression::setValue(float value)
{
    this->value = value;
}

float JConstantFloatExpression::getValue() const
{
    return value;
}

JConstantFloatExpressionFactory::JConstantFloatExpressionFactory()
    : SubTypeFactory()
{}

JConstantFloatExpression* JConstantFloatExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JConstantFloatExpression* result = new JConstantFloatExpression();
    result->setValue((float)zJson->zValue("value")->asNumber()->getNumber());
    return result;
}

Framework::JSON::JSONObject* JConstantFloatExpressionFactory::toJsonObject(
    JConstantFloatExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue(
        "value", new Framework::JSON::JSONNumber(zObject->getValue()));
    return result;
}

JSONObjectValidationBuilder* JConstantFloatExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredNumber("value")->finishNumber();
}

const char* JConstantFloatExpressionFactory::getTypeToken() const
{
    return "constant";
}

JConstantBoolExpression::JConstantBoolExpression()
    : JBoolExpression()
{}

bool JConstantBoolExpression::getValue(JExpressionMemory* zMemory)
{
    return value;
}

void JConstantBoolExpression::setValue(bool value)
{
    this->value = value;
}

bool JConstantBoolExpression::getValue() const
{
    return value;
}

JConstantBoolExpressionFactory::JConstantBoolExpressionFactory()
    : SubTypeFactory()
{}

JConstantBoolExpression* JConstantBoolExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JConstantBoolExpression* result = new JConstantBoolExpression();
    result->setValue(zJson->zValue("value")->asBool()->getBool());
    return result;
}

Framework::JSON::JSONObject* JConstantBoolExpressionFactory::toJsonObject(
    JConstantBoolExpression* zObject) const
{
    Framework::JSON::JSONObject* zResult = new Framework::JSON::JSONObject();
    zResult->addValue(
        "value", new Framework::JSON::JSONBool(zObject->getValue()));
    return zResult;
}

JSONObjectValidationBuilder* JConstantBoolExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredBool("value")->finishBool();
}

const char* JConstantBoolExpressionFactory::getTypeToken() const
{
    return "constant";
}

JNoiseFloatExpression::JNoiseFloatExpression()
    : JFloatExpression(),
      x(0),
      y(0),
      z(0)
{}

JNoiseFloatExpression::~JNoiseFloatExpression()
{
    if (x) x->release();
    if (y) y->release();
    if (z) z->release();
}

float JNoiseFloatExpression::getValue(JExpressionMemory* zMemory)
{
    return zMemory->getNoise(
        name, x->getValue(zMemory), y->getValue(zMemory), z->getValue(zMemory));
}

void JNoiseFloatExpression::setName(Framework::Text name)
{
    this->name = name;
}

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

void JNoiseFloatExpression::setX(JFloatExpression* x)
{
    if (this->x) this->x->release();
    this->x = x;
}

JFloatExpression* JNoiseFloatExpression::zX() const
{
    return x;
}

void JNoiseFloatExpression::setY(JFloatExpression* y)
{
    if (this->y) this->y->release();
    this->y = y;
}

JFloatExpression* JNoiseFloatExpression::zY() const
{
    return y;
}

void JNoiseFloatExpression::setZ(JFloatExpression* z)
{
    if (this->z) this->z->release();
    this->z = z;
}

JFloatExpression* JNoiseFloatExpression::zZ() const
{
    return z;
}

JNoiseFloatExpressionFactory::JNoiseFloatExpressionFactory()
    : SubTypeFactory()
{}

JNoiseFloatExpression* JNoiseFloatExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JNoiseFloatExpression* result = new JNoiseFloatExpression();
    result->setName(zJson->zValue("name")->asString()->getString());
    result->setX(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
        zJson->zValue("x")));
    result->setY(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
        zJson->zValue("y")));
    result->setZ(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
        zJson->zValue("z")));
    return result;
}

Framework::JSON::JSONObject* JNoiseFloatExpressionFactory::toJsonObject(
    JNoiseFloatExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue(
        "name", new Framework::JSON::JSONString(zObject->getName()));
    result->addValue(
        "x", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zX()));
    result->addValue(
        "y", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zY()));
    result->addValue(
        "z", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zZ()));
    return result;
}

JSONObjectValidationBuilder* JNoiseFloatExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredString("name")
        ->finishString()
        ->withRequiredAttribute("x",
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
        ->withRequiredAttribute("y",
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
        ->withRequiredAttribute("z",
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>());
}

const char* JNoiseFloatExpressionFactory::getTypeToken() const
{
    return "noise";
}

JOperatorFloatExpression::JOperatorFloatExpression()
    : JFloatExpression(),
      accumulator([](float a, float b) { return 0.f; })
{}

float JOperatorFloatExpression::getValue(JExpressionMemory* zMemory)
{
    bool first = 1;
    float val = 0.f;
    for (JFloatExpression* expression : values)
    {
        if (first)
        {
            first = 0;
            val = expression->getValue(zMemory);
        }
        else
        {
            val = accumulator(val, expression->getValue(zMemory));
        }
    }
    return val;
}

void JOperatorFloatExpression::setOperator(
    Framework::Text op, std::function<float(float a, float b)> accumulator)
{
    this->op = op;
    this->accumulator = accumulator;
}

Framework::Text JOperatorFloatExpression::getOperator()
{
    return op;
}

void JOperatorFloatExpression::addValue(JFloatExpression* value)
{
    values.add(value);
}

const Framework::RCArray<JFloatExpression>&
JOperatorFloatExpression::getValues() const
{
    return values;
}

JOperatorFloatExpressionFactory::JOperatorFloatExpressionFactory()
    : SubTypeFactory()
{}

JOperatorFloatExpression* JOperatorFloatExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JOperatorFloatExpression* result = new JOperatorFloatExpression();
    Framework::Text op = zJson->zValue("operator")->asString()->getString();
    if (op.istGleich("+"))
    {
        result->setOperator("+", [](float a, float b) { return a + b; });
    }
    else if (op.istGleich("-"))
    {
        result->setOperator("-", [](float a, float b) { return a - b; });
    }
    else if (op.istGleich("*"))
    {
        result->setOperator("*", [](float a, float b) { return a * b; });
    }
    else if (op.istGleich("/"))
    {
        result->setOperator("/", [](float a, float b) { return a / b; });
    }
    for (Framework::JSON::JSONValue* value :
        *zJson->zValue("values")->asArray())
    {
        result->addValue(
            Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(value));
    }
    return result;
}

Framework::JSON::JSONObject* JOperatorFloatExpressionFactory::toJsonObject(
    JOperatorFloatExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue(
        "operator", new Framework::JSON::JSONString(zObject->getOperator()));
    Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray();
    for (JFloatExpression* expression : zObject->getValues())
    {
        values->addValue(
            Game::INSTANCE->zTypeRegistry()->toJson<JFloatExpression>(
                expression));
    }
    result->addValue("values", values);
    return result;
}

JSONObjectValidationBuilder* JOperatorFloatExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredString("operator")
        ->whichIsOneOf({"+", "-", "*", "/"})
        ->finishString()
        ->withRequiredArray("values")
        ->addAcceptedTypeInArray(
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
        ->finishArray();
}

const char* JOperatorFloatExpressionFactory::getTypeToken() const
{
    return "operator";
}

JBoolOperatorBoolExpression::JBoolOperatorBoolExpression()
    : JBoolExpression()
{}

bool JBoolOperatorBoolExpression::getValue(JExpressionMemory* zMemory)
{
    bool first = 1;
    bool val = 0;
    for (JBoolExpression* expression : values)
    {
        if (first)
        {
            first = 0;
            val = expression->getValue(zMemory);
        }
        else
        {
            val = accumulator(val, expression->getValue(zMemory));
        }
    }
    return val;
}

void JBoolOperatorBoolExpression::setOperator(
    Framework::Text op, std::function<float(float a, float b)> accumulator)
{
    this->op = op;
    this->accumulator = accumulator;
}

Framework::Text JBoolOperatorBoolExpression::getOperator()
{
    return op;
}

void JBoolOperatorBoolExpression::addValue(JBoolExpression* value)
{
    values.add(value);
}

const Framework::RCArray<JBoolExpression>&
JBoolOperatorBoolExpression::getValues() const
{
    return values;
}

JBoolOperatorBoolExpressionFactory::JBoolOperatorBoolExpressionFactory()
    : SubTypeFactory()
{}

JBoolOperatorBoolExpression* JBoolOperatorBoolExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JBoolOperatorBoolExpression* result = new JBoolOperatorBoolExpression();
    for (Framework::JSON::JSONValue* value :
        *zJson->zValue("values")->asArray())
    {
        result->addValue(
            Game::INSTANCE->zTypeRegistry()->fromJson<JBoolExpression>(value));
    }
    Framework::Text op = zJson->zValue("operator")->asString()->getString();
    if (op.istGleich("&&"))
    {
        result->setOperator("&&", [](bool a, bool b) { return a && b; });
    }
    else if (op.istGleich("||"))
    {
        result->setOperator("||", [](bool a, bool b) { return a || b; });
    }
    return result;
}

Framework::JSON::JSONObject* JBoolOperatorBoolExpressionFactory::toJsonObject(
    JBoolOperatorBoolExpression* zObject) const
{
    Framework::JSON::JSONObject* zResult = new Framework::JSON::JSONObject();
    Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray();
    for (JBoolExpression* expression : zObject->getValues())
    {
        values->addValue(
            Game::INSTANCE->zTypeRegistry()->toJson<JBoolExpression>(
                expression));
    }
    zResult->addValue("values", values);
    zResult->addValue(
        "operator", new Framework::JSON::JSONString(zObject->getOperator()));
    return zResult;
}

JSONObjectValidationBuilder* JBoolOperatorBoolExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredString("operator")
        ->whichIsOneOf({"&&", "||"})
        ->finishString()
        ->withRequiredArray("values")
        ->addAcceptedTypeInArray(
            Game::INSTANCE->zTypeRegistry()->getValidator<JBoolExpression>())
        ->finishArray();
}

const char* JBoolOperatorBoolExpressionFactory::getTypeToken() const
{
    return "operator";
}

JFloatOperatorBoolExpression::JFloatOperatorBoolExpression()
    : JBoolExpression()
{}

bool JFloatOperatorBoolExpression::getValue(JExpressionMemory* zMemory)
{
    bool first = 1;
    bool val = 1;
    float last = 0.f;
    for (JFloatExpression* expression : values)
    {
        float current = expression->getValue(zMemory);
        if (!first) val &= accumulator(last, current);
        first = 0;
        last = current;
        if (!val) break;
    }
    return val;
}

void JFloatOperatorBoolExpression::setOperator(
    Framework::Text op, std::function<bool(float a, float b)> accumulator)
{
    this->op = op;
    this->accumulator = accumulator;
}

Framework::Text JFloatOperatorBoolExpression::getOperator()
{
    return op;
}

void JFloatOperatorBoolExpression::addValue(JFloatExpression* value)
{
    values.add(value);
}

const Framework::RCArray<JFloatExpression>&
JFloatOperatorBoolExpression::getValues() const
{
    return values;
}

JFloatOperatorBoolExpressionFactory::JFloatOperatorBoolExpressionFactory()
    : SubTypeFactory()
{}

JFloatOperatorBoolExpression* JFloatOperatorBoolExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JFloatOperatorBoolExpression* result = new JFloatOperatorBoolExpression();
    Framework::Text op = zJson->zValue("operator")->asString()->getString();
    if (op.istGleich(">"))
    {
        result->setOperator(">", [](float a, float b) { return a > b; });
    }
    else if (op.istGleich("<"))
    {
        result->setOperator("<", [](float a, float b) { return a < b; });
    }
    else if (op.istGleich(">="))
    {
        result->setOperator(">=", [](float a, float b) { return a >= b; });
    }
    else if (op.istGleich("<="))
    {
        result->setOperator("<=", [](float a, float b) { return a <= b; });
    }
    else if (op.istGleich("=="))
    {
        result->setOperator("==", [](float a, float b) { return a == b; });
    }
    else if (op.istGleich("!="))
    {
        result->setOperator("!=", [](float a, float b) { return a != b; });
    }
    else if (op.istGleich(">i"))
    {
        result->setOperator(
            ">i", [](float a, float b) { return (int)a > (int)b; });
    }
    else if (op.istGleich("<i"))
    {
        result->setOperator(
            "<i", [](float a, float b) { return (int)a < (int)b; });
    }
    else if (op.istGleich(">=i"))
    {
        result->setOperator(
            ">=i", [](float a, float b) { return (int)a >= (int)b; });
    }
    else if (op.istGleich("<=i"))
    {
        result->setOperator(
            "<=i", [](float a, float b) { return (int)a <= (int)b; });
    }
    else if (op.istGleich("==i"))
    {
        result->setOperator(
            "==i", [](float a, float b) { return (int)a == (int)b; });
    }
    else if (op.istGleich("!=i"))
    {
        result->setOperator(
            "!=i", [](float a, float b) { return (int)a != (int)b; });
    }
    for (Framework::JSON::JSONValue* value :
        *zJson->zValue("values")->asArray())
    {
        result->addValue(
            Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(value));
    }
    return result;
}

Framework::JSON::JSONObject* JFloatOperatorBoolExpressionFactory::toJsonObject(
    JFloatOperatorBoolExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue(
        "operator", new Framework::JSON::JSONString(zObject->getOperator()));
    Framework::JSON::JSONArray* values = new Framework::JSON::JSONArray();
    for (JFloatExpression* expression : zObject->getValues())
    {
        values->addValue(
            Game::INSTANCE->zTypeRegistry()->toJson<JFloatExpression>(
                expression));
    }
    result->addValue("values", values);
    return result;
}

JSONObjectValidationBuilder*
JFloatOperatorBoolExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder->withRequiredString("operator")
        ->whichIsOneOf({">",
            "<",
            ">=",
            "<=",
            "==",
            "!=",
            "<i",
            ">i",
            ">=i",
            "<=i",
            "==i",
            "!=i"})
        ->finishString()
        ->withRequiredArray("values")
        ->addAcceptedTypeInArray(
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
        ->finishArray();
}

const char* JFloatOperatorBoolExpressionFactory::getTypeToken() const
{
    return "comparsion";
}

JBlockTypeBoolExpression::JBlockTypeBoolExpression()
    : JBoolExpression(),
      typeId(0),
      x(0),
      y(0),
      z(0)
{}

JBlockTypeBoolExpression ::~JBlockTypeBoolExpression()
{
    if (x) x->release();
    if (y) y->release();
    if (z) z->release();
}

bool JBlockTypeBoolExpression::getValue(JExpressionMemory* zMemory)
{
    int x = (int)(round(this->x->getValue(zMemory)));
    int y = (int)(round(this->y->getValue(zMemory)));
    int z = (int)(round(this->z->getValue(zMemory)));
    if (z < 0 || z >= WORLD_HEIGHT || !zMemory->zCurrentChunk()
        || Game::getChunkCenter(x, y) != zMemory->zCurrentChunk()->getCenter())
    {
        return 0;
    }
    return zMemory->zCurrentChunk()->getBlockTypeAt(
               Dimension::chunkCoordinates({x, y, z}))
        == typeId;
}

void JBlockTypeBoolExpression::setTypeId(int typeId)
{
    this->typeId = typeId;
}

int JBlockTypeBoolExpression::getTypeId() const
{
    return typeId;
}

void JBlockTypeBoolExpression::setX(JFloatExpression* x)
{
    if (this->x) this->x->release();
    this->x = x;
}

JFloatExpression* JBlockTypeBoolExpression::zX() const
{
    return x;
}

void JBlockTypeBoolExpression::setY(JFloatExpression* y)
{
    if (this->y) this->y->release();
    this->y = y;
}

JFloatExpression* JBlockTypeBoolExpression::zY() const
{
    return y;
}

void JBlockTypeBoolExpression::setZ(JFloatExpression* z)
{
    if (this->z) this->z->release();
    this->z = z;
}

JFloatExpression* JBlockTypeBoolExpression::zZ() const
{
    return z;
}

JBlockTypeBoolExpressionFactory::JBlockTypeBoolExpressionFactory()
    : SubTypeFactory()
{}

JBlockTypeBoolExpression* JBlockTypeBoolExpressionFactory::fromJson(
    Framework::JSON::JSONObject* zJson) const
{
    JBlockTypeBoolExpression* result = new JBlockTypeBoolExpression();
    result->setTypeId(Game::INSTANCE->getBlockTypeId(
        zJson->zValue("blockType")->asString()->getString()));
    result->setX(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
        zJson->zValue("x")));
    result->setY(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
        zJson->zValue("y")));
    result->setZ(Game::INSTANCE->zTypeRegistry()->fromJson<JFloatExpression>(
        zJson->zValue("z")));
    return result;
}

Framework::JSON::JSONObject* JBlockTypeBoolExpressionFactory::toJsonObject(
    JBlockTypeBoolExpression* zObject) const
{
    Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject();
    result->addValue("blockType",
        new Framework::JSON::JSONString(
            Game::INSTANCE->zBlockType(zObject->getTypeId())->getName()));
    result->addValue(
        "x", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zX()));
    result->addValue(
        "y", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zY()));
    result->addValue(
        "z", Game::INSTANCE->zTypeRegistry()->toJson(zObject->zZ()));
    return result;
}

JSONObjectValidationBuilder* JBlockTypeBoolExpressionFactory::addToValidator(
    JSONObjectValidationBuilder* builder) const
{
    return builder
        ->withRequiredAttribute("blockType",
            Game::INSTANCE->zTypeRegistry()->getValidator<Framework::Text>(
                BlockTypeNameFactory::TYPE_ID))
        ->withRequiredAttribute("x",
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
        ->withRequiredAttribute("y",
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>())
        ->withRequiredAttribute("z",
            Game::INSTANCE->zTypeRegistry()->getValidator<JFloatExpression>());
}

const char* JBlockTypeBoolExpressionFactory::getTypeToken() const
{
    return "blockType";
}