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

package com.hypixel.hytale.component.spatial;

import it.unimi.dsi.fastutil.ints.IntArrays;
import java.util.Arrays;
import java.util.Objects;
import com.hypixel.hytale.common.util.ArrayUtil;
import javax.annotation.Nonnull;
import com.hypixel.hytale.math.vector.Vector3d;

public class SpatialData<T>
{
    public static final Vector3d[] EMPTY_VECTOR_ARRAY;
    @Nonnull
    private int[] indexes;
    @Nonnull
    private long[] moroton;
    private Vector3d[] vectors;
    @Nonnull
    private T[] data;
    private int size;
    
    public SpatialData() {
        this.indexes = ArrayUtil.EMPTY_INT_ARRAY;
        this.moroton = ArrayUtil.EMPTY_LONG_ARRAY;
        this.vectors = SpatialData.EMPTY_VECTOR_ARRAY;
        this.data = ArrayUtil.emptyArray();
    }
    
    public int size() {
        return this.size;
    }
    
    public int getSortedIndex(final int i) {
        return this.indexes[i];
    }
    
    @Nonnull
    public Vector3d getVector(final int i) {
        return this.vectors[i];
    }
    
    @Nonnull
    public T getData(final int i) {
        return this.data[i];
    }
    
    public void add(@Nonnull final Vector3d vector, @Nonnull final T value) {
        Objects.requireNonNull(value);
        if (this.vectors.length < this.size + 1) {
            final int newLength = ArrayUtil.grow(this.size);
            this.indexes = Arrays.copyOf(this.indexes, newLength);
            this.vectors = Arrays.copyOf(this.vectors, newLength);
            this.data = Arrays.copyOf(this.data, newLength);
            for (int i = this.size; i < newLength; ++i) {
                this.vectors[i] = new Vector3d();
            }
        }
        final int index = this.size++;
        this.indexes[index] = index;
        this.vectors[index].assign(vector);
        this.data[index] = value;
    }
    
    public void addCapacity(final int additionalSize) {
        final int newSize = this.size + additionalSize;
        if (this.vectors.length < newSize) {
            final int newLength = ArrayUtil.grow(newSize);
            this.indexes = Arrays.copyOf(this.indexes, newLength);
            this.vectors = Arrays.copyOf(this.vectors, newLength);
            this.data = Arrays.copyOf(this.data, newLength);
            for (int i = this.size; i < newLength; ++i) {
                this.vectors[i] = new Vector3d();
            }
        }
    }
    
    public void append(@Nonnull final Vector3d vector, @Nonnull final T value) {
        Objects.requireNonNull(value);
        final int index = this.size++;
        this.indexes[index] = index;
        this.vectors[index].assign(vector);
        this.data[index] = value;
    }
    
    public void sort() {
        IntArrays.quickSort(this.indexes, 0, this.size, (i1, i2) -> {
            final Vector3d v1 = this.vectors[i1];
            final Vector3d v2 = this.vectors[i2];
            final int xComp = Double.compare(v1.x, v2.x);
            if (xComp != 0) {
                return xComp;
            }
            else {
                final int zComp = Double.compare(v1.z, v2.z);
                if (zComp != 0) {
                    return zComp;
                }
                else {
                    return Double.compare(v1.y, v2.y);
                }
            }
        });
    }
    
    public void sortMorton() {
        double minX = Double.POSITIVE_INFINITY;
        double minY = Double.POSITIVE_INFINITY;
        double minZ = Double.POSITIVE_INFINITY;
        double maxX = Double.NEGATIVE_INFINITY;
        double maxY = Double.NEGATIVE_INFINITY;
        double maxZ = Double.NEGATIVE_INFINITY;
        for (int i = 0; i < this.size; ++i) {
            final Vector3d v = this.vectors[i];
            if (v.x < minX) {
                minX = v.x;
            }
            if (v.y < minY) {
                minY = v.y;
            }
            if (v.z < minZ) {
                minZ = v.z;
            }
            if (v.x > maxX) {
                maxX = v.x;
            }
            if (v.y > maxY) {
                maxY = v.y;
            }
            if (v.z > maxZ) {
                maxZ = v.z;
            }
        }
        this.moroton = ((this.moroton.length < this.size) ? Arrays.copyOf(this.moroton, this.size) : this.moroton);
        for (int i = 0; i < this.size; ++i) {
            final Vector3d v = this.vectors[i];
            this.moroton[i] = Long.reverse(MortonCode.encode(v.x, v.y, v.z, minX, minY, minZ, maxX, maxY, maxZ));
        }
        IntArrays.quickSort(this.indexes, 0, this.size, (i1, i2) -> Long.compare(this.moroton[i1], this.moroton[i2]));
    }
    
    public void clear() {
        Arrays.fill(this.data, 0, this.size, null);
        this.size = 0;
    }
    
    static {
        EMPTY_VECTOR_ARRAY = new Vector3d[0];
    }
}
