// 
// 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 BlockPyramidUtil
{
    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));
        }
        for (int y = height - 1; y >= 0; --y) {
            final double rf = 1.0 - y / (double)height;
            final double dx = radiusX * rf;
            int maxX;
            int x;
            for (int minX = x = -(maxX = (int)dx); x <= maxX; ++x) {
                final double dz = radiusZ * 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 double df = 1.0 / height;
        for (int y = height - 1; y >= 0; --y) {
            final boolean cap = capped && y < thickness;
            final double rf = 1.0 - y * df;
            final double dx = rf * radiusX;
            final double dz = rf * radiusZ;
            final int maxX;
            final int minX = -(maxX = (int)dx);
            final int maxZ;
            final int minZ = -(maxZ = (int)dz);
            final double innerRf = rf - df;
            final double innerDx = innerRf * radiusX;
            final double innerDz = innerRf * radiusZ;
            final int innerMinX = cap ? 1 : (-(int)innerDx + thickness);
            final int innerMaxX = cap ? 0 : ((int)innerDx - thickness);
            final int innerMinZ = cap ? 1 : (-(int)innerDz + thickness);
            final int innerMaxZ = cap ? 0 : ((int)innerDz - thickness);
            for (int x = minX; x <= maxX; ++x) {
                for (int z = minZ; z <= maxZ; ++z) {
                    if (x < innerMinX || x > innerMaxX || 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));
        }
        for (int y = height - 1; y >= 0; --y) {
            final double rf = 1.0 - y / (double)height;
            final double dx = radiusX * rf;
            int maxX;
            int x;
            for (int minX = x = -(maxX = (int)dx); x <= maxX; ++x) {
                final double dz = radiusZ * 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) {
        forEachBlockInverted(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 double df = 1.0 / height;
        for (int y = height - 1; y >= 0; --y) {
            final boolean cap = capped && y < thickness;
            final double rf = 1.0 - y * df;
            final double dx = rf * radiusX;
            final double dz = rf * radiusZ;
            final int maxX;
            final int minX = -(maxX = (int)dx);
            final int maxZ;
            final int minZ = -(maxZ = (int)dz);
            final double innerRf = rf - df;
            final double innerDx = innerRf * radiusX;
            final double innerDz = innerRf * radiusZ;
            final int innerMinX = cap ? 1 : (-(int)innerDx + thickness);
            final int innerMaxX = cap ? 0 : ((int)innerDx - thickness);
            final int innerMinZ = cap ? 1 : (-(int)innerDz + thickness);
            final int innerMaxZ = cap ? 0 : ((int)innerDz - thickness);
            for (int x = minX; x <= maxX; ++x) {
                for (int z = minZ; z <= maxZ; ++z) {
                    if (x < innerMinX || x > innerMaxX || z < innerMinZ || z > innerMaxZ) {
                        if (!consumer.test(originX + x, originY + height - 1 - y, originZ + z, t)) {
                            return;
                        }
                    }
                }
            }
        }
    }
}
