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

package com.hypixel.hytale.procedurallib.property;

import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.util.TrigMathUtil;

public class GradientNoiseProperty implements NoiseProperty
{
    protected final NoiseProperty noise;
    protected final GradientMode mode;
    protected final double distance;
    protected final double invNormalize;
    
    public GradientNoiseProperty(final NoiseProperty noise, final GradientMode mode, final double distance, final double normalize) {
        this.noise = noise;
        this.mode = mode;
        this.distance = distance;
        this.invNormalize = 1.0 / distance / normalize;
    }
    
    @Override
    public double get(final int seed, final double x, final double y) {
        final double v = this.noise.get(seed, x, y);
        final double s = this.noise.get(seed, x, y + this.distance);
        final double e = this.noise.get(seed, x + this.distance, y);
        final double dx = e - v;
        final double dy = s - v;
        return switch (this.mode.ordinal()) {
            default -> throw new MatchException(null, null);
            case 1 -> getAngle(dx, dy);
            case 2 -> getAbsAngle(dx, dy);
            case 0 -> getMagnitude(dx, dy, this.invNormalize);
        };
    }
    
    @Override
    public double get(final int seed, final double x, final double y, final double z) {
        throw new UnsupportedOperationException();
    }
    
    protected static double getAngle(final double dx, final double dy) {
        float angle = TrigMathUtil.atan2(dy, dx);
        angle = (angle + 3.1415927f) / 6.2831855f;
        return convertRange(angle);
    }
    
    protected static double getAbsAngle(final double dx, final double dy) {
        final float angle = TrigMathUtil.atan2(dy, dx);
        return Math.abs(angle) / 3.1415927f;
    }
    
    protected static double getMagnitude(final double dx, final double dy, final double invNormalize) {
        final double mag = MathUtil.length(dx, dy);
        return MathUtil.clamp(mag * invNormalize, 0.0, 1.0);
    }
    
    protected static float convertRange(float angle) {
        angle += 0.125f;
        return (angle > 1.0f) ? (angle - 1.0f) : angle;
    }
    
    public enum GradientMode
    {
        MAGNITUDE, 
        ANGLE, 
        ANGLE_ABS;
    }
}
