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

package com.hypixel.hytale.server.spawning.util;

import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import java.util.Random;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;

public class RandomChunkColumnIterator
{
    @Nonnull
    private final ChunkColumnMask availablePositions;
    @Nullable
    private final ChunkColumnMask initialPositions;
    @Nonnull
    private final Random random;
    private final long seed;
    private int currentIndex;
    private int lastSavedIteratorPosition;
    
    public RandomChunkColumnIterator() {
        this.availablePositions = new ChunkColumnMask();
        this.random = new Random();
        this.initialPositions = null;
        this.seed = this.random.nextLong();
    }
    
    public RandomChunkColumnIterator(@Nonnull final ChunkColumnMask initialPositions) {
        this.availablePositions = new ChunkColumnMask();
        this.random = new Random();
        this.initialPositions = initialPositions;
        if (initialPositions.isEmpty()) {
            throw new IllegalArgumentException();
        }
        this.seed = this.random.nextLong();
    }
    
    public RandomChunkColumnIterator(final ChunkColumnMask initialPositions, @Nonnull final WorldChunk chunk) {
        this.availablePositions = new ChunkColumnMask();
        this.random = new Random();
        this.initialPositions = initialPositions;
        this.seed = (chunk.getX() * 151L + chunk.getZ()) * 131L;
    }
    
    public int getCurrentIndex() {
        return this.currentIndex;
    }
    
    public int getCurrentX() {
        return ChunkUtil.xFromColumn(this.currentIndex);
    }
    
    public int getCurrentZ() {
        return ChunkUtil.zFromColumn(this.currentIndex);
    }
    
    @Nullable
    public ChunkColumnMask getInitialPositions() {
        return this.initialPositions;
    }
    
    public int nextPosition() {
        if (this.availablePositions.isEmpty()) {
            this.reset();
        }
        final int start = this.random.nextInt(1024);
        int index = this.availablePositions.nextSetBit(start);
        if (index == -1) {
            index = this.availablePositions.previousSetBit(start);
        }
        return this.nextPosition(index);
    }
    
    public int nextPositionAvoidBorders() {
        if (this.availablePositions.isEmpty()) {
            this.reset();
        }
        final int index = this.random.nextInt(1024);
        int start;
        int end;
        if (this.availablePositions.get(index)) {
            start = this.availablePositions.previousClearBit(index) + 1;
            end = this.availablePositions.nextClearBit(index) - 1;
        }
        else {
            end = this.availablePositions.previousSetBit(index);
            start = this.availablePositions.nextSetBit(index);
            if (end == -1 || (start != -1 && index - end > start - index)) {
                end = this.availablePositions.nextClearBit(start) - 1;
            }
            else {
                start = this.availablePositions.previousClearBit(end) + 1;
            }
        }
        final int range = end - start + 1;
        if (range > 3) {
            start += 1 + this.random.nextInt(range - 2);
        }
        else if (range > 1) {
            start += this.random.nextInt(range);
        }
        if (!this.availablePositions.get(start)) {
            throw new IllegalArgumentException();
        }
        return this.nextPosition(start);
    }
    
    public void saveIteratorPosition() {
        this.lastSavedIteratorPosition = this.positionsLeft();
    }
    
    public boolean isAtSavedIteratorPosition() {
        return this.positionsLeft() == this.lastSavedIteratorPosition;
    }
    
    public int positionsLeft() {
        return this.availablePositions.cardinality();
    }
    
    public void markPositionVisited(final int index) {
        this.availablePositions.clear(index);
    }
    
    public void markPositionVisited() {
        this.markPositionVisited(this.currentIndex);
    }
    
    private void reset() {
        this.random.setSeed(this.seed);
        if (this.initialPositions == null) {
            this.availablePositions.set();
        }
        else {
            if (this.initialPositions.isEmpty()) {
                throw new IllegalArgumentException();
            }
            this.availablePositions.copyFrom(this.initialPositions);
        }
    }
    
    private int nextPosition(final int index) {
        if (index == -1) {
            throw new IllegalArgumentException();
        }
        this.markPositionVisited(index);
        return this.currentIndex = index;
    }
}
