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

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

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

public class DistortedCylinderShape extends AbstractDistortedExtrusion
{
    protected static final double PITCH_COMPENSATION_MIN = 1.0;
    protected static final double PITCH_COMPENSATION_RANGE = 3.0;
    @Nonnull
    protected final Vector3d o;
    @Nonnull
    protected final Vector3d v;
    protected final double startWidth;
    protected final double startHeight;
    protected final double midWidth;
    protected final double midHeight;
    protected final double endWidth;
    protected final double endHeight;
    
    public DistortedCylinderShape(@Nonnull final Vector3d o, @Nonnull final Vector3d v, final double startWidth, final double startHeight, final double midWidth, final double midHeight, final double endWidth, final double endHeight, final GeneralNoise.InterpolationFunction interpolation) {
        this(o, v, startWidth, startHeight, midWidth, midHeight, endWidth, endHeight, MathUtil.maxValue(startWidth, midWidth, endWidth), MathUtil.maxValue(startHeight, midHeight, endHeight), interpolation);
    }
    
    public DistortedCylinderShape(@Nonnull final Vector3d o, @Nonnull final Vector3d v, final double startWidth, final double startHeight, final double midWidth, final double midHeight, final double endWidth, final double endHeight, final double maxWidth, final double maxHeight, final GeneralNoise.InterpolationFunction interpolation) {
        super(o, v, maxWidth, maxHeight, interpolation);
        this.o = o;
        this.v = v;
        this.startWidth = startWidth;
        this.startHeight = startHeight;
        this.midWidth = midWidth;
        this.midHeight = midHeight;
        this.endWidth = endWidth;
        this.endHeight = endHeight;
    }
    
    @Nonnull
    @Override
    public Vector3d getStart() {
        return this.o.clone();
    }
    
    @Nonnull
    @Override
    public Vector3d getEnd() {
        final double x = this.o.x + this.v.x;
        final double y = this.o.y + this.v.y;
        final double z = this.o.z + this.v.z;
        return new Vector3d(x, y, z);
    }
    
    @Nonnull
    @Override
    public Vector3d getAnchor(@Nonnull final Vector3d vector, final double t, final double tv, final double th) {
        final double radiusY = this.getHeightAt(t);
        final double radiusXZ = this.getWidthAt(t);
        return CaveNodeShapeUtils.getPipeAnchor(vector, this.o, this.v, radiusXZ, radiusY, radiusXZ, t, tv, th);
    }
    
    @Override
    public double getProjection(final double x, final double z) {
        double t = (x - this.o.x) * this.v.x + (z - this.o.z) * this.v.z;
        t /= this.v.x * this.v.x + this.v.z * this.v.z;
        return t;
    }
    
    @Override
    public boolean isValidProjection(final double t) {
        return t > 0.0 && t < 1.0;
    }
    
    @Override
    public double getYAt(final double t) {
        return this.o.y + this.v.y * t;
    }
    
    @Override
    public double getWidthAt(final double t) {
        return getDimAt(t, this.startWidth, this.midWidth, this.endWidth, this.interpolation);
    }
    
    @Override
    public double getHeightAt(final double t) {
        return getDimAt(t, this.startHeight, this.midHeight, this.endHeight, this.interpolation);
    }
    
    public double getDistanceSq(double x, double z, final double t) {
        if (t <= 0.0) {
            x -= this.o.x;
            z -= this.o.z;
        }
        else if (t >= 1.0) {
            x -= this.o.x + this.v.x;
            z -= this.o.z + this.v.z;
        }
        else {
            x -= this.o.x + this.v.x * t;
            z -= this.o.z + this.v.z * t;
        }
        return x * x + z * z;
    }
    
    public double getHeightComponent(final double width, final double width2, final double dist2) {
        return Math.sqrt(width2 - dist2) / width;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "DistortedCylinderShape{origin=" + String.valueOf(this.o) + ", direction=" + String.valueOf(this.v) + ", startWidth=" + this.startWidth + ", startHeight=" + this.startHeight + ", midWidth=" + this.midWidth + ", midHeight=" + this.midHeight + ", endWidth=" + this.endWidth + ", endHeight=" + this.endHeight;
    }
    
    protected static double getDimAt(double t, final double startDim, final double midDim, final double endDim, @Nonnull final GeneralNoise.InterpolationFunction interpolation) {
        if (t <= 0.0) {
            return startDim;
        }
        if (t >= 1.0) {
            return endDim;
        }
        if (t <= 0.5) {
            t = interpolation.interpolate(t * 2.0);
            return MathUtil.lerpUnclamped(startDim, midDim, t);
        }
        t = interpolation.interpolate((t - 0.5) * 2.0);
        return MathUtil.lerpUnclamped(midDim, endDim, t);
    }
    
    protected static double getCompensationFactor(@Nonnull final Vector3d direction) {
        final double ny = direction.y / direction.length();
        final double pitch = TrigMathUtil.asin(-ny);
        return Math.abs(pitch) / 1.5707963705062866;
    }
    
    protected static double getHeightCompensation(final double factor) {
        return 1.0 + factor * factor * factor * 3.0;
    }
    
    public static class Factory implements DistortedShape.Factory
    {
        @Nonnull
        @Override
        public DistortedShape create(@Nonnull final Vector3d origin, @Nonnull final Vector3d direction, final double length, final double startWidth, double startHeight, final double midWidth, double midHeight, final double endWidth, double endHeight, final GeneralNoise.InterpolationFunction interpolation) {
            final double comp = DistortedCylinderShape.getCompensationFactor(direction);
            final double scale = DistortedCylinderShape.getHeightCompensation(comp);
            startHeight *= scale;
            midHeight *= scale;
            endHeight *= scale;
            return new DistortedCylinderShape(origin, direction, startWidth, startHeight, midWidth, midHeight, endWidth, endHeight, interpolation);
        }
    }
}
