package net.minecraft.world.level;

import java.util.Spliterator;
import java.util.stream.StreamSupport;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import java.util.Spliterators;
import java.util.stream.Stream;
import net.minecraft.core.BlockPos;

public class ChunkPos {
    public static final long INVALID_CHUNK_POS;
    public final int x;
    public final int z;
    
    public ChunkPos(final int integer1, final int integer2) {
        this.x = integer1;
        this.z = integer2;
    }
    
    public ChunkPos(final BlockPos fu) {
        this.x = fu.getX() >> 4;
        this.z = fu.getZ() >> 4;
    }
    
    public ChunkPos(final long long1) {
        this.x = (int)long1;
        this.z = (int)(long1 >> 32);
    }
    
    public long toLong() {
        return asLong(this.x, this.z);
    }
    
    public static long asLong(final int integer1, final int integer2) {
        return ((long)integer1 & 0xFFFFFFFFL) | ((long)integer2 & 0xFFFFFFFFL) << 32;
    }
    
    public static int getX(final long long1) {
        return (int)(long1 & 0xFFFFFFFFL);
    }
    
    public static int getZ(final long long1) {
        return (int)(long1 >>> 32 & 0xFFFFFFFFL);
    }
    
    @Override
    public int hashCode() {
        final int integer2 = 1664525 * this.x + 1013904223;
        final int integer3 = 1664525 * (this.z ^ 0xDEADBEEF) + 1013904223;
        return integer2 ^ integer3;
    }
    
    @Override
    public boolean equals(final Object object) {
        if (this == object) {
            return true;
        }
        if (object instanceof ChunkPos) {
            final ChunkPos bph3 = (ChunkPos)object;
            return this.x == bph3.x && this.z == bph3.z;
        }
        return false;
    }
    
    public int getMinBlockX() {
        return this.x << 4;
    }
    
    public int getMinBlockZ() {
        return this.z << 4;
    }
    
    public int getMaxBlockX() {
        return (this.x << 4) + 15;
    }
    
    public int getMaxBlockZ() {
        return (this.z << 4) + 15;
    }
    
    public int getRegionX() {
        return this.x >> 5;
    }
    
    public int getRegionZ() {
        return this.z >> 5;
    }
    
    public int getRegionLocalX() {
        return this.x & 0x1F;
    }
    
    public int getRegionLocalZ() {
        return this.z & 0x1F;
    }
    
    public BlockPos getBlockAt(final int integer1, final int integer2, final int integer3) {
        return new BlockPos((this.x << 4) + integer1, integer2, (this.z << 4) + integer3);
    }
    
    @Override
    public String toString() {
        return "[" + this.x + ", " + this.z + "]";
    }
    
    public BlockPos getWorldPosition() {
        return new BlockPos(this.getMinBlockX(), 0, this.getMinBlockZ());
    }
    
    public int getChessboardDistance(final ChunkPos bph) {
        return Math.max(Math.abs(this.x - bph.x), Math.abs(this.z - bph.z));
    }
    
    public static Stream<ChunkPos> rangeClosed(final ChunkPos bph, final int integer) {
        return rangeClosed(new ChunkPos(bph.x - integer, bph.z - integer), new ChunkPos(bph.x + integer, bph.z + integer));
    }
    
    public static Stream<ChunkPos> rangeClosed(final ChunkPos bph1, final ChunkPos bph2) {
        final int integer3 = Math.abs(bph1.x - bph2.x) + 1;
        final int integer4 = Math.abs(bph1.z - bph2.z) + 1;
        final int integer5 = (bph1.x < bph2.x) ? 1 : -1;
        final int integer6 = (bph1.z < bph2.z) ? 1 : -1;
        return StreamSupport.<ChunkPos>stream((Spliterator<ChunkPos>)new Spliterators.AbstractSpliterator<ChunkPos>((long)(integer3 * integer4), 64) {
            @Nullable
            private ChunkPos pos;
            
            @Override
            public boolean tryAdvance(final Consumer<? super ChunkPos> consumer) {
                if (this.pos == null) {
                    this.pos = bph1;
                }
                else {
                    final int integer3 = this.pos.x;
                    final int integer4 = this.pos.z;
                    if (integer3 == bph2.x) {
                        if (integer4 == bph2.z) {
                            return false;
                        }
                        this.pos = new ChunkPos(bph1.x, integer4 + integer6);
                    }
                    else {
                        this.pos = new ChunkPos(integer3 + integer5, integer4);
                    }
                }
                consumer.accept(this.pos);
                return true;
            }
        }, false);
    }
    
    static {
        INVALID_CHUNK_POS = asLong(1875016, 1875016);
    }
}
