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

package com.hypixel.hytale.math.block;

import javax.annotation.Nonnull;
import com.hypixel.hytale.function.predicate.TriIntObjPredicate;

public class BlockConeUtil
{
    public static <T> void forEachBlock(final int originX, final int originY, final int originZ, final int radiusX, final int height, final int radiusZ, final T t, @Nonnull final TriIntObjPredicate<T> consumer) {
        if (radiusX <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusX));
        }
        if (height <= 0) {
            throw new IllegalArgumentException(String.valueOf(height));
        }
        if (radiusZ <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusZ));
        }
        final float radiusXAdjusted = radiusX + 0.41f;
        final float radiusZAdjusted = radiusZ + 0.41f;
        for (int y = height - 1; y >= 0; --y) {
            final double rf = 1.0 - y / (double)height;
            final double dx = radiusXAdjusted * rf;
            int maxX;
            int x;
            for (int minX = x = -(maxX = (int)dx); x <= maxX; ++x) {
                final double qx = 1.0 - x * x / (dx * dx);
                final double dz = Math.sqrt(qx) * radiusZAdjusted * rf;
                int maxZ;
                int z;
                for (int minZ = z = -(maxZ = (int)dz); z <= maxZ; ++z) {
                    if (!consumer.test(originX + x, originY + y, originZ + z, t)) {
                        return;
                    }
                }
            }
        }
    }
    
    public static <T> void forEachBlock(final int originX, final int originY, final int originZ, final int radiusX, final int height, final int radiusZ, final int thickness, final T t, @Nonnull final TriIntObjPredicate<T> consumer) {
        forEachBlock(originX, originY, originZ, radiusX, height, radiusZ, thickness, false, t, consumer);
    }
    
    public static <T> void forEachBlock(final int originX, final int originY, final int originZ, final int radiusX, final int height, final int radiusZ, final int thickness, final boolean capped, final T t, @Nonnull final TriIntObjPredicate<T> consumer) {
        if (thickness < 1) {
            forEachBlock(originX, originY, originZ, radiusX, height, radiusZ, t, consumer);
            return;
        }
        if (radiusX <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusX));
        }
        if (height <= 0) {
            throw new IllegalArgumentException(String.valueOf(height));
        }
        if (radiusZ <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusZ));
        }
        final float radiusXAdjusted = radiusX + 0.41f;
        for (int y = height - 1; y >= 0; --y) {
            final boolean cap = capped && y < thickness;
            final double rf = 1.0 - y / (double)height;
            final double dx = radiusXAdjusted * rf;
            final double dxInvSqr = 1.0 / (dx * dx);
            final double innerDx = (dx > thickness) ? (dx - thickness) : 0.0;
            final double innerDxInvSqr = (innerDx > 0.0) ? (1.0 / (innerDx * innerDx)) : 0.0;
            int maxX;
            int x;
            for (int minX = x = -(maxX = (int)dx); x <= maxX; ++x) {
                final double dz = Math.sqrt(1.0 - x * x * dxInvSqr) * dx;
                final int maxZ;
                final int minZ = -(maxZ = (int)dz);
                final double innerMaxZ = cap ? 0.0 : (Math.sqrt(1.0 - x * x * innerDxInvSqr) * innerDx);
                final double innerMinZ = cap ? 0.0 : (-innerMaxZ);
                for (int z = minZ; z <= maxZ; ++z) {
                    if (z <= innerMinZ || z >= innerMaxZ) {
                        if (!consumer.test(originX + x, originY + y, originZ + z, t)) {
                            return;
                        }
                    }
                }
            }
        }
    }
    
    public static <T> void forEachBlockInverted(final int originX, final int originY, final int originZ, final int radiusX, final int height, final int radiusZ, final T t, @Nonnull final TriIntObjPredicate<T> consumer) {
        if (radiusX <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusX));
        }
        if (height <= 0) {
            throw new IllegalArgumentException(String.valueOf(height));
        }
        if (radiusZ <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusZ));
        }
        final float radiusXAdjusted = radiusX + 0.41f;
        final float radiusZAdjusted = radiusZ + 0.41f;
        for (int y = height - 1; y >= 0; --y) {
            final double rf = 1.0 - y / (double)height;
            final double dx = radiusXAdjusted * rf;
            int maxX;
            int x;
            for (int minX = x = -(maxX = (int)dx); x <= maxX; ++x) {
                final double qx = 1.0 - x * x / (dx * dx);
                final double dz = Math.sqrt(qx) * radiusZAdjusted * rf;
                int maxZ;
                int z;
                for (int minZ = z = -(maxZ = (int)dz); z <= maxZ; ++z) {
                    if (!consumer.test(originX + x, originY + height - 1 - y, originZ + z, t)) {
                        return;
                    }
                }
            }
        }
    }
    
    public static <T> void forEachBlockInverted(final int originX, final int originY, final int originZ, final int radiusX, final int height, final int radiusZ, final int thickness, final T t, @Nonnull final TriIntObjPredicate<T> consumer) {
        forEachBlock(originX, originY, originZ, radiusX, height, radiusZ, thickness, false, t, consumer);
    }
    
    public static <T> void forEachBlockInverted(final int originX, final int originY, final int originZ, final int radiusX, final int height, final int radiusZ, final int thickness, final boolean capped, final T t, @Nonnull final TriIntObjPredicate<T> consumer) {
        if (thickness < 1) {
            forEachBlockInverted(originX, originY, originZ, radiusX, height, radiusZ, t, consumer);
            return;
        }
        if (radiusX <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusX));
        }
        if (height <= 0) {
            throw new IllegalArgumentException(String.valueOf(height));
        }
        if (radiusZ <= 0) {
            throw new IllegalArgumentException(String.valueOf(radiusZ));
        }
        final float radiusXAdjusted = radiusX + 0.41f;
        for (int y = height - 1; y >= 0; --y) {
            final boolean cap = capped && y < thickness;
            final double rf = 1.0 - y / (double)height;
            final double dx = radiusXAdjusted * rf;
            final double dxInvSqr = 1.0 / (dx * dx);
            final double innerDx = (dx > thickness) ? (dx - thickness) : 0.0;
            final double innerDxInvSqr = (innerDx > 0.0) ? (1.0 / (innerDx * innerDx)) : 0.0;
            int maxX;
            int x;
            for (int minX = x = -(maxX = (int)dx); x <= maxX; ++x) {
                final double dz = Math.sqrt(1.0 - x * x * dxInvSqr) * dx;
                final int maxZ;
                final int minZ = -(maxZ = (int)dz);
                final double innerMaxZ = cap ? 0.0 : (Math.sqrt(1.0 - x * x * innerDxInvSqr) * innerDx);
                final double innerMinZ = cap ? 0.0 : (-innerMaxZ);
                for (int z = minZ; z <= maxZ; ++z) {
                    if (z <= innerMinZ || z >= innerMaxZ) {
                        if (!consumer.test(originX + x, originY + height - 1 - y, originZ + z, t)) {
                            return;
                        }
                    }
                }
            }
        }
    }
}
