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

package com.hypixel.hytale.server.worldgen.cave.shape;

import com.hypixel.hytale.server.worldgen.util.BlockFluidEntry;
import com.hypixel.hytale.server.worldgen.util.bounds.IWorldBounds;
import com.hypixel.hytale.server.worldgen.cave.CaveType;
import com.hypixel.hytale.assetstore.map.BlockTypeAssetMap;
import com.hypixel.hytale.server.core.universe.world.worldgen.GeneratedBlockChunk;
import com.hypixel.hytale.server.worldgen.cave.CaveNodeType;
import com.hypixel.hytale.math.util.ChunkUtil;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import java.util.Random;
import com.hypixel.hytale.server.worldgen.cave.element.CaveNode;
import com.hypixel.hytale.server.worldgen.cave.Cave;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.worldgen.chunk.ChunkGeneratorExecution;

public abstract class AbstractCaveNodeShape implements CaveNodeShape
{
    @Override
    public void populateChunk(final int seed, @Nonnull final ChunkGeneratorExecution execution, @Nonnull final Cave cave, @Nonnull final CaveNode node, @Nonnull final Random random) {
        final GeneratedBlockChunk chunk = execution.getChunk();
        final BlockTypeAssetMap<String, BlockType> blockTypeMap = BlockType.getAssetMap();
        final CaveType caveType = cave.getCaveType();
        final CaveNodeType caveNodeType = node.getCaveNodeType();
        final IWorldBounds shapeBounds = this.getBounds();
        final boolean surfaceLimited = cave.getCaveType().isSurfaceLimited();
        final int environment = node.getCaveNodeType().hasEnvironment() ? node.getCaveNodeType().getEnvironment() : caveType.getEnvironment();
        final int chunkLowX = ChunkUtil.minBlock(execution.getX());
        final int chunkLowZ = ChunkUtil.minBlock(execution.getZ());
        final int chunkHighX = ChunkUtil.maxBlock(execution.getX());
        final int chunkHighZ = ChunkUtil.maxBlock(execution.getZ());
        final int minX = Math.max(chunkLowX, shapeBounds.getLowBoundX());
        final int minY = shapeBounds.getLowBoundY();
        final int minZ = Math.max(chunkLowZ, shapeBounds.getLowBoundZ());
        final int maxX = Math.min(chunkHighX, shapeBounds.getHighBoundX());
        final int maxY = shapeBounds.getHighBoundY();
        final int maxZ = Math.min(chunkHighZ, shapeBounds.getHighBoundZ());
        for (int x = minX; x <= maxX; ++x) {
            final int cx = x - chunkLowX;
            for (int z = minZ; z <= maxZ; ++z) {
                final int cz = z - chunkLowZ;
                int height = maxY;
                boolean heightLimited = false;
                if (surfaceLimited) {
                    final int chunkHeight = chunk.getHeight(cx, cz);
                    if (height >= chunkHeight) {
                        height = chunkHeight;
                        heightLimited = true;
                    }
                }
                int lowest = Integer.MAX_VALUE;
                int lowestPossible = Integer.MAX_VALUE;
                int highest = Integer.MIN_VALUE;
                int highestPossible = Integer.MIN_VALUE;
                for (int y = minY; y <= height; ++y) {
                    if (this.shouldReplace(seed, x, z, y)) {
                        if (y < lowestPossible) {
                            lowestPossible = y;
                        }
                        if (y > highestPossible) {
                            highestPossible = y;
                        }
                        final int current = execution.getBlock(cx, y, cz);
                        final int currentFluid = execution.getFluid(cx, y, cz);
                        final boolean isCandidateBlock = !surfaceLimited || current != 0;
                        if (isCandidateBlock) {
                            final BlockFluidEntry blockEntry = CaveNodeShapeUtils.getFillingBlock(caveType, caveNodeType, y, random);
                            if (caveType.getBlockMask().eval(current, currentFluid, blockEntry.blockId(), blockEntry.fluidId())) {
                                if (execution.setBlock(cx, y, cz, (byte)6, blockEntry, environment)) {
                                    if (y < lowest) {
                                        lowest = y;
                                    }
                                    if (y > highest) {
                                        highest = y;
                                    }
                                }
                                if (execution.setFluid(cx, y, cz, (byte)6, blockEntry.fluidId(), environment)) {
                                    if (y < lowest) {
                                        lowest = y;
                                    }
                                    if (y > highest) {
                                        highest = y;
                                    }
                                }
                            }
                        }
                    }
                }
                final CaveNodeType.CaveNodeCoverEntry[] covers2;
                final CaveNodeType.CaveNodeCoverEntry[] covers = covers2 = caveNodeType.getCovers();
                for (final CaveNodeType.CaveNodeCoverEntry cover : covers2) {
                    final CaveNodeType.CaveNodeCoverEntry.Entry entry = cover.get(random);
                    final int y2 = CaveNodeShapeUtils.getCoverHeight(lowest, lowestPossible, highest, highestPossible, heightLimited, cover, entry);
                    if (y2 >= 0 && cover.getDensityCondition().eval(seed + node.getSeedOffset(), x, z) && cover.getHeightCondition().eval(seed, x, z, y2, random) && cover.getMapCondition().eval(seed, x, z) && CaveNodeShapeUtils.isCoverMatchingParent(cx, cz, y2, execution, cover)) {
                        execution.setBlock(cx, y2, cz, (byte)5, entry.getEntry(), environment);
                        execution.setFluid(cx, y2, cz, (byte)5, entry.getEntry().fluidId(), environment);
                    }
                }
                if (CaveNodeShapeUtils.invalidateCover(cx, lowest - 1, cz, CaveNodeType.CaveNodeCoverType.CEILING, execution, blockTypeMap)) {
                    final BlockFluidEntry blockEntry2 = CaveNodeShapeUtils.getFillingBlock(caveType, caveNodeType, lowest - 1, random);
                    execution.overrideBlock(cx, lowest - 1, cz, (byte)6, blockEntry2);
                    execution.overrideFluid(cx, lowest - 1, cz, (byte)6, blockEntry2.fluidId());
                }
                if (CaveNodeShapeUtils.invalidateCover(cx, highest + 1, cz, CaveNodeType.CaveNodeCoverType.FLOOR, execution, blockTypeMap)) {
                    final BlockFluidEntry blockEntry2 = CaveNodeShapeUtils.getFillingBlock(caveType, caveNodeType, highest + 1, random);
                    execution.overrideBlock(cx, highest + 1, cz, (byte)6, blockEntry2);
                    execution.overrideFluid(cx, highest + 1, cz, (byte)6, blockEntry2.fluidId());
                }
            }
        }
    }
}
