package net.minecraft.world.phys;

import net.minecraft.util.Mth;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.Optional;
import net.minecraft.core.Direction;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.core.BlockPos;

public class AABB {
    public final double minX;
    public final double minY;
    public final double minZ;
    public final double maxX;
    public final double maxY;
    public final double maxZ;
    
    public AABB(final double double1, final double double2, final double double3, final double double4, final double double5, final double double6) {
        this.minX = Math.min(double1, double4);
        this.minY = Math.min(double2, double5);
        this.minZ = Math.min(double3, double6);
        this.maxX = Math.max(double1, double4);
        this.maxY = Math.max(double2, double5);
        this.maxZ = Math.max(double3, double6);
    }
    
    public AABB(final BlockPos fk) {
        this(fk.getX(), fk.getY(), fk.getZ(), fk.getX() + 1, fk.getY() + 1, fk.getZ() + 1);
    }
    
    public AABB(final BlockPos fk1, final BlockPos fk2) {
        this(fk1.getX(), fk1.getY(), fk1.getZ(), fk2.getX(), fk2.getY(), fk2.getZ());
    }
    
    public AABB(final Vec3 cvl1, final Vec3 cvl2) {
        this(cvl1.x, cvl1.y, cvl1.z, cvl2.x, cvl2.y, cvl2.z);
    }
    
    public static AABB of(final BoundingBox clb) {
        return new AABB(clb.x0, clb.y0, clb.z0, clb.x1 + 1, clb.y1 + 1, clb.z1 + 1);
    }
    
    public double min(final Direction.Axis a) {
        return a.choose(this.minX, this.minY, this.minZ);
    }
    
    public double max(final Direction.Axis a) {
        return a.choose(this.maxX, this.maxY, this.maxZ);
    }
    
    @Override
    public boolean equals(final Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof AABB)) {
            return false;
        }
        final AABB cvf3 = (AABB)object;
        return Double.compare(cvf3.minX, this.minX) == 0 && Double.compare(cvf3.minY, this.minY) == 0 && Double.compare(cvf3.minZ, this.minZ) == 0 && Double.compare(cvf3.maxX, this.maxX) == 0 && Double.compare(cvf3.maxY, this.maxY) == 0 && Double.compare(cvf3.maxZ, this.maxZ) == 0;
    }
    
    @Override
    public int hashCode() {
        long long2 = Double.doubleToLongBits(this.minX);
        int integer4 = (int)(long2 ^ long2 >>> 32);
        long2 = Double.doubleToLongBits(this.minY);
        integer4 = 31 * integer4 + (int)(long2 ^ long2 >>> 32);
        long2 = Double.doubleToLongBits(this.minZ);
        integer4 = 31 * integer4 + (int)(long2 ^ long2 >>> 32);
        long2 = Double.doubleToLongBits(this.maxX);
        integer4 = 31 * integer4 + (int)(long2 ^ long2 >>> 32);
        long2 = Double.doubleToLongBits(this.maxY);
        integer4 = 31 * integer4 + (int)(long2 ^ long2 >>> 32);
        long2 = Double.doubleToLongBits(this.maxZ);
        integer4 = 31 * integer4 + (int)(long2 ^ long2 >>> 32);
        return integer4;
    }
    
    public AABB contract(final double double1, final double double2, final double double3) {
        double double4 = this.minX;
        double double5 = this.minY;
        double double6 = this.minZ;
        double double7 = this.maxX;
        double double8 = this.maxY;
        double double9 = this.maxZ;
        if (double1 < 0.0) {
            double4 -= double1;
        }
        else if (double1 > 0.0) {
            double7 -= double1;
        }
        if (double2 < 0.0) {
            double5 -= double2;
        }
        else if (double2 > 0.0) {
            double8 -= double2;
        }
        if (double3 < 0.0) {
            double6 -= double3;
        }
        else if (double3 > 0.0) {
            double9 -= double3;
        }
        return new AABB(double4, double5, double6, double7, double8, double9);
    }
    
    public AABB expandTowards(final Vec3 cvl) {
        return this.expandTowards(cvl.x, cvl.y, cvl.z);
    }
    
    public AABB expandTowards(final double double1, final double double2, final double double3) {
        double double4 = this.minX;
        double double5 = this.minY;
        double double6 = this.minZ;
        double double7 = this.maxX;
        double double8 = this.maxY;
        double double9 = this.maxZ;
        if (double1 < 0.0) {
            double4 += double1;
        }
        else if (double1 > 0.0) {
            double7 += double1;
        }
        if (double2 < 0.0) {
            double5 += double2;
        }
        else if (double2 > 0.0) {
            double8 += double2;
        }
        if (double3 < 0.0) {
            double6 += double3;
        }
        else if (double3 > 0.0) {
            double9 += double3;
        }
        return new AABB(double4, double5, double6, double7, double8, double9);
    }
    
    public AABB inflate(final double double1, final double double2, final double double3) {
        final double double4 = this.minX - double1;
        final double double5 = this.minY - double2;
        final double double6 = this.minZ - double3;
        final double double7 = this.maxX + double1;
        final double double8 = this.maxY + double2;
        final double double9 = this.maxZ + double3;
        return new AABB(double4, double5, double6, double7, double8, double9);
    }
    
    public AABB inflate(final double double1) {
        return this.inflate(double1, double1, double1);
    }
    
    public AABB intersect(final AABB cvf) {
        final double double3 = Math.max(this.minX, cvf.minX);
        final double double4 = Math.max(this.minY, cvf.minY);
        final double double5 = Math.max(this.minZ, cvf.minZ);
        final double double6 = Math.min(this.maxX, cvf.maxX);
        final double double7 = Math.min(this.maxY, cvf.maxY);
        final double double8 = Math.min(this.maxZ, cvf.maxZ);
        return new AABB(double3, double4, double5, double6, double7, double8);
    }
    
    public AABB minmax(final AABB cvf) {
        final double double3 = Math.min(this.minX, cvf.minX);
        final double double4 = Math.min(this.minY, cvf.minY);
        final double double5 = Math.min(this.minZ, cvf.minZ);
        final double double6 = Math.max(this.maxX, cvf.maxX);
        final double double7 = Math.max(this.maxY, cvf.maxY);
        final double double8 = Math.max(this.maxZ, cvf.maxZ);
        return new AABB(double3, double4, double5, double6, double7, double8);
    }
    
    public AABB move(final double double1, final double double2, final double double3) {
        return new AABB(this.minX + double1, this.minY + double2, this.minZ + double3, this.maxX + double1, this.maxY + double2, this.maxZ + double3);
    }
    
    public AABB move(final BlockPos fk) {
        return new AABB(this.minX + fk.getX(), this.minY + fk.getY(), this.minZ + fk.getZ(), this.maxX + fk.getX(), this.maxY + fk.getY(), this.maxZ + fk.getZ());
    }
    
    public AABB move(final Vec3 cvl) {
        return this.move(cvl.x, cvl.y, cvl.z);
    }
    
    public boolean intersects(final AABB cvf) {
        return this.intersects(cvf.minX, cvf.minY, cvf.minZ, cvf.maxX, cvf.maxY, cvf.maxZ);
    }
    
    public boolean intersects(final double double1, final double double2, final double double3, final double double4, final double double5, final double double6) {
        return this.minX < double4 && this.maxX > double1 && this.minY < double5 && this.maxY > double2 && this.minZ < double6 && this.maxZ > double3;
    }
    
    public boolean intersects(final Vec3 cvl1, final Vec3 cvl2) {
        return this.intersects(Math.min(cvl1.x, cvl2.x), Math.min(cvl1.y, cvl2.y), Math.min(cvl1.z, cvl2.z), Math.max(cvl1.x, cvl2.x), Math.max(cvl1.y, cvl2.y), Math.max(cvl1.z, cvl2.z));
    }
    
    public boolean contains(final Vec3 cvl) {
        return this.contains(cvl.x, cvl.y, cvl.z);
    }
    
    public boolean contains(final double double1, final double double2, final double double3) {
        return double1 >= this.minX && double1 < this.maxX && double2 >= this.minY && double2 < this.maxY && double3 >= this.minZ && double3 < this.maxZ;
    }
    
    public double getSize() {
        final double double2 = this.getXsize();
        final double double3 = this.getYsize();
        final double double4 = this.getZsize();
        return (double2 + double3 + double4) / 3.0;
    }
    
    public double getXsize() {
        return this.maxX - this.minX;
    }
    
    public double getYsize() {
        return this.maxY - this.minY;
    }
    
    public double getZsize() {
        return this.maxZ - this.minZ;
    }
    
    public AABB deflate(final double double1) {
        return this.inflate(-double1);
    }
    
    public Optional<Vec3> clip(final Vec3 cvl1, final Vec3 cvl2) {
        final double[] arr4 = { 1.0 };
        final double double5 = cvl2.x - cvl1.x;
        final double double6 = cvl2.y - cvl1.y;
        final double double7 = cvl2.z - cvl1.z;
        final Direction fp11 = getDirection(this, cvl1, arr4, null, double5, double6, double7);
        if (fp11 == null) {
            return Optional.<Vec3>empty();
        }
        final double double8 = arr4[0];
        return Optional.<Vec3>of(cvl1.add(double8 * double5, double8 * double6, double8 * double7));
    }
    
    @Nullable
    public static BlockHitResult clip(final Iterable<AABB> iterable, final Vec3 cvl2, final Vec3 cvl3, final BlockPos fk) {
        final double[] arr5 = { 1.0 };
        Direction fp6 = null;
        final double double7 = cvl3.x - cvl2.x;
        final double double8 = cvl3.y - cvl2.y;
        final double double9 = cvl3.z - cvl2.z;
        for (final AABB cvf14 : iterable) {
            fp6 = getDirection(cvf14.move(fk), cvl2, arr5, fp6, double7, double8, double9);
        }
        if (fp6 == null) {
            return null;
        }
        final double double10 = arr5[0];
        return new BlockHitResult(cvl2.add(double10 * double7, double10 * double8, double10 * double9), fp6, fk, false);
    }
    
    @Nullable
    private static Direction getDirection(final AABB cvf, final Vec3 cvl, final double[] arr, @Nullable Direction fp, final double double5, final double double6, final double double7) {
        if (double5 > 1.0E-7) {
            fp = clipPoint(arr, fp, double5, double6, double7, cvf.minX, cvf.minY, cvf.maxY, cvf.minZ, cvf.maxZ, Direction.WEST, cvl.x, cvl.y, cvl.z);
        }
        else if (double5 < -1.0E-7) {
            fp = clipPoint(arr, fp, double5, double6, double7, cvf.maxX, cvf.minY, cvf.maxY, cvf.minZ, cvf.maxZ, Direction.EAST, cvl.x, cvl.y, cvl.z);
        }
        if (double6 > 1.0E-7) {
            fp = clipPoint(arr, fp, double6, double7, double5, cvf.minY, cvf.minZ, cvf.maxZ, cvf.minX, cvf.maxX, Direction.DOWN, cvl.y, cvl.z, cvl.x);
        }
        else if (double6 < -1.0E-7) {
            fp = clipPoint(arr, fp, double6, double7, double5, cvf.maxY, cvf.minZ, cvf.maxZ, cvf.minX, cvf.maxX, Direction.UP, cvl.y, cvl.z, cvl.x);
        }
        if (double7 > 1.0E-7) {
            fp = clipPoint(arr, fp, double7, double5, double6, cvf.minZ, cvf.minX, cvf.maxX, cvf.minY, cvf.maxY, Direction.NORTH, cvl.z, cvl.x, cvl.y);
        }
        else if (double7 < -1.0E-7) {
            fp = clipPoint(arr, fp, double7, double5, double6, cvf.maxZ, cvf.minX, cvf.maxX, cvf.minY, cvf.maxY, Direction.SOUTH, cvl.z, cvl.x, cvl.y);
        }
        return fp;
    }
    
    @Nullable
    private static Direction clipPoint(final double[] arr, @Nullable final Direction fp2, final double double3, final double double4, final double double5, final double double6, final double double7, final double double8, final double double9, final double double10, final Direction fp11, final double double12, final double double13, final double double14) {
        final double double15 = (double6 - double12) / double3;
        final double double16 = double13 + double15 * double4;
        final double double17 = double14 + double15 * double5;
        if (0.0 < double15 && double15 < arr[0] && double7 - 1.0E-7 < double16 && double16 < double8 + 1.0E-7 && double9 - 1.0E-7 < double17 && double17 < double10 + 1.0E-7) {
            arr[0] = double15;
            return fp11;
        }
        return fp2;
    }
    
    @Override
    public String toString() {
        return "box[" + this.minX + ", " + this.minY + ", " + this.minZ + "] -> [" + this.maxX + ", " + this.maxY + ", " + this.maxZ + "]";
    }
    
    public boolean hasNaN() {
        return Double.isNaN(this.minX) || Double.isNaN(this.minY) || Double.isNaN(this.minZ) || Double.isNaN(this.maxX) || Double.isNaN(this.maxY) || Double.isNaN(this.maxZ);
    }
    
    public Vec3 getCenter() {
        return new Vec3(Mth.lerp(0.5, this.minX, this.maxX), Mth.lerp(0.5, this.minY, this.maxY), Mth.lerp(0.5, this.minZ, this.maxZ));
    }
}
