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

package com.hypixel.hytale.server.core.universe.world.worldgen;

import com.hypixel.hytale.server.core.universe.world.chunk.section.BlockSection;
import com.hypixel.hytale.server.core.universe.world.chunk.BlockChunk;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.Holder;
import java.util.logging.Level;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.world.chunk.palette.ShortBytePalette;
import com.hypixel.hytale.protocol.Opacity;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.universe.world.chunk.environment.EnvironmentChunk;
import com.hypixel.hytale.server.core.universe.world.chunk.palette.IntBytePalette;
import com.hypixel.hytale.logger.HytaleLogger;

public class GeneratedBlockChunk
{
    private static final HytaleLogger LOGGER;
    protected long index;
    protected int x;
    protected int z;
    protected final IntBytePalette tint;
    protected final EnvironmentChunk environments;
    protected final GeneratedChunkSection[] chunkSections;
    
    public GeneratedBlockChunk() {
        this(0L, 0, 0);
    }
    
    public GeneratedBlockChunk(final long index, final int x, final int z) {
        this(index, x, z, new IntBytePalette(), new EnvironmentChunk(), new GeneratedChunkSection[10]);
    }
    
    public GeneratedBlockChunk(final long index, final int x, final int z, final IntBytePalette tint, final EnvironmentChunk environments, final GeneratedChunkSection[] chunkSections) {
        this.index = index;
        this.x = x;
        this.z = z;
        this.tint = tint;
        this.environments = environments;
        this.chunkSections = chunkSections;
    }
    
    public long getIndex() {
        return this.index;
    }
    
    public int getX() {
        return this.x;
    }
    
    public int getZ() {
        return this.z;
    }
    
    public void setCoordinates(final long index, final int x, final int z) {
        this.index = index;
        this.x = x;
        this.z = z;
    }
    
    public int getHeight(final int x, final int z) {
        int y = 320;
        while (--y > 0) {
            final GeneratedChunkSection section = this.getSection(y);
            if (section == null) {
                y = ChunkUtil.indexSection(y) * 32;
                if (y == 0) {
                    break;
                }
                continue;
            }
            else {
                final int blockId = section.getBlock(x, y, z);
                final BlockType type = BlockType.getAssetMap().getAsset(blockId);
                if (blockId != 0 && type != null && type.getOpacity() != Opacity.Transparent) {
                    break;
                }
                continue;
            }
        }
        return y;
    }
    
    @Nonnull
    public ShortBytePalette generateHeight() {
        final ShortBytePalette height = new ShortBytePalette();
        for (int x = 0; x < 32; ++x) {
            for (int z = 0; z < 32; ++z) {
                height.set(x, z, (short)this.getHeight(x, z));
            }
        }
        return height;
    }
    
    @Nullable
    public GeneratedChunkSection getSection(final int y) {
        final int index = ChunkUtil.indexSection(y);
        if (index >= 0 && index < this.chunkSections.length) {
            return this.chunkSections[index];
        }
        return null;
    }
    
    public int getTint(final int x, final int z) {
        return this.tint.get(x, z);
    }
    
    public void setTint(final int x, final int z, final int tint) {
        this.tint.set(x, z, tint);
    }
    
    public void setEnvironment(final int x, final int y, final int z, final int environment) {
        this.environments.set(x, y, z, environment);
    }
    
    public void setEnvironmentColumn(final int x, final int z, final int environment) {
        this.environments.setColumn(x, z, environment);
    }
    
    public int getEnvironment(final int x, final int y, final int z) {
        return this.environments.get(x, y, z);
    }
    
    public int getRotationIndex(final int x, final int y, final int z) {
        if (y < 0 || y >= 320) {
            return 0;
        }
        final GeneratedChunkSection section = this.getSection(y);
        if (section == null) {
            return 0;
        }
        return section.getRotationIndex(x, y, z);
    }
    
    public int getBlock(final int x, final int y, final int z) {
        if (y < 0 || y >= 320) {
            return 0;
        }
        final GeneratedChunkSection section = this.getSection(y);
        if (section == null) {
            return 0;
        }
        return section.getBlock(x, y, z);
    }
    
    public void setBlock(final int x, final int y, final int z, final int blockId, final int rotation, final int filler) {
        if (y < 0 || y >= 320) {
            GeneratedBlockChunk.LOGGER.at(Level.INFO).withCause(new Exception()).log("Failed to set block %d, %d, %d to %d because it is outside the world bounds", x, y, z, blockId);
            return;
        }
        GeneratedChunkSection section = this.getSection(y);
        final int sectionIndex = ChunkUtil.indexSection(y);
        if (section == null) {
            if (blockId == 0) {
                return;
            }
            section = this.initialize(sectionIndex);
        }
        section.setBlock(x, y, z, blockId, rotation, filler);
    }
    
    @Nonnull
    private GeneratedChunkSection initialize(final int section) {
        return this.chunkSections[section] = new GeneratedChunkSection();
    }
    
    public void removeSection(final int y) {
        final int index = ChunkUtil.indexSection(y);
        if (index >= 0 && index < this.chunkSections.length) {
            this.chunkSections[index] = null;
        }
    }
    
    @Nonnull
    public BlockChunk toBlockChunk(final Holder<ChunkStore>[] sectionHolders) {
        for (int y = 0; y < this.chunkSections.length; ++y) {
            final GeneratedChunkSection chunkSection = this.chunkSections[y];
            if (chunkSection != null) {
                sectionHolders[y].putComponent(BlockSection.getComponentType(), chunkSection.toChunkSection());
            }
        }
        final ShortBytePalette height = this.generateHeight();
        this.environments.trim();
        return new BlockChunk(this.x, this.z, height, this.tint, this.environments);
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
}
