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

package com.hypixel.hytale.server.core.modules.collision;

import java.util.function.Supplier;
import com.hypixel.hytale.math.shape.Box;
import javax.annotation.Nonnull;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.math.vector.Vector2d;

public class CollisionMath
{
    public static final ThreadLocal<Vector2d> MIN_MAX;
    public static final int DISJOINT = 0;
    public static final int TOUCH_X = 1;
    public static final int TOUCH_Y = 2;
    public static final int TOUCH_Z = 4;
    public static final int TOUCH_ANY = 7;
    public static final int OVERLAP_X = 8;
    public static final int OVERLAP_Y = 16;
    public static final int OVERLAP_Z = 32;
    public static final int OVERLAP_ANY = 56;
    public static final int OVERLAP_ALL = 56;
    
    public CollisionMath() {
        throw new IllegalStateException("CollisionMath can't be instantiated");
    }
    
    public static boolean intersectVectorAABB(@Nonnull final Vector3d pos, @Nonnull final Vector3d vec, final double x, final double y, final double z, @Nonnull final Box box, @Nonnull final Vector2d minMax) {
        return intersectRayAABB(pos, vec, x, y, z, box, minMax) && minMax.x <= 1.0;
    }
    
    public static boolean intersectRayAABB(@Nonnull final Vector3d pos, @Nonnull final Vector3d ray, final double x, final double y, final double z, @Nonnull final Box box, @Nonnull final Vector2d minMax) {
        minMax.x = 0.0;
        minMax.y = Double.MAX_VALUE;
        final Vector3d min = box.getMin();
        final Vector3d max = box.getMax();
        return intersect1D(pos.x, ray.getX(), x + min.x, x + max.x, minMax) && intersect1D(pos.y, ray.getY(), y + min.y, y + max.y, minMax) && intersect1D(pos.z, ray.getZ(), z + min.z, z + max.z, minMax) && minMax.x >= 0.0;
    }
    
    public static double intersectRayAABB(@Nonnull final Vector3d pos, @Nonnull final Vector3d ray, final double x, final double y, final double z, @Nonnull final Box box) {
        final Vector2d minMax = CollisionMath.MIN_MAX.get();
        return intersectRayAABB(pos, ray, x, y, z, box, minMax) ? minMax.x : -1.7976931348623157E308;
    }
    
    public static boolean intersectVectorAABB(@Nonnull final Vector3d pos, @Nonnull final Vector3d vec, final double x, final double y, final double z, final double radius, final double height, @Nonnull final Vector2d minMax) {
        return intersectRayAABB(pos, vec, x, y, z, radius, height, minMax) && minMax.x <= 1.0;
    }
    
    public static boolean intersectRayAABB(@Nonnull final Vector3d pos, @Nonnull final Vector3d ray, final double x, final double y, final double z, final double radius, final double height, @Nonnull final Vector2d minMax) {
        minMax.x = 0.0;
        minMax.y = Double.MAX_VALUE;
        return intersect1D(pos.x, ray.getX(), x - radius, x + radius, minMax) && intersect1D(pos.y, ray.getY(), y, y + height, minMax) && intersect1D(pos.z, ray.getZ(), z - radius, z + radius, minMax) && minMax.x >= 0.0;
    }
    
    public static boolean intersectSweptAABBs(@Nonnull final Vector3d posP, @Nonnull final Vector3d vP, @Nonnull final Box p, @Nonnull final Vector3d posQ, @Nonnull final Box q, @Nonnull final Vector2d minMax, @Nonnull final Box temp) {
        return intersectSweptAABBs(posP, vP, p, posQ.x, posQ.y, posQ.z, q, minMax, temp);
    }
    
    public static boolean intersectSweptAABBs(@Nonnull final Vector3d posP, @Nonnull final Vector3d vP, @Nonnull final Box p, final double qx, final double qy, final double qz, @Nonnull final Box q, @Nonnull final Vector2d minMax, @Nonnull final Box temp) {
        temp.assign(q).minkowskiSum(p);
        return intersectVectorAABB(posP, vP, qx, qy, qz, temp, minMax);
    }
    
    public static boolean intersect1D(final double p, final double s, final double min, final double max, @Nonnull final Vector2d minMax) {
        if (Math.abs(s) < 1.0E-5) {
            return p >= min && p <= max;
        }
        final double t1 = (min - p) / s;
        final double t2 = (max - p) / s;
        if (t2 >= t1) {
            if (t1 > minMax.x) {
                minMax.x = t1;
            }
            if (t2 < minMax.y) {
                minMax.y = t2;
            }
        }
        else {
            if (t2 > minMax.x) {
                minMax.x = t2;
            }
            if (t1 < minMax.y) {
                minMax.y = t1;
            }
        }
        return minMax.x <= minMax.y;
    }
    
    public static boolean isDisjoint(final int code) {
        return code == 0;
    }
    
    public static boolean isOverlapping(final int code) {
        return code == 56;
    }
    
    public static boolean isTouching(final int code) {
        return (code & 0x7) != 0x0;
    }
    
    public static int intersectAABBs(@Nonnull final Vector3d p, @Nonnull final Box bbP, @Nonnull final Vector3d q, @Nonnull final Box bbQ) {
        return intersectAABBs(p.x, p.y, p.z, bbP, q.x, q.y, q.z, bbQ);
    }
    
    public static int intersectAABBs(final double px, final double py, final double pz, @Nonnull final Box bbP, final double qx, final double qy, final double qz, @Nonnull final Box bbQ) {
        int x = intersect1D(px, bbP.min.x, bbP.max.x, qx, bbQ.min.x, bbQ.max.x);
        if (x == 0) {
            return 0;
        }
        x &= 0x9;
        int y = intersect1D(py, bbP.min.y, bbP.max.y, qy, bbQ.min.y, bbQ.max.y);
        if (y == 0) {
            return 0;
        }
        y &= 0x12;
        int z = intersect1D(pz, bbP.min.z, bbP.max.z, qz, bbQ.min.z, bbQ.max.z);
        if (z == 0) {
            return 0;
        }
        z &= 0x24;
        return x | y | z;
    }
    
    public static int intersect1D(final double p, final double pMin, final double pMax, final double q, final double qMin, final double qMax) {
        return intersect1D(p, pMin, pMax, q, qMin, qMax, 1.0E-5);
    }
    
    public static int intersectAABBs(final double px, final double py, final double pz, @Nonnull final Box bbP, final double qx, final double qy, final double qz, @Nonnull final Box bbQ, final double thickness) {
        int x = intersect1D(px, bbP.min.x, bbP.max.x, qx, bbQ.min.x, bbQ.max.x, thickness);
        if (x == 0) {
            return 0;
        }
        x &= 0x9;
        int y = intersect1D(py, bbP.min.y, bbP.max.y, qy, bbQ.min.y, bbQ.max.y, thickness);
        if (y == 0) {
            return 0;
        }
        y &= 0x12;
        int z = intersect1D(pz, bbP.min.z, bbP.max.z, qz, bbQ.min.z, bbQ.max.z, thickness);
        if (z == 0) {
            return 0;
        }
        z &= 0x24;
        return x | y | z;
    }
    
    public static int intersect1D(final double p, final double pMin, final double pMax, final double q, final double qMin, final double qMax, final double thickness) {
        final double offset = q - p;
        double dist = pMin - qMax - offset;
        if (dist > thickness) {
            return 0;
        }
        if (dist > -thickness) {
            return 7;
        }
        dist = qMin - pMax + offset;
        if (dist > thickness) {
            return 0;
        }
        if (dist > -thickness) {
            return 7;
        }
        return 56;
    }
    
    static {
        MIN_MAX = ThreadLocal.withInitial((Supplier<? extends Vector2d>)Vector2d::new);
    }
}
