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

package com.hypixel.hytale.math.iterator;

import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.math.util.ChunkUtil;

public class SpiralIterator
{
    public static final long MAX_RADIUS_LONG;
    public static final int MAX_RADIUS;
    private boolean setup;
    private int chunkX;
    private int chunkZ;
    private long maxI;
    private long i;
    private int x;
    private int z;
    private int dx;
    private int dz;
    
    public SpiralIterator() {
    }
    
    public SpiralIterator(final int chunkX, final int chunkZ, final int radius) {
        this.init(chunkX, chunkZ, radius);
    }
    
    public SpiralIterator(final int chunkX, final int chunkZ, final int radiusFrom, final int radiusTo) {
        this.init(chunkX, chunkZ, radiusFrom, radiusTo);
    }
    
    public void init(final int chunkX, final int chunkZ, final int radiusTo) {
        this.init(chunkX, chunkZ, 0, radiusTo);
    }
    
    public void init(final int chunkX, final int chunkZ, final int radiusFrom, final int radiusTo) {
        if (radiusFrom < 0) {
            throw new IllegalArgumentException("radiusFrom must be >= 0: " + radiusFrom);
        }
        if (radiusTo <= 0) {
            throw new IllegalArgumentException("radiusTo must be > 0: " + radiusTo);
        }
        if (radiusTo > SpiralIterator.MAX_RADIUS) {
            throw new IllegalArgumentException("radiusTo must be < MAX_RADIUS " + SpiralIterator.MAX_RADIUS + ": " + radiusTo);
        }
        if (radiusFrom >= radiusTo) {
            throw new IllegalArgumentException("radiusFrom must be < radiusTo: " + radiusFrom + " -> " + radiusTo);
        }
        this.chunkX = chunkX;
        this.chunkZ = chunkZ;
        final long widthTo = 1L + radiusTo * 2L;
        this.maxI = widthTo * widthTo;
        if (radiusFrom != 0) {
            final long widthFrom = 1L + radiusFrom * 2L;
            this.i = widthFrom * widthFrom;
            final long pos = getPosFromIndex((int)this.i);
            this.x = ChunkUtil.xOfChunkIndex(pos);
            this.z = ChunkUtil.zOfChunkIndex(pos);
            this.dx = 1;
            this.dz = 0;
        }
        else {
            this.i = 0L;
            final int n = 0;
            this.z = n;
            this.x = n;
            this.dx = 0;
            this.dz = -1;
        }
        this.setup = true;
    }
    
    public void reset() {
        this.setup = false;
    }
    
    public long next() {
        if (!this.setup) {
            throw new IllegalStateException("SpiralIterator is not setup!");
        }
        final long chunkCoordinates = ChunkUtil.indexChunk(this.chunkX + this.x, this.chunkZ + this.z);
        if (this.x == this.z || (this.x < 0 && this.x == -this.z) || (this.x > 0 && this.x == 1 - this.z)) {
            final int tempDx = this.dx;
            this.dx = -this.dz;
            this.dz = tempDx;
        }
        this.x += this.dx;
        this.z += this.dz;
        ++this.i;
        return chunkCoordinates;
    }
    
    public boolean hasNext() {
        return this.i < this.maxI;
    }
    
    public boolean isSetup() {
        return this.setup;
    }
    
    public long getIndex() {
        return this.i;
    }
    
    public long getMaxIndex() {
        return this.maxI;
    }
    
    public int getChunkX() {
        return this.chunkX;
    }
    
    public int getChunkZ() {
        return this.chunkZ;
    }
    
    public int getX() {
        return this.x;
    }
    
    public int getZ() {
        return this.z;
    }
    
    public int getDx() {
        return this.dx;
    }
    
    public int getDz() {
        return this.dz;
    }
    
    public int getCurrentRadius() {
        return MathUtil.ceil((Math.sqrt((double)this.i) - 1.0) / 2.0);
    }
    
    public int getCompletedRadius() {
        return (int)((Math.sqrt((double)this.i) - 1.0) / 2.0);
    }
    
    public static long getPosFromIndex(int index) {
        if (index < 0) {
            throw new IllegalArgumentException("Index mus be >= 0");
        }
        final int k = MathUtil.ceil((Math.sqrt(++index) - 1.0) / 2.0);
        final int t = 2 * k;
        int m = (int)Math.pow(1 + t, 2.0);
        final int m2 = m - t;
        if (index >= m2) {
            return ChunkUtil.indexChunk(k - (m - index), -k);
        }
        m = m2;
        final int m3 = m - t;
        if (index >= m3) {
            return ChunkUtil.indexChunk(-k, -k + (m - index));
        }
        m = m3;
        if (index >= m - t) {
            return ChunkUtil.indexChunk(-k + (m - index), k);
        }
        return ChunkUtil.indexChunk(k, k - (m - index - t));
    }
    
    static {
        MAX_RADIUS_LONG = (long)Math.sqrt(9.223372036854776E18) / 2L - 1L;
        MAX_RADIUS = (int)SpiralIterator.MAX_RADIUS_LONG;
    }
}
