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

package com.hypixel.hytale.math.util;

import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import javax.annotation.Nonnull;

public class ChunkUtil
{
    public static final int BITS = 5;
    public static final int SIZE = 32;
    public static final int SIZE_2 = 1024;
    public static final int SIZE_MINUS_1 = 31;
    public static final int SIZE_MASK = 31;
    public static final int SIZE_COLUMNS = 1024;
    public static final int SIZE_COLUMNS_MASK = 1023;
    public static final int SIZE_BLOCKS = 32768;
    public static final int BITS2 = 10;
    public static final int NON_CHUNK_MASK = -32;
    public static final int HEIGHT_SECTIONS = 10;
    public static final int HEIGHT = 320;
    public static final int HEIGHT_MINUS_1 = 319;
    public static final int HEIGHT_MASK;
    public static final int SIZE_BLOCKS_COLUMN = 327680;
    public static final long NOT_FOUND;
    public static final int MIN_Y = 0;
    public static final int MIN_ENTITY_Y = -32;
    public static final int MIN_SECTION = 0;
    
    private ChunkUtil() {
    }
    
    public static byte[] shortToByteArray(@Nonnull final short[] data) {
        final ByteBuffer byteBuffer = ByteBuffer.allocate(data.length * 2).order(ByteOrder.LITTLE_ENDIAN);
        byteBuffer.asShortBuffer().put(data);
        return byteBuffer.array();
    }
    
    public static byte[] intToByteArray(@Nonnull final int[] data) {
        final ByteBuffer byteBuffer = ByteBuffer.allocate(data.length * 4).order(ByteOrder.LITTLE_ENDIAN);
        byteBuffer.asIntBuffer().put(data);
        return byteBuffer.array();
    }
    
    public static int indexColumn(final int x, final int z) {
        return (z & 0x1F) << 5 | (x & 0x1F);
    }
    
    public static int xFromColumn(final int index) {
        return index & 0x1F;
    }
    
    public static int zFromColumn(final int index) {
        return index >> 5 & 0x1F;
    }
    
    public static int indexSection(final int y) {
        return y >> 5;
    }
    
    public static int indexBlockFromColumn(final int column, final int y) {
        return (y & 0x1F) << 10 | (column & 0x3FF);
    }
    
    public static int indexBlock(final int x, final int y, final int z) {
        return (y & 0x1F) << 10 | (z & 0x1F) << 5 | (x & 0x1F);
    }
    
    public static int xFromIndex(final int index) {
        return index & 0x1F;
    }
    
    public static int yFromIndex(final int index) {
        return index >> 10 & 0x1F;
    }
    
    public static int zFromIndex(final int index) {
        return index >> 5 & 0x1F;
    }
    
    public static int indexBlockInColumn(final int x, final int y, final int z) {
        return (y & ChunkUtil.HEIGHT_MASK) << 10 | (z & 0x1F) << 5 | (x & 0x1F);
    }
    
    public static int indexBlockInColumnFromColumn(final int column, final int y) {
        return (y & ChunkUtil.HEIGHT_MASK) << 10 | (column & 0x3FF);
    }
    
    public static int xFromBlockInColumn(final int index) {
        return index & 0x1F;
    }
    
    public static int yFromBlockInColumn(final int index) {
        return index >> 10 & ChunkUtil.HEIGHT_MASK;
    }
    
    public static int zFromBlockInColumn(final int index) {
        return index >> 5 & 0x1F;
    }
    
    public static int localCoordinate(final long v) {
        return (int)(v & 0x1FL);
    }
    
    public static int chunkCoordinate(final double block) {
        return MathUtil.floor(block) >> 5;
    }
    
    public static int chunkCoordinate(final int block) {
        return block >> 5;
    }
    
    public static int chunkCoordinate(final long block) {
        return (int)(block >> 5);
    }
    
    public static int minBlock(final int index) {
        return index << 5;
    }
    
    public static int maxBlock(final int index) {
        return (index << 5) + 31;
    }
    
    public static boolean isWithinLocalChunk(final int x, final int z) {
        return x >= 0 && z >= 0 && x < 32 && z < 32;
    }
    
    public static boolean isBorderBlock(final int x, final int z) {
        return x == 0 || z == 0 || x == 31 || z == 31;
    }
    
    public static boolean isBorderBlockGlobal(int x, int z) {
        x &= 0x1F;
        z &= 0x1F;
        return isBorderBlock(x, z);
    }
    
    public static boolean isInsideChunk(final int chunkX, final int chunkZ, final int x, final int z) {
        return chunkCoordinate(x) == chunkX && chunkCoordinate(z) == chunkZ;
    }
    
    public static boolean isSameChunk(final int x0, final int z0, final int x1, final int z1) {
        return chunkCoordinate(x0) == chunkCoordinate(x1) && chunkCoordinate(z0) == chunkCoordinate(z1);
    }
    
    public static boolean isSameChunkSection(final int x0, final int y0, final int z0, final int x1, final int y1, final int z1) {
        return chunkCoordinate(x0) == chunkCoordinate(x1) && chunkCoordinate(y0) == chunkCoordinate(y1) && chunkCoordinate(z0) == chunkCoordinate(z1);
    }
    
    public static boolean isInsideChunkRelative(final int x, final int z) {
        return (x & 0x1F) == x && (z & 0x1F) == z;
    }
    
    public static int xOfChunkIndex(final long index) {
        return (int)(index >> 32);
    }
    
    public static int zOfChunkIndex(final long index) {
        return (int)index;
    }
    
    public static long indexChunk(final int x, final int z) {
        return (long)x << 32 | ((long)z & 0xFFFFFFFFL);
    }
    
    public static long indexChunkFromBlock(final int blockX, final int blockZ) {
        return indexChunk(chunkCoordinate(blockX), chunkCoordinate(blockZ));
    }
    
    public static long indexChunkFromBlock(final double blockX, final double blockZ) {
        return indexChunkFromBlock(MathUtil.floor(blockX), MathUtil.floor(blockZ));
    }
    
    public static int worldCoordFromLocalCoord(final int chunkCoord, final int localCoord) {
        return chunkCoord << 5 | localCoord;
    }
    
    static {
        HEIGHT_MASK = (Integer.highestOneBit(320) << 1) - 1;
        NOT_FOUND = indexChunk(Integer.MIN_VALUE, Integer.MIN_VALUE);
    }
}
