// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.procedurallib.logic;

import javax.annotation.Nonnull;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.procedurallib.property.NoiseFormulaProperty;
import com.hypixel.hytale.procedurallib.condition.IIntCondition;
import com.hypixel.hytale.procedurallib.supplier.IDoubleRange;
import com.hypixel.hytale.procedurallib.logic.cell.evaluator.PointEvaluator;
import com.hypixel.hytale.procedurallib.logic.cell.CellDistanceFunction;
import com.hypixel.hytale.procedurallib.NoiseFunction;

public class BranchNoise implements NoiseFunction
{
    protected final CellDistanceFunction parentFunction;
    protected final PointEvaluator parentEvaluator;
    protected final double parentValue;
    protected final double emptyValue;
    protected final IDoubleRange parentFade;
    protected final IIntCondition parentDensity;
    protected final DistanceNoise.Distance2Function distance2Function;
    protected final NoiseFormulaProperty.NoiseFormula.Formula noiseFormula;
    protected final CellDistanceFunction lineFunction;
    protected final PointEvaluator lineEvaluator;
    protected final double lineScale;
    protected final IDoubleRange lineThickness;
    
    public BranchNoise(final CellDistanceFunction parentFunction, final PointEvaluator parentEvaluator, final double parentValue, final IDoubleRange parentFade, final IIntCondition parentDensity, final DistanceNoise.Distance2Function distance2Function, final NoiseFormulaProperty.NoiseFormula.Formula noiseFormula, final CellDistanceFunction lineFunction, final PointEvaluator lineEvaluator, final double lineScale, final IDoubleRange lineThickness) {
        this.parentFunction = parentFunction;
        this.parentEvaluator = parentEvaluator;
        this.parentValue = parentValue;
        this.emptyValue = toOutputRange(parentValue);
        this.parentFade = parentFade;
        this.parentDensity = parentDensity;
        this.distance2Function = distance2Function;
        this.noiseFormula = noiseFormula;
        this.lineFunction = lineFunction;
        this.lineEvaluator = lineEvaluator;
        this.lineScale = lineScale;
        this.lineThickness = lineThickness;
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, final double x, final double y) {
        final ResultBuffer.ResultBuffer2d parent = this.getParentNoise(offsetSeed, x, y);
        if (!this.parentDensity.eval(parent.hash)) {
            return this.emptyValue;
        }
        final double parentDistance = this.noiseFormula.eval(this.distance2Function.eval(parent.distance, parent.distance2));
        final double lineValue = this.getLineValue(offsetSeed, x, y, parent.hash, parent.x, parent.y, parentDistance, parent);
        final double parentFade = this.parentFade.getValue(parentDistance);
        final double noiseValue = MathUtil.lerp(this.parentValue, lineValue, parentFade);
        return toOutputRange(noiseValue);
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, final double x, final double y, final double z) {
        throw new UnsupportedOperationException();
    }
    
    @Nonnull
    protected ResultBuffer.ResultBuffer2d localBuffer2d() {
        return ResultBuffer.buffer2d;
    }
    
    @Nonnull
    protected ResultBuffer.ResultBuffer2d getParentNoise(final int seed, double x, double y) {
        final ResultBuffer.ResultBuffer2d buffer = this.localBuffer2d();
        buffer.distance = Double.POSITIVE_INFINITY;
        buffer.distance2 = Double.POSITIVE_INFINITY;
        x = this.parentFunction.scale(x);
        y = this.parentFunction.scale(y);
        final int cellX = this.parentFunction.getCellX(x, y);
        final int cellY = this.parentFunction.getCellY(x, y);
        this.parentFunction.transition2D(seed, x, y, cellX, cellY, buffer, this.parentEvaluator);
        return buffer;
    }
    
    protected double getLineValue(final int seed, double x, double y, final int parentHash, final double parentX, final double parentY, final double parentDistance, @Nonnull final ResultBuffer.ResultBuffer2d buffer) {
        final double thickness = this.lineThickness.getValue(parentDistance);
        if (thickness == 0.0) {
            return 1.0;
        }
        buffer.distance = Double.POSITIVE_INFINITY;
        buffer.x2 = parentX;
        buffer.y2 = parentY;
        buffer.ix2 = parentHash;
        buffer.distance2 = thickness;
        x *= this.lineScale;
        y *= this.lineScale;
        x = this.lineFunction.scale(x);
        y = this.lineFunction.scale(y);
        final int cellX = this.lineFunction.getCellX(x, y);
        final int cellY = this.lineFunction.getCellY(x, y);
        this.lineFunction.nearest2D(seed, x, y, cellX, cellY, buffer, this.lineEvaluator);
        final double distance = buffer.distance;
        if (distance >= thickness * thickness) {
            return 1.0;
        }
        return Math.sqrt(distance) / thickness;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "BranchNoise{parentFunction=" + String.valueOf(this.parentFunction) + ", parentEvaluator=" + String.valueOf(this.parentEvaluator) + ", parentValue=" + this.parentValue + ", parentFade=" + String.valueOf(this.parentFade) + ", distance2Function=" + String.valueOf(this.distance2Function) + ", noiseFormula=" + String.valueOf(this.noiseFormula) + ", lineFunction=" + String.valueOf(this.lineFunction) + ", lineEvaluator=" + String.valueOf(this.lineEvaluator) + ", lineScale=" + this.lineScale + ", lineThickness=" + String.valueOf(this.lineThickness);
    }
    
    protected static double toOutputRange(final double value) {
        return 2.0 * value - 1.0;
    }
}
