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

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

import com.hypixel.hytale.math.vector.Vector3d;
import java.util.Objects;
import javax.annotation.Nonnull;

public class Calculator
{
    public static int toIntFloored(double d) {
        d = Math.floor(d);
        return (int)d;
    }
    
    public static boolean perfectDiv(final int x, final int divisor) {
        return x % divisor == 0;
    }
    
    public static double max(@Nonnull final double... n) {
        Objects.requireNonNull(n);
        if (n.length <= 0) {
            throw new IllegalArgumentException("array can't be empty");
        }
        double max = Double.NEGATIVE_INFINITY;
        for (final double value : n) {
            if (max < value) {
                max = value;
            }
        }
        return max;
    }
    
    public static double min(@Nonnull final double... n) {
        Objects.requireNonNull(n);
        if (n.length <= 0) {
            throw new IllegalArgumentException("array can't be empty");
        }
        double min = Double.POSITIVE_INFINITY;
        for (final double value : n) {
            if (min > value) {
                min = value;
            }
        }
        return min;
    }
    
    public static int max(@Nonnull final int... n) {
        Objects.requireNonNull(n);
        if (n.length <= 0) {
            throw new IllegalArgumentException("array can't be empty");
        }
        int max = Integer.MIN_VALUE;
        for (final int value : n) {
            if (max < value) {
                max = value;
            }
        }
        return max;
    }
    
    public static int min(@Nonnull final int... n) {
        Objects.requireNonNull(n);
        if (n.length <= 0) {
            throw new IllegalArgumentException("array can't be empty");
        }
        int min = Integer.MAX_VALUE;
        for (final int value : n) {
            if (min > value) {
                min = value;
            }
        }
        return min;
    }
    
    public static int limit(final int value, final int floor, final int ceil) {
        if (floor >= ceil) {
            throw new IllegalArgumentException("floor must be smaller than ceil");
        }
        if (value < floor) {
            return floor;
        }
        return Math.min(value, ceil);
    }
    
    public static double limit(final double value, final double floor, final double ceil) {
        if (floor >= ceil) {
            throw new IllegalArgumentException("floor must be smaller than ceil");
        }
        if (value < floor) {
            return floor;
        }
        if (value > ceil) {
            return ceil;
        }
        return value;
    }
    
    public static double distance(final double x1, final double y1, final double z1, final double x2, final double y2, final double z2) {
        return Math.sqrt(Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0) + Math.pow(z2 - z1, 2.0));
    }
    
    public static double distance(@Nonnull final Vector3d a, @Nonnull final Vector3d b) {
        return Math.sqrt(Math.pow(b.x - a.x, 2.0) + Math.pow(b.y - a.y, 2.0) + Math.pow(b.z - a.z, 2.0));
    }
    
    public static double distance(final double x1, final double y1, final double x2, final double y2) {
        return Math.sqrt(Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0));
    }
    
    public static boolean isDivisibleBy(int number, final int divisor) {
        if (number == 0) {
            return false;
        }
        while (number != 1) {
            if (number % 4 != 0) {
                return false;
            }
            number >>= 2;
        }
        return true;
    }
    
    public static double clamp(final double wallA, double value, final double wallB) {
        double ceil;
        double floor;
        if (wallA > wallB) {
            ceil = wallA;
            floor = wallB;
        }
        else {
            if (wallA >= wallB) {
                return wallA;
            }
            ceil = wallB;
            floor = wallA;
        }
        if (value < floor) {
            value = floor;
        }
        else if (value > ceil || Double.isInfinite(value)) {
            value = ceil;
        }
        return value;
    }
    
    public static int clamp(final int wallA, int value, final int wallB) {
        int ceil;
        int floor;
        if (wallA > wallB) {
            ceil = wallA;
            floor = wallB;
        }
        else {
            if (wallA >= wallB) {
                return wallA;
            }
            ceil = wallB;
            floor = wallA;
        }
        if (value < floor) {
            value = floor;
        }
        else if (value > ceil) {
            value = ceil;
        }
        return value;
    }
    
    public static int toNearestInt(final double input) {
        return (int)Math.round(input);
    }
    
    public static double smoothMin(final double range, final double a, final double b) {
        if (range < 0.0) {
            throw new IllegalArgumentException("negative range");
        }
        if (range == 0.0) {
            return Math.min(a, b);
        }
        if (Math.abs(a - b) >= range) {
            return Math.min(a, b);
        }
        final double weight = clamp(0.0, 0.5 + 0.5 * (b - a) / range, 1.0);
        return Interpolation.linear(b, a, weight) - range * weight * (1.0 - weight);
    }
    
    public static double smoothMax(final double range, final double a, final double b) {
        if (range < 0.0) {
            throw new IllegalArgumentException("negative range");
        }
        if (range == 0.0) {
            return Math.max(a, b);
        }
        if (Math.abs(a - b) > range) {
            return Math.max(a, b);
        }
        final double weight = clamp(0.0, 0.5 + 0.5 * (b - a) / range, 1.0);
        return Interpolation.linear(a, b, weight) + range * weight * (1.0 - weight);
    }
    
    public static int wrap(int value, final int max) {
        value %= max;
        return (value < 0) ? (value + max) : value;
    }
    
    public static int floor(final int value, final int gridSize) {
        return (value < 0) ? (value / gridSize * gridSize - ((value % gridSize != 0) ? gridSize : 0)) : (value / gridSize * gridSize);
    }
    
    public static int ceil(final int value, final int gridSize) {
        return (value >= 0) ? ((value + gridSize - 1) / gridSize * gridSize) : (value / gridSize * gridSize);
    }
}
