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

package com.hypixel.hytale.procedurallib.property;

import com.hypixel.hytale.procedurallib.logic.GeneralNoise;
import javax.annotation.Nonnull;
import com.hypixel.hytale.procedurallib.NoiseFunction3d;
import com.hypixel.hytale.procedurallib.NoiseFunction2d;
import com.hypixel.hytale.procedurallib.NoiseFunction;

public class FractalNoiseProperty implements NoiseProperty
{
    protected final int seedOffset;
    protected final NoiseFunction function;
    protected final FractalFunction fractalFunction;
    protected final int octaves;
    protected final double lacunarity;
    protected final double persistence;
    
    public FractalNoiseProperty(final int seedOffset, final NoiseFunction function, final FractalFunction fractalFunction, final int octaves, final double lacunarity, final double persistence) {
        this.seedOffset = seedOffset;
        this.function = function;
        this.fractalFunction = fractalFunction;
        this.octaves = octaves;
        this.lacunarity = lacunarity;
        this.persistence = persistence;
    }
    
    public int getSeedOffset() {
        return this.seedOffset;
    }
    
    public NoiseFunction getFunction() {
        return this.function;
    }
    
    public FractalFunction getFractalFunction() {
        return this.fractalFunction;
    }
    
    public int getOctaves() {
        return this.octaves;
    }
    
    public double getLacunarity() {
        return this.lacunarity;
    }
    
    public double getPersistence() {
        return this.persistence;
    }
    
    @Override
    public double get(final int seed, final double x, final double y) {
        return this.fractalFunction.get(seed, seed + this.seedOffset, x, y, this.octaves, this.lacunarity, this.persistence, this.function);
    }
    
    @Override
    public double get(final int seed, final double x, final double y, final double z) {
        return this.fractalFunction.get(seed, seed + this.seedOffset, x, y, z, this.octaves, this.lacunarity, this.persistence, this.function);
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "FractalNoiseProperty{seedOffset=" + this.seedOffset + ", function=" + String.valueOf(this.function) + ", fractalFunction=" + String.valueOf(this.fractalFunction) + ", octaves=" + this.octaves + ", lacunarity=" + this.lacunarity + ", persistence=" + this.persistence;
    }
    
    public enum FractalMode
    {
        FBM((FractalFunction)new FractalFunction() {
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction2d noise) {
                double sum = noise.get(seed, offsetSeed, x, y);
                double amp = 1.0;
                for (int i = 1; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    amp *= persistence;
                    sum += noise.get(seed, ++offsetSeed, x, y) * amp;
                }
                return GeneralNoise.limit(sum * 0.5 + 0.5);
            }
            
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, double z, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction3d noise) {
                double sum = noise.get(seed, offsetSeed, x, y, z);
                double amp = 1.0;
                for (int i = 1; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    z *= lacunarity;
                    amp *= persistence;
                    sum += noise.get(seed, ++offsetSeed, x, y, z) * amp;
                }
                return GeneralNoise.limit(sum * 0.5 + 0.5);
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "FbmFractalFunction{}";
            }
        }), 
        BILLOW((FractalFunction)new FractalFunction() {
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction2d noise) {
                double sum = Math.abs(noise.get(seed, offsetSeed, x, y)) * 2.0 - 1.0;
                double amp = 1.0;
                for (int i = 1; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    amp *= persistence;
                    sum += (Math.abs(noise.get(seed, ++offsetSeed, x, y)) * 2.0 - 1.0) * amp;
                }
                return GeneralNoise.limit(sum * 0.5 + 0.5);
            }
            
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, double z, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction3d noise) {
                double sum = Math.abs(noise.get(seed, offsetSeed, x, y, z)) * 2.0 - 1.0;
                double amp = 1.0;
                for (int i = 1; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    z *= lacunarity;
                    amp *= persistence;
                    sum += (Math.abs(noise.get(seed, ++offsetSeed, x, y, z)) * 2.0 - 1.0) * amp;
                }
                return GeneralNoise.limit(sum * 0.5 + 0.5);
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "BillowFractalFunction{}";
            }
        }), 
        MULTI_RIGID((FractalFunction)new FractalFunction() {
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction2d noise) {
                double sum = 1.0 - Math.abs(noise.get(seed, offsetSeed, x, y));
                double amp = 1.0;
                for (int i = 1; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    amp *= persistence;
                    sum -= (1.0 - Math.abs(noise.get(seed, ++offsetSeed, x, y))) * amp;
                }
                return GeneralNoise.limit(sum * 0.5 + 0.5);
            }
            
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, double z, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction3d noise) {
                double sum = 1.0 - Math.abs(noise.get(seed, offsetSeed, x, y, z));
                float amp = 1.0f;
                for (int i = 1; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    z *= lacunarity;
                    amp *= (float)persistence;
                    sum -= (1.0 - Math.abs(noise.get(seed, ++offsetSeed, x, y, z))) * amp;
                }
                return GeneralNoise.limit(sum * 0.5 + 0.5);
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "MultiRigidFractalFunction{}";
            }
        }), 
        OLDSCHOOL((FractalFunction)new FractalFunction() {
            @Override
            public double get(int seed, int offsetSeed, final double x, final double y, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction2d noise) {
                double maxAmp = 0.0;
                double amp = 1.0;
                int freq = 1;
                double sum = 0.0;
                --seed;
                for (int i = 0; i < octaves; ++i) {
                    sum += noise.get(seed, offsetSeed++, x * freq, y * freq) * amp;
                    maxAmp += amp;
                    amp *= persistence;
                    freq <<= 1;
                }
                sum /= maxAmp;
                sum *= 0.5;
                return sum + 0.5;
            }
            
            @Override
            public double get(int seed, int offsetSeed, final double x, final double y, final double z, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction3d noise) {
                double maxAmp = 0.0;
                double amp = 1.0;
                int freq = 1;
                double sum = 0.0;
                --seed;
                for (int i = 0; i < octaves; ++i) {
                    sum += noise.get(seed, offsetSeed++, x * freq, y * freq, z * freq) * amp;
                    maxAmp += amp;
                    amp *= persistence;
                    freq <<= 1;
                }
                sum /= maxAmp;
                sum *= 0.5;
                return sum + 0.5;
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "OldschoolFractalFunction{}";
            }
        }), 
        MIN((FractalFunction)new FractalFunction() {
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction2d noise) {
                double min = noise.get(seed, offsetSeed, x, y);
                for (int i = 0; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    final double d = noise.get(seed, ++offsetSeed, x, y);
                    if (d < min) {
                        min = d;
                    }
                }
                return GeneralNoise.limit(min * 0.5 + 0.5);
            }
            
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final double z, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction3d noise) {
                double min = noise.get(seed, offsetSeed, x, y, z);
                for (int i = 0; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    final double d = noise.get(seed, ++offsetSeed, x, y, z);
                    if (d < min) {
                        min = d;
                    }
                }
                return GeneralNoise.limit(min * 0.5 + 0.5);
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "MinFractalFunction{}";
            }
        }), 
        MAX((FractalFunction)new FractalFunction() {
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction2d noise) {
                double max = noise.get(seed, offsetSeed, x, y);
                for (int i = 0; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    final double d = noise.get(seed, ++offsetSeed, x, y);
                    if (d > max) {
                        max = d;
                    }
                }
                return GeneralNoise.limit(max * 0.5 + 0.5);
            }
            
            @Override
            public double get(final int seed, int offsetSeed, double x, double y, final double z, final int octaves, final double lacunarity, final double persistence, @Nonnull final NoiseFunction3d noise) {
                double max = noise.get(seed, offsetSeed, x, y, z);
                for (int i = 0; i < octaves; ++i) {
                    x *= lacunarity;
                    y *= lacunarity;
                    final double d = noise.get(seed, ++offsetSeed, x, y, z);
                    if (d > max) {
                        max = d;
                    }
                }
                return GeneralNoise.limit(max * 0.5 + 0.5);
            }
            
            @Nonnull
            @Override
            public String toString() {
                return "MaxFractalFunction{}";
            }
        });
        
        private final FractalFunction function;
        
        private FractalMode(final FractalFunction function) {
            this.function = function;
        }
        
        public FractalFunction getFunction() {
            return this.function;
        }
    }
    
    private interface FractalFunction
    {
        double get(final int p0, final int p1, final double p2, final double p3, final int p4, final double p5, final double p6, final NoiseFunction2d p7);
        
        double get(final int p0, final int p1, final double p2, final double p3, final double p4, final int p5, final double p6, final double p7, final NoiseFunction3d p8);
    }
}
