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

package com.hypixel.hytale.server.worldgen.cave.shape.distorted;

import com.hypixel.hytale.server.worldgen.cave.CaveType;
import com.hypixel.hytale.server.worldgen.cave.shape.CaveNodeShapeUtils;
import javax.annotation.Nonnull;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.procedurallib.logic.GeneralNoise;

public class DistortedEllipsoidShape extends AbstractDistortedBody
{
    private final double radiusX;
    private final double radiusY;
    private final double radiusZ;
    private final double radiusX2;
    private final double radiusY2;
    private final double radiusZ2;
    private final double invRadiusX2;
    private final double invRadiusZ2;
    private final GeneralNoise.InterpolationFunction interpolation;
    
    public DistortedEllipsoidShape(@Nonnull final Vector3d o, final Vector3d d, final double yaw, final double pitch, final double radiusX, final double radiusY, final double radiusZ, final GeneralNoise.InterpolationFunction interpolation) {
        super(o, d, yaw, pitch, radiusX, radiusY, radiusZ);
        this.radiusX = radiusX;
        this.radiusY = radiusY;
        this.radiusZ = radiusZ;
        this.radiusX2 = radiusX * radiusX;
        this.radiusY2 = radiusY * radiusY;
        this.radiusZ2 = radiusZ * radiusZ;
        this.invRadiusX2 = 1.0 / this.radiusX2;
        this.invRadiusZ2 = 1.0 / this.radiusZ2;
        this.interpolation = interpolation;
    }
    
    @Nonnull
    @Override
    public Vector3d getAnchor(@Nonnull final Vector3d vector, final double tx, final double ty, final double tz) {
        return CaveNodeShapeUtils.getSphereAnchor(vector, this.o, this.radiusX, this.radiusY, this.radiusZ, tx, ty, tz);
    }
    
    @Override
    public double getProjection(final double x, final double z) {
        return 0.0;
    }
    
    @Override
    public boolean isValidProjection(final double t) {
        return true;
    }
    
    @Override
    public double getYAt(final double t) {
        return this.o.y;
    }
    
    @Override
    public double getWidthAt(final double t) {
        return Math.min(this.radiusX, this.radiusZ);
    }
    
    @Override
    public double getHeightAt(final double t) {
        return this.radiusY;
    }
    
    @Override
    protected double getHeight(final int seed, final double x, final double z, final double t, final double centerY, final CaveType caveType, @Nonnull final ShapeDistortion distortion) {
        final double dx = x - this.o.x;
        final double dz = z - this.o.z;
        final double dx2 = dx * dx;
        if (dx2 > this.radiusX2) {
            return 0.0;
        }
        final double dz2 = dz * dz;
        if (dz2 > this.radiusZ2) {
            return 0.0;
        }
        final double qx = this.interpolation.interpolate(dx2 * this.invRadiusX2);
        final double qz = this.interpolation.interpolate(dz2 * this.invRadiusZ2);
        double qh = qx + qz;
        final double noise = distortion.getWidthFactor(seed, x, z);
        if (noise > 0.0) {
            qh /= noise;
        }
        final double y2 = (1.0 - qh) * this.radiusY2;
        if (y2 <= 0.0) {
            return 0.0;
        }
        return Math.sqrt(y2);
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "DistortedEllipsoidShape{origin=" + String.valueOf(this.o) + ", direction=" + String.valueOf(this.v) + ", radiusX=" + this.radiusX + ", radiusY=" + this.radiusY + ", radiusZ=" + this.radiusZ;
    }
    
    private static double wrapPitch(final double pitch, final double radiusY, final double radiusZ) {
        final double min = Math.min(radiusY, radiusZ);
        final double max = Math.max(radiusY, radiusZ);
        final double aspect = 1.0 - min / max;
        if (pitch < -0.7853981852531433) {
            final double alpha = 1.0 - Math.abs((pitch + 0.7853981852531433) / 0.7853981852531433);
            return -1.5707963705062866 * aspect * alpha;
        }
        if (pitch > 0.7853981852531433) {
            final double alpha = 1.0 - Math.abs((pitch - 0.7853981852531433) / 0.7853981852531433);
            return 1.5707963705062866 * aspect * alpha;
        }
        return pitch;
    }
    
    public static class Factory extends AbstractDistortedBody.Factory
    {
        @Nonnull
        @Override
        protected DistortedShape createShape(@Nonnull final Vector3d origin, final Vector3d direction, final double yaw, double pitch, final double radiusX, double radiusY, double radiusZ, final GeneralNoise.InterpolationFunction interpolation) {
            if (pitch < -0.7853981852531433) {
                final double ry = radiusY;
                radiusY = radiusZ;
                radiusZ = ry;
                pitch = DistortedEllipsoidShape.wrapPitch(pitch, radiusY, radiusZ);
            }
            else if (pitch > 0.7853981852531433) {
                final double ry = radiusY;
                radiusY = radiusZ;
                radiusZ = ry;
                pitch = DistortedEllipsoidShape.wrapPitch(pitch, radiusY, radiusZ);
            }
            else {
                final double alpha = 1.0 - Math.abs(pitch / 1.5707963705062866);
                radiusY /= alpha;
                radiusZ *= alpha;
            }
            return new DistortedEllipsoidShape(origin, direction, yaw, pitch, radiusX, radiusY, radiusZ, interpolation);
        }
    }
}
