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 fu) {
        this(fu.getX(), fu.getY(), fu.getZ(), fu.getX() + 1, fu.getY() + 1, fu.getZ() + 1);
    }
    
    public AABB(final BlockPos fu1, final BlockPos fu2) {
        this(fu1.getX(), fu1.getY(), fu1.getZ(), fu2.getX(), fu2.getY(), fu2.getZ());
    }
    
    public AABB(final Vec3 dem1, final Vec3 dem2) {
        this(dem1.x, dem1.y, dem1.z, dem2.x, dem2.y, dem2.z);
    }
    
    public static AABB of(final BoundingBox ctd) {
        return new AABB(ctd.x0, ctd.y0, ctd.z0, ctd.x1 + 1, ctd.y1 + 1, ctd.z1 + 1);
    }
    
    public static AABB unitCubeFromLowerCorner(final Vec3 dem) {
        return new AABB(dem.x, dem.y, dem.z, dem.x + 1.0, dem.y + 1.0, dem.z + 1.0);
    }
    
    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 deg3 = (AABB)object;
        return Double.compare(deg3.minX, this.minX) == 0 && Double.compare(deg3.minY, this.minY) == 0 && Double.compare(deg3.minZ, this.minZ) == 0 && Double.compare(deg3.maxX, this.maxX) == 0 && Double.compare(deg3.maxY, this.maxY) == 0 && Double.compare(deg3.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 dem) {
        return this.expandTowards(dem.x, dem.y, dem.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 deg) {
        final double double3 = Math.max(this.minX, deg.minX);
        final double double4 = Math.max(this.minY, deg.minY);
        final double double5 = Math.max(this.minZ, deg.minZ);
        final double double6 = Math.min(this.maxX, deg.maxX);
        final double double7 = Math.min(this.maxY, deg.maxY);
        final double double8 = Math.min(this.maxZ, deg.maxZ);
        return new AABB(double3, double4, double5, double6, double7, double8);
    }
    
    public AABB minmax(final AABB deg) {
        final double double3 = Math.min(this.minX, deg.minX);
        final double double4 = Math.min(this.minY, deg.minY);
        final double double5 = Math.min(this.minZ, deg.minZ);
        final double double6 = Math.max(this.maxX, deg.maxX);
        final double double7 = Math.max(this.maxY, deg.maxY);
        final double double8 = Math.max(this.maxZ, deg.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 fu) {
        return new AABB(this.minX + fu.getX(), this.minY + fu.getY(), this.minZ + fu.getZ(), this.maxX + fu.getX(), this.maxY + fu.getY(), this.maxZ + fu.getZ());
    }
    
    public AABB move(final Vec3 dem) {
        return this.move(dem.x, dem.y, dem.z);
    }
    
    public boolean intersects(final AABB deg) {
        return this.intersects(deg.minX, deg.minY, deg.minZ, deg.maxX, deg.maxY, deg.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 dem1, final Vec3 dem2) {
        return this.intersects(Math.min(dem1.x, dem2.x), Math.min(dem1.y, dem2.y), Math.min(dem1.z, dem2.z), Math.max(dem1.x, dem2.x), Math.max(dem1.y, dem2.y), Math.max(dem1.z, dem2.z));
    }
    
    public boolean contains(final Vec3 dem) {
        return this.contains(dem.x, dem.y, dem.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 dem1, final Vec3 dem2) {
        final double[] arr4 = { 1.0 };
        final double double5 = dem2.x - dem1.x;
        final double double6 = dem2.y - dem1.y;
        final double double7 = dem2.z - dem1.z;
        final Direction fz11 = getDirection(this, dem1, arr4, null, double5, double6, double7);
        if (fz11 == null) {
            return Optional.<Vec3>empty();
        }
        final double double8 = arr4[0];
        return Optional.<Vec3>of(dem1.add(double8 * double5, double8 * double6, double8 * double7));
    }
    
    @Nullable
    public static BlockHitResult clip(final Iterable<AABB> iterable, final Vec3 dem2, final Vec3 dem3, final BlockPos fu) {
        final double[] arr5 = { 1.0 };
        Direction fz6 = null;
        final double double7 = dem3.x - dem2.x;
        final double double8 = dem3.y - dem2.y;
        final double double9 = dem3.z - dem2.z;
        for (final AABB deg14 : iterable) {
            fz6 = getDirection(deg14.move(fu), dem2, arr5, fz6, double7, double8, double9);
        }
        if (fz6 == null) {
            return null;
        }
        final double double10 = arr5[0];
        return new BlockHitResult(dem2.add(double10 * double7, double10 * double8, double10 * double9), fz6, fu, false);
    }
    
    @Nullable
    private static Direction getDirection(final AABB deg, final Vec3 dem, final double[] arr, @Nullable Direction fz, final double double5, final double double6, final double double7) {
        if (double5 > 1.0E-7) {
            fz = clipPoint(arr, fz, double5, double6, double7, deg.minX, deg.minY, deg.maxY, deg.minZ, deg.maxZ, Direction.WEST, dem.x, dem.y, dem.z);
        }
        else if (double5 < -1.0E-7) {
            fz = clipPoint(arr, fz, double5, double6, double7, deg.maxX, deg.minY, deg.maxY, deg.minZ, deg.maxZ, Direction.EAST, dem.x, dem.y, dem.z);
        }
        if (double6 > 1.0E-7) {
            fz = clipPoint(arr, fz, double6, double7, double5, deg.minY, deg.minZ, deg.maxZ, deg.minX, deg.maxX, Direction.DOWN, dem.y, dem.z, dem.x);
        }
        else if (double6 < -1.0E-7) {
            fz = clipPoint(arr, fz, double6, double7, double5, deg.maxY, deg.minZ, deg.maxZ, deg.minX, deg.maxX, Direction.UP, dem.y, dem.z, dem.x);
        }
        if (double7 > 1.0E-7) {
            fz = clipPoint(arr, fz, double7, double5, double6, deg.minZ, deg.minX, deg.maxX, deg.minY, deg.maxY, Direction.NORTH, dem.z, dem.x, dem.y);
        }
        else if (double7 < -1.0E-7) {
            fz = clipPoint(arr, fz, double7, double5, double6, deg.maxZ, deg.minX, deg.maxX, deg.minY, deg.maxY, Direction.SOUTH, dem.z, dem.x, dem.y);
        }
        return fz;
    }
    
    @Nullable
    private static Direction clipPoint(final double[] arr, @Nullable final Direction fz2, 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 fz11, 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 fz11;
        }
        return fz2;
    }
    
    @Override
    public String toString() {
        return "AABB[" + 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));
    }
    
    public static AABB ofSize(final double double1, final double double2, final double double3) {
        return new AABB(-double1 / 2.0, -double2 / 2.0, -double3 / 2.0, double1 / 2.0, double2 / 2.0, double3 / 2.0);
    }
}
