#pragma once

#include <Either.h>
#include <JSON.h>

#include "Block.h"
#include "JNoise.h"
#include "JsonExpression.h"

class GeneratorRule : public virtual Framework::ReferenceCounter
{
private:
    Noise* noise;
    float threshold;
    JBoolExpression* condition;

protected:
    virtual Framework::Either<Block*, int> createBlock(
        int x, int y, int z, int dimensionId)
        = 0;

public:
    GeneratorRule(
        Framework::JSON::JSONValue* zConfig, JExpressionMemory* zMemory);
    ~GeneratorRule();

    bool checkCondition(int x, int y, int z, JExpressionMemory* zMemory);
    Framework::Either<Block*, int> generateBlock(
        int x, int y, int z, int dimensionId);

    template<class T>
    static Framework::JSON::Validator::ObjectValidationBuilder<T>*
    addToValidator(
        Framework::JSON::Validator::ObjectValidationBuilder<T>* builder)
    {
        return builder
            ->withRequiredAttribute("noise", JNoise::getValidator(true))
            ->withRequiredAttribute(
                "condition", JExpressionParser::getBoolValidator())
            ->withRequiredNumber("threshold")
            ->whichIsOptional()
            ->whichIsGreaterOrEqual(0.0)
            ->whichIsLessOrEqual(1.0)
            ->finishNumber();
    }
};