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

package com.hypixel.hytale.builtin.hytalegenerator.framework.math;

import javax.annotation.Nonnull;
import it.unimi.dsi.fastutil.doubles.Double2DoubleFunction;
import java.util.function.Function;

public class Stepinizer implements Function<Double, Double>, Double2DoubleFunction
{
    private double stepSize;
    private double stepSizeHalf;
    private double slope;
    private double topSmooth;
    private double bottomSmooth;
    
    public Stepinizer() {
        this.setStep(1.0);
        this.setEdgeSlope(1.0);
        this.setSmooth(1.0, 1.0);
    }
    
    @Nonnull
    public Stepinizer setSmooth(final double top, final double bottom) {
        if (top <= 0.0 || bottom <= 0.0) {
            throw new IllegalArgumentException("invalid values provided");
        }
        this.topSmooth = top;
        this.bottomSmooth = bottom;
        return this;
    }
    
    @Nonnull
    public Stepinizer setEdgeSlope(final double slope) {
        if (slope < 0.0) {
            throw new IllegalArgumentException("negative slope");
        }
        this.slope = slope;
        return this;
    }
    
    @Nonnull
    public Stepinizer setStep(final double size) {
        if (size < 0.0) {
            throw new IllegalArgumentException("negative size");
        }
        this.stepSize = size;
        this.stepSizeHalf = size / 2.0;
        return this;
    }
    
    public double apply(final double x) {
        return this.get(x);
    }
    
    @Override
    public double get(final double x) {
        final double polarity = this.polarity(x);
        final double steepness = this.steepness(polarity);
        final double bottomStep = this.bottomStep(x);
        final double topStep = this.topStep(x);
        double result;
        if (polarity < 0.0) {
            result = Calculator.smoothMax(this.bottomSmooth, steepness, -1.0);
        }
        else {
            result = Calculator.smoothMin(this.topSmooth, steepness, 1.0);
        }
        result = Normalizer.normalize(-1.0, 1.0, bottomStep, topStep, result);
        return result;
    }
    
    private double closestStep(final double x) {
        final double remainder = x % this.stepSize;
        if (remainder < this.stepSizeHalf) {
            return x - remainder;
        }
        return x - remainder + this.stepSize;
    }
    
    private double topStep(final double x) {
        return x - x % this.stepSize + this.stepSize;
    }
    
    private double bottomStep(final double x) {
        return x - x % this.stepSize;
    }
    
    private double polarity(final double x) {
        final double midPoint = this.bottomStep(x) + this.stepSizeHalf;
        return (x - midPoint) / this.stepSizeHalf;
    }
    
    private double steepness(final double x) {
        return this.slope * x;
    }
}
