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

package com.hypixel.hytale.procedurallib.logic;

import javax.annotation.Nonnull;
import com.hypixel.hytale.procedurallib.logic.cell.evaluator.PointEvaluator;
import com.hypixel.hytale.procedurallib.logic.cell.CellDistanceFunction;
import com.hypixel.hytale.procedurallib.NoiseFunction;

public abstract class DistanceNoise implements NoiseFunction
{
    protected final CellDistanceFunction cellDistanceFunction;
    protected final PointEvaluator pointEvaluator;
    protected final Distance2Function distance2Function;
    
    public DistanceNoise(final CellDistanceFunction cellDistanceFunction, final PointEvaluator pointEvaluator, final Distance2Function distance2Function) {
        this.cellDistanceFunction = cellDistanceFunction;
        this.pointEvaluator = pointEvaluator;
        this.distance2Function = distance2Function;
    }
    
    public CellDistanceFunction getCellDistanceFunction() {
        return this.cellDistanceFunction;
    }
    
    public Distance2Function getDistance2Function() {
        return this.distance2Function;
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, double x, double y) {
        x = this.cellDistanceFunction.scale(x);
        y = this.cellDistanceFunction.scale(y);
        final int xr = this.cellDistanceFunction.getCellX(x, y);
        final int yr = this.cellDistanceFunction.getCellY(x, y);
        final ResultBuffer.ResultBuffer2d buffer = this.localBuffer2d();
        buffer.distance = Double.POSITIVE_INFINITY;
        buffer.distance2 = Double.POSITIVE_INFINITY;
        this.cellDistanceFunction.transition2D(offsetSeed, x, y, xr, yr, buffer, this.pointEvaluator);
        buffer.distance = Math.sqrt(buffer.distance);
        buffer.distance2 = Math.sqrt(buffer.distance2);
        return GeneralNoise.limit(this.distance2Function.eval(buffer.distance, buffer.distance2)) * 2.0 - 1.0;
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, double x, double y, double z) {
        x = this.cellDistanceFunction.scale(x);
        y = this.cellDistanceFunction.scale(y);
        z = this.cellDistanceFunction.scale(z);
        final int xr = this.cellDistanceFunction.getCellX(x, y, z);
        final int yr = this.cellDistanceFunction.getCellY(x, y, z);
        final int zr = this.cellDistanceFunction.getCellZ(x, y, z);
        final ResultBuffer.ResultBuffer3d buffer = this.localBuffer3d();
        buffer.distance = Double.POSITIVE_INFINITY;
        buffer.distance2 = Double.POSITIVE_INFINITY;
        this.cellDistanceFunction.transition3D(offsetSeed, x, y, z, xr, yr, zr, buffer, this.pointEvaluator);
        buffer.distance = Math.sqrt(buffer.distance);
        buffer.distance2 = Math.sqrt(buffer.distance2);
        return GeneralNoise.limit(this.distance2Function.eval(buffer.distance, buffer.distance2)) * 2.0 - 1.0;
    }
    
    protected abstract ResultBuffer.ResultBuffer2d localBuffer2d();
    
    protected abstract ResultBuffer.ResultBuffer3d localBuffer3d();
    
    @Nonnull
    @Override
    public String toString() {
        return "DistanceNoise{cellDistanceFunction=" + String.valueOf(this.cellDistanceFunction) + ", pointEvaluator=" + String.valueOf(this.pointEvaluator) + ", distance2Function=" + String.valueOf(this.distance2Function);
    }
    
    public enum Distance2Mode
    {
        ADD((Distance2Function)new Distance2Function() {
            @Override
            public double eval(final double distance, final double distance2) {
                return distance + distance2;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "AddDistance2Function{}";
            }
        }), 
        SUB((Distance2Function)new Distance2Function() {
            @Override
            public double eval(final double distance, final double distance2) {
                return distance2 - distance;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "SubDistance2Function{}";
            }
        }), 
        MUL((Distance2Function)new Distance2Function() {
            @Override
            public double eval(final double distance, final double distance2) {
                return distance * distance2;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "MulDistance2Function{}";
            }
        }), 
        DIV((Distance2Function)new Distance2Function() {
            @Override
            public double eval(final double distance, final double distance2) {
                return distance / distance2;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "DivDistance2Function{}";
            }
        }), 
        MIN((Distance2Function)new Distance2Function() {
            @Override
            public double eval(final double distance, final double distance2) {
                return distance;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "MinDistance2Function{}";
            }
        }), 
        MAX((Distance2Function)new Distance2Function() {
            @Override
            public double eval(final double distance, final double distance2) {
                return distance2;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "MaxDistance2Function{}";
            }
        });
        
        private final Distance2Function function;
        
        private Distance2Mode(final Distance2Function function) {
            this.function = function;
        }
        
        public Distance2Function getFunction() {
            return this.function;
        }
    }
    
    @FunctionalInterface
    public interface Distance2Function
    {
        double eval(final double p0, final double p1);
    }
}
