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

import net.minecraft.world.level.LevelSimulatedReader;
import net.minecraft.world.level.levelgen.Heightmap;
import java.util.Optional;
import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import java.util.Set;
import net.minecraft.core.BlockPos;
import java.util.Random;
import net.minecraft.world.level.LevelSimulatedRW;
import com.mojang.datafixers.Dynamic;
import java.util.function.Function;
import net.minecraft.world.level.levelgen.feature.configurations.SmallTreeConfiguration;

public abstract class AbstractSmallTreeFeature<T extends SmallTreeConfiguration> extends AbstractTreeFeature<T> {
    public AbstractSmallTreeFeature(final Function<Dynamic<?>, ? extends T> function) {
        super(function);
    }
    
    protected void placeTrunk(final LevelSimulatedRW bkb, final Random random, final int integer3, final BlockPos fk, final int integer5, final Set<BlockPos> set, final BoundingBox clb, final SmallTreeConfiguration chi) {
        for (int integer6 = 0; integer6 < integer3 - integer5; ++integer6) {
            this.placeLog(bkb, random, fk.above(integer6), set, clb, chi);
        }
    }
    
    public Optional<BlockPos> getProjectedOrigin(final LevelSimulatedRW bkb, final int integer2, final int integer3, final int integer4, final BlockPos fk, final SmallTreeConfiguration chi) {
        BlockPos fk2;
        if (!chi.fromSapling) {
            final int integer5 = bkb.getHeightmapPos(Heightmap.Types.OCEAN_FLOOR, fk).getY();
            final int integer6 = bkb.getHeightmapPos(Heightmap.Types.WORLD_SURFACE, fk).getY();
            fk2 = new BlockPos(fk.getX(), integer5, fk.getZ());
            if (integer6 - integer5 > chi.maxWaterDepth) {
                return Optional.<BlockPos>empty();
            }
        }
        else {
            fk2 = fk;
        }
        if (fk2.getY() < 1 || fk2.getY() + integer2 + 1 > 256) {
            return Optional.<BlockPos>empty();
        }
        for (int integer5 = 0; integer5 <= integer2 + 1; ++integer5) {
            final int integer6 = chi.foliagePlacer.getTreeRadiusForHeight(integer3, integer2, integer4, integer5);
            final BlockPos.MutableBlockPos a11 = new BlockPos.MutableBlockPos();
            for (int integer7 = -integer6; integer7 <= integer6; ++integer7) {
                for (int integer8 = -integer6; integer8 <= integer6; ++integer8) {
                    if (integer5 + fk2.getY() < 0 || integer5 + fk2.getY() >= 256) {
                        return Optional.<BlockPos>empty();
                    }
                    a11.set(integer7 + fk2.getX(), integer5 + fk2.getY(), integer8 + fk2.getZ());
                    if (!AbstractTreeFeature.isFree(bkb, a11) || (!chi.ignoreVines && AbstractTreeFeature.isVine(bkb, a11))) {
                        return Optional.<BlockPos>empty();
                    }
                }
            }
        }
        if (!AbstractTreeFeature.isGrassOrDirtOrFarmland(bkb, fk2.below()) || fk2.getY() >= 256 - integer2 - 1) {
            return Optional.<BlockPos>empty();
        }
        return Optional.<BlockPos>of(fk2);
    }
}
