package net.minecraft.world.level.levelgen.synth;

import net.minecraft.util.Mth;
import javax.annotation.Nullable;
import java.util.Random;
import it.unimi.dsi.fastutil.ints.IntSortedSet;
import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
import java.util.stream.IntStream;
import net.minecraft.world.level.levelgen.WorldgenRandom;

public class PerlinNoise implements SurfaceNoise {
    private final ImprovedNoise[] noiseLevels;
    private final double highestFreqValueFactor;
    private final double highestFreqInputFactor;
    
    public PerlinNoise(final WorldgenRandom ccf, final int integer2, final int integer3) {
        this(ccf, (IntSortedSet)new IntRBTreeSet(IntStream.rangeClosed(-integer2, integer3).toArray()));
    }
    
    public PerlinNoise(final WorldgenRandom ccf, final IntSortedSet intSortedSet) {
        if (intSortedSet.isEmpty()) {
            throw new IllegalArgumentException("Need some octaves!");
        }
        final int integer4 = -intSortedSet.firstInt();
        final int integer5 = intSortedSet.lastInt();
        final int integer6 = integer4 + integer5 + 1;
        if (integer6 < 1) {
            throw new IllegalArgumentException("Total number of octaves needs to be >= 1");
        }
        final ImprovedNoise cnm7 = new ImprovedNoise(ccf);
        final int integer7 = integer5;
        this.noiseLevels = new ImprovedNoise[integer6];
        if (integer7 >= 0 && integer7 < integer6 && intSortedSet.contains(0)) {
            this.noiseLevels[integer7] = cnm7;
        }
        for (int integer8 = integer7 + 1; integer8 < integer6; ++integer8) {
            if (integer8 >= 0 && intSortedSet.contains(integer7 - integer8)) {
                this.noiseLevels[integer8] = new ImprovedNoise(ccf);
            }
            else {
                ccf.consumeCount(262);
            }
        }
        if (integer5 > 0) {
            final long long9 = (long)(cnm7.noise(0.0, 0.0, 0.0, 0.0, 0.0) * 9.223372036854776E18);
            final WorldgenRandom ccf2 = new WorldgenRandom(long9);
            for (int integer9 = integer7 - 1; integer9 >= 0; --integer9) {
                if (integer9 < integer6 && intSortedSet.contains(integer7 - integer9)) {
                    this.noiseLevels[integer9] = new ImprovedNoise(ccf2);
                }
                else {
                    ccf2.consumeCount(262);
                }
            }
        }
        this.highestFreqInputFactor = Math.pow(2.0, integer5);
        this.highestFreqValueFactor = 1.0 / (Math.pow(2.0, integer6) - 1.0);
    }
    
    public double getValue(final double double1, final double double2, final double double3) {
        return this.getValue(double1, double2, double3, 0.0, 0.0, false);
    }
    
    public double getValue(final double double1, final double double2, final double double3, final double double4, final double double5, final boolean boolean6) {
        double double6 = 0.0;
        double double7 = this.highestFreqInputFactor;
        double double8 = this.highestFreqValueFactor;
        for (final ImprovedNoise cnm22 : this.noiseLevels) {
            if (cnm22 != null) {
                double6 += cnm22.noise(wrap(double1 * double7), boolean6 ? (-cnm22.yo) : wrap(double2 * double7), wrap(double3 * double7), double4 * double7, double5 * double7) * double8;
            }
            double7 /= 2.0;
            double8 *= 2.0;
        }
        return double6;
    }
    
    @Nullable
    public ImprovedNoise getOctaveNoise(final int integer) {
        return this.noiseLevels[integer];
    }
    
    public static double wrap(final double double1) {
        return double1 - Mth.lfloor(double1 / 3.3554432E7 + 0.5) * 3.3554432E7;
    }
    
    @Override
    public double getSurfaceNoiseValue(final double double1, final double double2, final double double3, final double double4) {
        return this.getValue(double1, double2, 0.0, double3, double4, false);
    }
}
