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

package com.hypixel.hytale.procedurallib.logic;

import com.hypixel.hytale.procedurallib.logic.cell.GridCellDistanceFunction;
import com.hypixel.hytale.procedurallib.condition.IIntCondition;
import com.hypixel.hytale.math.vector.Vector2i;
import com.hypixel.hytale.procedurallib.NoiseFunction;

public class MeshNoise implements NoiseFunction
{
    public static final Vector2i[] ADJACENT_CELLS;
    private final IIntCondition density;
    private final double thickness;
    private final double thicknessSquared;
    private final double jitterX;
    private final double jitterY;
    
    public MeshNoise(final IIntCondition density, final double thickness, final double jitterX, final double jitterY) {
        this.density = density;
        this.thickness = thickness;
        this.thicknessSquared = thickness * thickness;
        this.jitterX = jitterX;
        this.jitterY = jitterY;
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, final double x, final double y) {
        final double thickness = this.thickness;
        double lowest = this.thicknessSquared;
        final int _x = GeneralNoise.fastFloor(x);
        final int _y = GeneralNoise.fastFloor(y);
        final double rx = x - _x;
        final double ry = y - _y;
        for (int c = 0; c < 8; ++c) {
            switch (c) {
                case 0: {
                    if (rx >= thickness) {
                        continue;
                    }
                    if (ry >= thickness) {
                        continue;
                    }
                    break;
                }
                case 1: {
                    if (rx >= thickness) {
                        continue;
                    }
                    break;
                }
                case 2: {
                    if (rx >= thickness) {
                        continue;
                    }
                    if (ry < 1.0 - thickness) {
                        continue;
                    }
                    break;
                }
                case 3: {
                    if (ry >= thickness) {
                        continue;
                    }
                    break;
                }
                case 5: {
                    if (ry < 1.0 - thickness) {
                        continue;
                    }
                    break;
                }
                case 6: {
                    if (rx < 1.0 - thickness) {
                        continue;
                    }
                    if (ry >= thickness) {
                        continue;
                    }
                    break;
                }
                case 7: {
                    if (rx < 1.0 - thickness) {
                        continue;
                    }
                    break;
                }
            }
            final int cx = c / 3;
            final int cy = c % 3;
            final int xr = _x + cx - 1;
            final int yr = _y + cy - 1;
            final int cellHash = GridCellDistanceFunction.getHash(offsetSeed, xr, yr);
            if (this.density.eval(cellHash)) {
                final DoubleArray.Double2 cell = CellularNoise.CELL_2D[cellHash & 0xFF];
                final double cellX = cell.x * this.jitterX;
                final double cellY = cell.y * this.jitterY;
                final double centerX = xr + cellX;
                final double centerY = yr + cellY;
                final double qX = x - centerX;
                final double qY = y - centerY;
                for (final Vector2i v : MeshNoise.ADJACENT_CELLS) {
                    final int xi = xr + v.x;
                    final int yi = yr + v.y;
                    final int vecHash = GridCellDistanceFunction.getHash(offsetSeed, xi, yi);
                    if (this.density.eval(vecHash)) {
                        final DoubleArray.Double2 vec = CellularNoise.CELL_2D[vecHash & 0xFF];
                        final double vecX = vec.x * this.jitterX;
                        final double vecY = vec.y * this.jitterY;
                        final double vx = v.x + vecX - cellX;
                        final double vy = v.y + vecY - cellY;
                        double t = (qX * vx + qY * vy) / (vx * vx + vy * vy);
                        if (t < 0.0) {
                            t = 0.0;
                        }
                        else if (t > 1.0) {
                            t = 1.0;
                        }
                        final double lx = centerX + vx * t;
                        final double ly = centerY + vy * t;
                        final double dx = x - lx;
                        final double dy = y - ly;
                        final double distance = dx * dx + dy * dy;
                        if (distance < lowest) {
                            lowest = distance;
                        }
                    }
                }
            }
        }
        if (lowest != this.thicknessSquared) {
            final double distance2 = Math.sqrt(lowest);
            final double d = distance2 / thickness;
            return d * 2.0 - 1.0;
        }
        return 1.0;
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, final double x, final double y, final double z) {
        throw new UnsupportedOperationException("3d not supported");
    }
    
    static {
        ADJACENT_CELLS = new Vector2i[] { new Vector2i(-1, 0), new Vector2i(0, -1), new Vector2i(1, 0), new Vector2i(0, 1) };
    }
}
