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

package com.hypixel.hytale.procedurallib.json;

import com.hypixel.hytale.procedurallib.logic.ResultBuffer;
import com.hypixel.hytale.procedurallib.logic.cell.HexCellDistanceFunction;
import com.hypixel.hytale.procedurallib.logic.cell.GridCellDistanceFunction;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.hypixel.hytale.procedurallib.supplier.DoubleRange;
import com.hypixel.hytale.procedurallib.logic.cell.evaluator.BranchEvaluator;
import com.hypixel.hytale.procedurallib.logic.cell.evaluator.DensityPointEvaluator;
import com.hypixel.hytale.procedurallib.condition.ConstantIntCondition;
import com.hypixel.hytale.procedurallib.condition.IDoubleCondition;
import com.hypixel.hytale.procedurallib.logic.cell.DistanceCalculationMode;
import com.hypixel.hytale.procedurallib.logic.cell.jitter.CellJitter;
import javax.annotation.Nonnull;
import com.hypixel.hytale.procedurallib.logic.cell.CellPointFunction;
import com.hypixel.hytale.procedurallib.property.NoiseFormulaProperty;
import com.hypixel.hytale.procedurallib.logic.DistanceNoise;
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.logic.cell.CellType;
import com.google.gson.JsonElement;
import java.nio.file.Path;
import com.hypixel.hytale.procedurallib.logic.BranchNoise;

public class BranchNoiseJsonLoader<T extends SeedResource> extends AbstractCellJitterJsonLoader<T, BranchNoise>
{
    public BranchNoiseJsonLoader(final SeedString<T> seed, final Path dataFolder, final JsonElement json) {
        super(seed, dataFolder, json);
    }
    
    @Nonnull
    @Override
    public BranchNoise load() {
        final T resource = (T)this.seed.get();
        final CellType parentCellType = this.loadParentCellType();
        final CellDistanceFunction parentFunction = getCellDistanceFunction(parentCellType);
        final PointEvaluator parentEvaluator = this.loadParentEvaluator();
        final double parentValue = this.loadDouble("ParentValue", 0.0);
        final IDoubleRange parentFade = this.loadRange("ParentFade", 0.0);
        final IIntCondition parentDensity = this.loadParentDensity();
        final DistanceNoise.Distance2Function parentDistanceType = this.loadParentDistance2Function();
        final NoiseFormulaProperty.NoiseFormula.Formula parentFormula = this.loadParentFormula();
        final CellType lineCellType = this.loadLineCellType();
        final CellPointFunction linePointFunction = getCellPointFunction(lineCellType);
        final double lineScale = this.loadDouble("LineScale", 0.1);
        final IDoubleRange lineThickness = this.loadRange("LineThickness", 0.1);
        final CellDistanceFunction lineFunction = getCellDistanceFunction(lineCellType);
        final PointEvaluator lineEvaluator = this.loadLineEvaluator(parentFunction, linePointFunction, lineScale);
        return new LoadedBranchNoise(parentFunction, parentEvaluator, parentValue, parentFade, parentDensity, parentDistanceType, parentFormula, lineFunction, lineEvaluator, lineScale, lineThickness, resource);
    }
    
    protected CellType loadParentCellType() {
        return this.loadEnum("ParentType", CellType::valueOf, Constant.DEFAULT_PARENT_CELL_TYPE);
    }
    
    protected CellType loadLineCellType() {
        return this.loadEnum("LineType", CellType::valueOf, Constant.DEFAULT_LINE_CELL_TYPE);
    }
    
    protected PointEvaluator loadParentEvaluator() {
        final double defaultJitter = this.loadDouble("ParentJitter", 1.0);
        final double jitterX = this.loadDouble("ParentJitterX", defaultJitter);
        final double jitterY = this.loadDouble("ParentJitterY", defaultJitter);
        final CellJitter jitter = CellJitter.of(jitterX, jitterY, 1.0);
        final DistanceCalculationMode distanceMode = this.loadEnum("ParentDistanceMode", DistanceCalculationMode::valueOf, Constant.DEFAULT_PARENT_DISTANCE_CAL_MODE);
        return PointEvaluator.of(distanceMode.getFunction(), null, null, jitter);
    }
    
    @Nonnull
    protected IIntCondition loadParentDensity() {
        IIntCondition density = ConstantIntCondition.DEFAULT_TRUE;
        if (this.has("ParentDensity")) {
            final IDoubleCondition densityRange = new DoubleConditionJsonLoader(this.seed, this.dataFolder, this.get("ParentDensity")).load();
            density = DensityPointEvaluator.getDensityCondition(densityRange);
        }
        return density;
    }
    
    protected DistanceNoise.Distance2Function loadParentDistance2Function() {
        return this.loadEnum("ParentDistanceType", DistanceNoise.Distance2Mode::valueOf, Constant.DEFAULT_PARENT_DISTANCE_TYPE).getFunction();
    }
    
    protected NoiseFormulaProperty.NoiseFormula.Formula loadParentFormula() {
        return this.loadEnum("ParentFormula", NoiseFormulaProperty.NoiseFormula::valueOf, Constant.DEFAULT_PARENT_FORMULA).getFormula();
    }
    
    @Nonnull
    protected PointEvaluator loadLineEvaluator(@Nonnull final CellDistanceFunction parentFunction, @Nonnull final CellPointFunction linePointFunction, final double lineScale) {
        final double defaultJitter = this.loadDouble("LineJitter", 1.0);
        final double jitterX = this.loadDouble("LineJitterX", defaultJitter);
        final double jitterY = this.loadDouble("LineJitterY", defaultJitter);
        final CellJitter jitter = CellJitter.of(jitterX, jitterY, 1.0);
        final BranchEvaluator.Direction direction = this.loadEnum("LineDirection", BranchEvaluator.Direction::valueOf, Constant.DEFAULT_LINE_DIRECTION);
        return new BranchEvaluator(parentFunction, linePointFunction, direction, jitter, lineScale);
    }
    
    protected double loadDouble(final String key, final double def) {
        if (!this.has(key)) {
            return def;
        }
        return this.get(key).getAsDouble();
    }
    
    @Nullable
    protected IDoubleRange loadRange(final String key, final double def) {
        if (!this.has(key)) {
            return new DoubleRange.Constant(def);
        }
        return new DoubleRangeJsonLoader(this.seed, this.dataFolder, this.get(key)).load();
    }
    
    protected <E extends Enum<E>> E loadEnum(final String key, @Nonnull final Function<String, E> valueOf, final E def) {
        if (!this.has(key)) {
            return def;
        }
        return valueOf.apply(this.get(key).getAsString());
    }
    
    @Nonnull
    protected static CellDistanceFunction getCellDistanceFunction(@Nonnull final CellType cellType) {
        return switch (cellType) {
            default -> throw new MatchException(null, null);
            case SQUARE -> GridCellDistanceFunction.DISTANCE_FUNCTION;
            case HEX -> HexCellDistanceFunction.DISTANCE_FUNCTION;
        };
    }
    
    @Nonnull
    protected static CellPointFunction getCellPointFunction(@Nonnull final CellType cellType) {
        return switch (cellType) {
            default -> throw new MatchException(null, null);
            case SQUARE -> GridCellDistanceFunction.POINT_FUNCTION;
            case HEX -> HexCellDistanceFunction.POINT_FUNCTION;
        };
    }
    
    protected static class LoadedBranchNoise extends BranchNoise
    {
        protected final SeedResource seedResource;
        
        public LoadedBranchNoise(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, final SeedResource seedResource) {
            super(parentFunction, parentEvaluator, parentValue, parentFade, parentDensity, distance2Function, noiseFormula, lineFunction, lineEvaluator, lineScale, lineThickness);
            this.seedResource = seedResource;
        }
        
        @Nonnull
        @Override
        protected ResultBuffer.ResultBuffer2d localBuffer2d() {
            return this.seedResource.localBuffer2d();
        }
        
        @Nonnull
        @Override
        public String toString() {
            return "LoadedBranchNoise{seedResource=" + String.valueOf(this.seedResource) + ", 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);
        }
    }
    
    public interface Constant
    {
        public static final String KEY_PARENT_TYPE = "ParentType";
        public static final String KEY_PARENT_DISTANCE_CALCULATION_MODE = "ParentDistanceMode";
        public static final String KEY_PARENT_DISTANCE_TYPE = "ParentDistanceType";
        public static final String KEY_PARENT_FORMULA = "ParentFormula";
        public static final String KEY_PARENT_JITTER = "ParentJitter";
        public static final String KEY_PARENT_JITTER_X = "ParentJitterX";
        public static final String KEY_PARENT_JITTER_Y = "ParentJitterY";
        public static final String KEY_PARENT_VALUE = "ParentValue";
        public static final String KEY_PARENT_FADE = "ParentFade";
        public static final String KEY_PARENT_DENSITY = "ParentDensity";
        public static final String KEY_LINE_TYPE = "LineType";
        public static final String KEY_LINE_DIRECTION_MODE = "LineDirection";
        public static final String KEY_LINE_SCALE = "LineScale";
        public static final String KEY_LINE_JITTER = "LineJitter";
        public static final String KEY_LINE_JITTER_X = "LineJitterX";
        public static final String KEY_LINE_JITTER_Y = "LineJitterY";
        public static final String KEY_LINE_THICKNESS = "LineThickness";
        public static final double DEFAULT_JITTER = 1.0;
        public static final double DEFAULT_PARENT_VALUE = 0.0;
        public static final double DEFAULT_PARENT_FADE = 0.0;
        public static final double DEFAULT_LINE_SCALE = 0.1;
        public static final double DEFAULT_LINE_THICKNESS = 0.1;
        public static final CellType DEFAULT_PARENT_CELL_TYPE = CellType.SQUARE;
        public static final CellType DEFAULT_LINE_CELL_TYPE = CellType.SQUARE;
        public static final BranchEvaluator.Direction DEFAULT_LINE_DIRECTION = BranchEvaluator.Direction.OUTWARD;
        public static final DistanceCalculationMode DEFAULT_PARENT_DISTANCE_CAL_MODE = DistanceCalculationMode.EUCLIDEAN;
        public static final DistanceNoise.Distance2Mode DEFAULT_PARENT_DISTANCE_TYPE = DistanceNoise.Distance2Mode.DIV;
        public static final NoiseFormulaProperty.NoiseFormula DEFAULT_PARENT_FORMULA = NoiseFormulaProperty.NoiseFormula.SQRT;
    }
}
