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

package com.hypixel.hytale.server.worldgen.climate;

import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.procedurallib.logic.cell.CellDistanceFunction;
import com.hypixel.hytale.procedurallib.logic.cell.evaluator.PointEvaluator;
import com.hypixel.hytale.procedurallib.logic.ResultBuffer;
import com.hypixel.hytale.procedurallib.property.NoiseProperty;
import javax.annotation.Nonnull;

public class ClimateNoise
{
    @Nonnull
    public final Grid grid;
    @Nonnull
    public final NoiseProperty continent;
    @Nonnull
    public final NoiseProperty temperature;
    @Nonnull
    public final NoiseProperty intensity;
    @Nonnull
    public final Thresholds thresholds;
    
    public ClimateNoise(@Nonnull final Grid grid, @Nonnull final NoiseProperty continent, @Nonnull final NoiseProperty temperature, @Nonnull final NoiseProperty intensity, @Nonnull final Thresholds thresholds) {
        this.grid = grid;
        this.temperature = temperature;
        this.intensity = intensity;
        this.continent = continent;
        this.thresholds = thresholds;
    }
    
    public int generate(final int seed, final double x, final double y, @Nonnull final Buffer buffer, @Nonnull final ClimateGraph climate) {
        this.grid.eval(seed, x, y, buffer.pos);
        final double c = this.continent.get(seed, x, y);
        final double t = this.temperature.get(seed, buffer.pos.x, buffer.pos.y);
        final double i = this.intensity.get(seed, buffer.pos.x, buffer.pos.y);
        final int index = climate.indexOf(t, i);
        buffer.continent = c;
        buffer.temperature = t;
        buffer.intensity = i;
        buffer.fade = climate.getFade(index);
        final int id = climate.getId(index);
        final int flags = getContinentFlags(c, this.thresholds);
        return id | flags;
    }
    
    private static int getContinentFlags(final double value, @Nonnull final Thresholds thresholds) {
        final boolean isLand = value <= thresholds.landShallowOceanOuter;
        final boolean isIsland = value >= thresholds.islandShallowOceanOuter;
        final boolean isOcean = value > thresholds.land && value < thresholds.island;
        final boolean isShore = (isLand && value > thresholds.landShoreInner) || (isIsland && value < thresholds.islandShoreInner);
        int flags = 0;
        if (isOcean) {
            flags |= Integer.MIN_VALUE;
        }
        if (isShore) {
            flags |= 0x40000000;
        }
        if (isIsland) {
            flags |= 0x20000000;
        }
        return flags;
    }
    
    public static class Buffer
    {
        public double continent;
        public double temperature;
        public double intensity;
        public double fade;
        public final ResultBuffer.ResultBuffer2d pos;
        
        public Buffer() {
            this.continent = 0.0;
            this.temperature = 0.0;
            this.intensity = 0.0;
            this.fade = 0.0;
            this.pos = new ResultBuffer.ResultBuffer2d();
        }
    }
    
    public static class Grid
    {
        public final int seedOffset;
        public final double scale;
        @Nonnull
        public final PointEvaluator evaluator;
        @Nonnull
        public final CellDistanceFunction grid;
        public final transient double invScale;
        
        public Grid(final int seedOffset, final double scale, @Nonnull final CellDistanceFunction grid, @Nonnull final PointEvaluator evaluator) {
            this.seedOffset = seedOffset;
            this.scale = scale;
            this.evaluator = evaluator;
            this.grid = grid;
            this.invScale = 1.0 / scale;
        }
        
        public void eval(final int seed, double x, double y, final ResultBuffer.ResultBuffer2d buffer) {
            x *= this.scale;
            y *= this.scale;
            buffer.distance = Double.MAX_VALUE;
            buffer.distance2 = Double.MAX_VALUE;
            this.grid.nearest2D(seed + this.seedOffset, x, y, MathUtil.floor(x), MathUtil.floor(y), buffer, this.evaluator);
            buffer.x *= this.invScale;
            buffer.y *= this.invScale;
        }
    }
    
    public static class Thresholds
    {
        public static final double LAND_DEFAULT = 0.5;
        public static final double ISLAND_DEFAULT = 0.8;
        public static final double BEACH_SIZE_DEFAULT = 0.05;
        public static final double SHALLOW_OCEAN_SIZE_DEFAULT = 0.15;
        public final double land;
        public final double island;
        public final double beachSize;
        public final double shallowOceanSize;
        public final transient double landShoreInner;
        public final transient double islandShoreInner;
        public final transient double landShallowOceanOuter;
        public final transient double islandShallowOceanOuter;
        
        public Thresholds(final double land, final double island, final double beach, final double shore) {
            this.land = land;
            this.island = island;
            this.beachSize = beach;
            this.shallowOceanSize = shore;
            this.landShoreInner = land - beach;
            this.islandShoreInner = island + beach;
            this.landShallowOceanOuter = land + shore;
            this.islandShallowOceanOuter = island - shore * 0.5;
        }
    }
}
