package net.minecraft.world.level.levelgen.feature;

import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
import javax.annotation.Nullable;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.LevelWriter;
import net.minecraft.world.level.block.Blocks;
import java.util.Iterator;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.core.Direction;
import net.minecraft.core.BlockPos;
import java.util.Random;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.WorldGenLevel;
import com.mojang.serialization.Codec;
import net.minecraft.world.level.block.Block;
import com.google.common.collect.ImmutableList;
import net.minecraft.world.level.levelgen.feature.configurations.ColumnFeatureConfiguration;

public class BasaltColumnsFeature extends Feature<ColumnFeatureConfiguration> {
    private static final ImmutableList<Block> CANNOT_PLACE_ON;
    
    public BasaltColumnsFeature(final Codec<ColumnFeatureConfiguration> codec) {
        super(codec);
    }
    
    @Override
    public boolean place(final WorldGenLevel bqu, final StructureFeatureManager bqq, final ChunkGenerator cha, final Random random, final BlockPos fu, final ColumnFeatureConfiguration cnj) {
        final int integer8 = cha.getSeaLevel();
        final BlockPos fu2 = findSurface(bqu, integer8, fu.mutable().clamp(Direction.Axis.Y, 1, bqu.getMaxBuildHeight() - 1), Integer.MAX_VALUE);
        if (fu2 == null) {
            return false;
        }
        final int integer9 = calculateHeight(random, cnj);
        final boolean boolean11 = random.nextFloat() < 0.9f;
        final int integer10 = Math.min(integer9, boolean11 ? 5 : 8);
        final int integer11 = boolean11 ? 50 : 15;
        boolean boolean12 = false;
        for (final BlockPos fu3 : BlockPos.randomBetweenClosed(random, integer11, fu2.getX() - integer10, fu2.getY(), fu2.getZ() - integer10, fu2.getX() + integer10, fu2.getY(), fu2.getZ() + integer10)) {
            final int integer12 = integer9 - fu3.distManhattan(fu2);
            if (integer12 >= 0) {
                boolean12 |= this.placeColumn(bqu, integer8, fu3, integer12, calculateReach(random, cnj));
            }
        }
        return boolean12;
    }
    
    private boolean placeColumn(final LevelAccessor bqc, final int integer2, final BlockPos fu, final int integer4, final int integer5) {
        boolean boolean7 = false;
        for (final BlockPos fu2 : BlockPos.betweenClosed(fu.getX() - integer5, fu.getY(), fu.getZ() - integer5, fu.getX() + integer5, fu.getY(), fu.getZ() + integer5)) {
            final int integer6 = fu2.distManhattan(fu);
            final BlockPos fu3 = isAirOrLavaOcean(bqc, integer2, fu2) ? findSurface(bqc, integer2, fu2.mutable(), integer6) : findAir(bqc, fu2.mutable(), integer6);
            if (fu3 == null) {
                continue;
            }
            int integer7 = integer4 - integer6 / 2;
            final BlockPos.MutableBlockPos a13 = fu3.mutable();
            while (integer7 >= 0) {
                if (isAirOrLavaOcean(bqc, integer2, a13)) {
                    this.setBlock(bqc, a13, Blocks.BASALT.defaultBlockState());
                    a13.move(Direction.UP);
                    boolean7 = true;
                }
                else {
                    if (!bqc.getBlockState(a13).is(Blocks.BASALT)) {
                        break;
                    }
                    a13.move(Direction.UP);
                }
                --integer7;
            }
        }
        return boolean7;
    }
    
    @Nullable
    private static BlockPos findSurface(final LevelAccessor bqc, final int integer2, final BlockPos.MutableBlockPos a, int integer4) {
        while (a.getY() > 1 && integer4 > 0) {
            --integer4;
            if (isAirOrLavaOcean(bqc, integer2, a)) {
                final BlockState cfj5 = bqc.getBlockState(a.move(Direction.DOWN));
                a.move(Direction.UP);
                if (!cfj5.isAir() && !BasaltColumnsFeature.CANNOT_PLACE_ON.contains(cfj5.getBlock())) {
                    return a;
                }
            }
            a.move(Direction.DOWN);
        }
        return null;
    }
    
    @Nullable
    private static BlockPos findAir(final LevelAccessor bqc, final BlockPos.MutableBlockPos a, int integer) {
        while (a.getY() < bqc.getMaxBuildHeight() && integer > 0) {
            --integer;
            final BlockState cfj4 = bqc.getBlockState(a);
            if (BasaltColumnsFeature.CANNOT_PLACE_ON.contains(cfj4.getBlock())) {
                return null;
            }
            if (cfj4.isAir()) {
                return a;
            }
            a.move(Direction.UP);
        }
        return null;
    }
    
    private static int calculateHeight(final Random random, final ColumnFeatureConfiguration cnj) {
        return cnj.minimumHeight + random.nextInt(cnj.maximumHeight - cnj.minimumHeight + 1);
    }
    
    private static int calculateReach(final Random random, final ColumnFeatureConfiguration cnj) {
        return cnj.minimumReach + random.nextInt(cnj.maximumReach - cnj.minimumReach + 1);
    }
    
    private static boolean isAirOrLavaOcean(final LevelAccessor bqc, final int integer, final BlockPos fu) {
        final BlockState cfj4 = bqc.getBlockState(fu);
        return cfj4.isAir() || (cfj4.is(Blocks.LAVA) && fu.getY() <= integer);
    }
    
    static {
        CANNOT_PLACE_ON = ImmutableList.<Block>of(Blocks.LAVA, Blocks.BEDROCK, Blocks.MAGMA_BLOCK, Blocks.SOUL_SAND, Blocks.NETHER_BRICKS, Blocks.NETHER_BRICK_FENCE, Blocks.NETHER_BRICK_STAIRS, Blocks.NETHER_WART, Blocks.CHEST, Blocks.SPAWNER);
    }
}
