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

package com.hypixel.hytale.math.iterator;

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

public final class BoxBlockIterator
{
    @Nonnull
    private static ThreadLocal<BoxIterationBuffer> THREAD_LOCAL_BUFFER;
    
    private BoxBlockIterator() {
        throw new UnsupportedOperationException("This is a utility class. Do not instantiate.");
    }
    
    public static BoxIterationBuffer getBuffer() {
        return BoxBlockIterator.THREAD_LOCAL_BUFFER.get();
    }
    
    public static boolean iterate(@Nonnull final Box box, @Nonnull final Vector3d position, @Nonnull final Vector3d d, final double maxDistance, @Nonnull final BoxIterationConsumer consumer) {
        return iterate(box, position, d, maxDistance, consumer, getBuffer());
    }
    
    public static boolean iterate(@Nonnull final Box box, @Nonnull final Vector3d pos, @Nonnull final Vector3d d, final double maxDistance, @Nonnull final BoxIterationConsumer consumer, @Nonnull final BoxIterationBuffer buffer) {
        return iterate(box.min, box.max, pos, d, maxDistance, consumer, buffer);
    }
    
    public static boolean iterate(@Nonnull final Box box, final double px, final double py, final double pz, final double dx, final double dy, final double dz, final double maxDistance, @Nonnull final BoxIterationConsumer consumer) {
        return iterate(box, px, py, pz, dx, dy, dz, maxDistance, consumer, getBuffer());
    }
    
    public static boolean iterate(@Nonnull final Box box, final double px, final double py, final double pz, final double dx, final double dy, final double dz, final double maxDistance, @Nonnull final BoxIterationConsumer consumer, @Nonnull final BoxIterationBuffer buffer) {
        return iterate(box.min, box.max, px, py, pz, dx, dy, dz, maxDistance, consumer, buffer);
    }
    
    public static boolean iterate(@Nonnull final Vector3d min, @Nonnull final Vector3d max, final double px, final double py, final double pz, final double dx, final double dy, final double dz, final double maxDistance, @Nonnull final BoxIterationConsumer consumer) {
        return iterate(min, max, px, py, pz, dx, dy, dz, maxDistance, consumer, getBuffer());
    }
    
    public static boolean iterate(@Nonnull final Vector3d min, @Nonnull final Vector3d max, final double px, final double py, final double pz, final double dx, final double dy, final double dz, final double maxDistance, @Nonnull final BoxIterationConsumer consumer, @Nonnull final BoxIterationBuffer buffer) {
        return iterate(min.x, min.y, min.z, max.x, max.y, max.z, px, py, pz, dx, dy, dz, maxDistance, consumer, buffer);
    }
    
    public static boolean iterate(@Nonnull final Vector3d min, @Nonnull final Vector3d max, @Nonnull final Vector3d pos, @Nonnull final Vector3d d, final double maxDistance, @Nonnull final BoxIterationConsumer consumer) {
        return iterate(min, max, pos, d, maxDistance, consumer, getBuffer());
    }
    
    public static boolean iterate(@Nonnull final Vector3d min, @Nonnull final Vector3d max, @Nonnull final Vector3d pos, @Nonnull final Vector3d d, final double maxDistance, @Nonnull final BoxIterationConsumer consumer, @Nonnull final BoxIterationBuffer buffer) {
        return iterate(min.x, min.y, min.z, max.x, max.y, max.z, pos.x, pos.y, pos.z, d.x, d.y, d.z, maxDistance, consumer, buffer);
    }
    
    public static boolean iterate(final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ, final double px, final double py, final double pz, final double dx, final double dy, final double dz, final double maxDistance, @Nonnull final BoxIterationConsumer consumer) {
        return iterate(minX, minY, minZ, maxX, maxY, maxZ, px, py, pz, dx, dy, dz, maxDistance, consumer, getBuffer());
    }
    
    public static boolean iterate(final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ, final double px, final double py, final double pz, final double dx, final double dy, final double dz, final double maxDistance, @Nonnull final BoxIterationConsumer consumer, @Nonnull final BoxIterationBuffer buffer) {
        if (minX > maxX) {
            throw new IllegalArgumentException("minX is larger than maxX! Given: " + minX + " > " + maxX);
        }
        if (minY > maxY) {
            throw new IllegalArgumentException("minY is larger than maxY! Given: " + minY + " > " + maxY);
        }
        if (minZ > maxZ) {
            throw new IllegalArgumentException("minZ is larger than maxZ! Given: " + minZ + " > " + maxZ);
        }
        if (consumer == null) {
            throw new NullPointerException("consumer is null!");
        }
        if (buffer == null) {
            throw new NullPointerException("buffer is null!");
        }
        return iterate0(minX, minY, minZ, maxX, maxY, maxZ, px, py, pz, dx, dy, dz, maxDistance, consumer, buffer);
    }
    
    private static boolean iterate0(final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ, final double posX, final double posY, final double posZ, final double dx, final double dy, final double dz, final double maxDistance, final BoxIterationConsumer consumer, @Nonnull final BoxIterationBuffer buffer) {
        buffer.consumer = consumer;
        buffer.mx = maxX - minX;
        buffer.my = maxY - minY;
        buffer.mz = maxZ - minZ;
        buffer.signX = ((dx > 0.0) ? -1 : 1);
        buffer.signY = ((dy > 0.0) ? -1 : 1);
        buffer.signZ = ((dz > 0.0) ? -1 : 1);
        final double bx = posX + ((dx > 0.0) ? maxX : minX);
        final double by = posY + ((dy > 0.0) ? maxY : minY);
        final double bz = posZ + ((dz > 0.0) ? maxZ : minZ);
        buffer.posX = (long)bx;
        buffer.posY = (long)by;
        buffer.posZ = (long)bz;
        return BlockIterator.iterate(bx, by, bz, dx, dy, dz, maxDistance, (x, y, z, px, py, pz, qx, qy, qz, buf) -> {
            final int tx = (int)MathUtil.fastCeil(((buf.signX < 0) ? (1.0 - px) : px) + buf.mx);
            final int ty = (int)MathUtil.fastCeil(((buf.signY < 0) ? (1.0 - py) : py) + buf.my);
            final int tz = (int)MathUtil.fastCeil(((buf.signZ < 0) ? (1.0 - pz) : pz) + buf.mz);
            if (x != buf.posX) {
                for (int iy = 0; iy < ty; ++iy) {
                    int iz = 0;
                    while (iz < tz) {
                        if (!buf.consumer.accept(x, y + iy * (long)buf.signY, z + iz * (long)buf.signZ)) {
                            return false;
                        }
                        else {
                            ++iz;
                        }
                    }
                }
                buf.posX = x;
            }
            if (y != buf.posY) {
                for (int iz2 = 0; iz2 < tz; ++iz2) {
                    int ix = 0;
                    while (ix < tx) {
                        if (!buf.consumer.accept(x + ix * (long)buf.signX, y, z + iz2 * (long)buf.signZ)) {
                            return false;
                        }
                        else {
                            ++ix;
                        }
                    }
                }
                buf.posY = y;
            }
            if (z != buf.posZ) {
                for (int ix2 = 0; ix2 < tx; ++ix2) {
                    int iy2 = 0;
                    while (iy2 < ty) {
                        if (!buf.consumer.accept(x + ix2 * (long)buf.signX, y + iy2 * (long)buf.signY, z)) {
                            return false;
                        }
                        else {
                            ++iy2;
                        }
                    }
                }
                buf.posZ = z;
            }
            return buf.consumer.next();
        }, buffer);
    }
    
    static {
        BoxBlockIterator.THREAD_LOCAL_BUFFER = ThreadLocal.withInitial((Supplier<? extends BoxIterationBuffer>)BoxIterationBuffer::new);
    }
    
    public static class BoxIterationBuffer
    {
        BoxIterationConsumer consumer;
        double mx;
        double my;
        double mz;
        int signX;
        int signY;
        int signZ;
        long posX;
        long posY;
        long posZ;
    }
    
    public interface BoxIterationConsumer
    {
        boolean next();
        
        boolean accept(final long p0, final long p1, final long p2);
    }
}
