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

package com.hypixel.hytale.procedurallib.logic;

import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.procedurallib.logic.cell.HexCellDistanceFunction;
import com.hypixel.hytale.procedurallib.logic.cell.jitter.CellJitter;
import com.hypixel.hytale.procedurallib.condition.IIntCondition;
import com.hypixel.hytale.procedurallib.NoiseFunction;

public class HexMeshNoise implements NoiseFunction
{
    protected final IIntCondition density;
    protected final double thickness;
    protected final double thicknessSquared;
    protected final CellJitter jitter;
    protected final boolean linesX;
    protected final boolean linesY;
    protected final boolean linesZ;
    
    public HexMeshNoise(final IIntCondition density, final double thickness, final CellJitter jitter, final boolean linesX, final boolean linesY, final boolean linesZ) {
        final double domainLocalThickness = HexCellDistanceFunction.DISTANCE_FUNCTION.scale(thickness);
        this.density = density;
        this.thickness = domainLocalThickness;
        this.thicknessSquared = domainLocalThickness * domainLocalThickness;
        this.jitter = jitter;
        this.linesX = linesX;
        this.linesY = linesY;
        this.linesZ = linesZ;
    }
    
    @Override
    public double get(final int seed, final int offsetSeed, double x, double y) {
        x = HexCellDistanceFunction.DISTANCE_FUNCTION.scale(x);
        y = HexCellDistanceFunction.DISTANCE_FUNCTION.scale(y);
        final int cx = HexCellDistanceFunction.toGridX(x, y);
        final int cy = HexCellDistanceFunction.toGridY(x, y);
        double nearest = this.thicknessSquared;
        nearest = this.checkConnections(offsetSeed, x, y, cx - 1, cy - 1, nearest);
        nearest = this.checkConnections(offsetSeed, x, y, cx - 1, cy + 0, nearest);
        nearest = this.checkConnections(offsetSeed, x, y, cx + 1, cy + 0, nearest);
        nearest = this.checkConnections(offsetSeed, x, y, cx + 0, cy - 1, nearest);
        nearest = this.checkConnections(offsetSeed, x, y, cx + 0, cy + 1, nearest);
        if (this.linesZ) {
            nearest = this.checkDiagonalConnections(offsetSeed, x, y, cx + 0, cy + 0, nearest);
            nearest = this.checkDiagonalConnections(offsetSeed, x, y, cx + 0, cy - 1, nearest);
            nearest = this.checkDiagonalConnections(offsetSeed, x, y, cx + 0, cy + 1, nearest);
            nearest = this.checkDiagonalConnections(offsetSeed, x, y, cx - 1, cy + 0, nearest);
            nearest = this.checkDiagonalConnections(offsetSeed, x, y, cx - 1, cy - 1, nearest);
        }
        if (nearest < this.thicknessSquared) {
            final double distance = Math.sqrt(nearest);
            final double d = distance / this.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");
    }
    
    protected double checkConnections(final int offsetSeed, final double x, final double y, final int cx, final int cy, double nearest) {
        final int hash = HexCellDistanceFunction.getHash(offsetSeed, cx, cy);
        if (!this.density.eval(hash)) {
            return nearest;
        }
        final DoubleArray.Double2 vec = HexCellDistanceFunction.HEX_CELL_2D[hash & 0xFF];
        final double px = this.jitter.getPointX(cx, vec);
        final double py = this.jitter.getPointY(cy, vec);
        final double ax = HexCellDistanceFunction.toHexX(px, py);
        final double ay = HexCellDistanceFunction.toHexY(px, py);
        final double adx = x - ax;
        final double ady = y - ay;
        if (this.linesX) {
            nearest = Math.min(nearest, this.dist2Cell(offsetSeed, x, y, adx, ady, ax, ay, cx - 1, cy));
            nearest = Math.min(nearest, this.dist2Cell(offsetSeed, x, y, adx, ady, ax, ay, cx + 1, cy));
        }
        if (this.linesY) {
            nearest = Math.min(nearest, this.dist2Cell(offsetSeed, x, y, adx, ady, ax, ay, cx, cy - 1));
            nearest = Math.min(nearest, this.dist2Cell(offsetSeed, x, y, adx, ady, ax, ay, cx, cy + 1));
        }
        return nearest;
    }
    
    protected double checkDiagonalConnections(final int offsetSeed, final double x, final double y, final int cx, final int cy, double nearest) {
        final int hash = HexCellDistanceFunction.getHash(offsetSeed, cx, cy);
        if (!this.density.eval(hash)) {
            return nearest;
        }
        final DoubleArray.Double2 vec = HexCellDistanceFunction.HEX_CELL_2D[hash & 0xFF];
        final double px = this.jitter.getPointX(cx, vec);
        final double py = this.jitter.getPointY(cy, vec);
        final double ax = HexCellDistanceFunction.toHexX(px, py);
        final double ay = HexCellDistanceFunction.toHexY(px, py);
        final double adx = x - ax;
        final double ady = y - ay;
        nearest = Math.min(nearest, this.dist2Cell(offsetSeed, x, y, adx, ady, ax, ay, cx - 1, cy + 1));
        nearest = Math.min(nearest, this.dist2Cell(offsetSeed, x, y, adx, ady, ax, ay, cx + 1, cy - 1));
        return nearest;
    }
    
    protected double dist2Cell(final int offsetSeed, final double x, final double y, final double adx, final double ady, final double ax, final double ay, final int cx, final int cy) {
        final int hash = HexCellDistanceFunction.getHash(offsetSeed, cx, cy);
        if (!this.density.eval(hash)) {
            return Double.MAX_VALUE;
        }
        final DoubleArray.Double2 vec = HexCellDistanceFunction.HEX_CELL_2D[hash & 0xFF];
        final double px = this.jitter.getPointX(cx, vec);
        final double py = this.jitter.getPointY(cy, vec);
        final double bx = HexCellDistanceFunction.toHexX(px, py);
        final double by = HexCellDistanceFunction.toHexY(px, py);
        return MathUtil.distanceToLineSq(x, y, ax, ay, bx, by, adx, ady, bx - ax, by - ay);
    }
}
