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

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

public abstract class MegaTreeFeature<T extends TreeConfiguration> extends AbstractTreeFeature<T> {
    public MegaTreeFeature(final Function<Dynamic<?>, ? extends T> function) {
        super(function);
    }
    
    protected int calcTreeHeigth(final Random random, final MegaTreeConfiguration cgr) {
        int integer4 = random.nextInt(3) + cgr.baseHeight;
        if (cgr.heightInterval > 1) {
            integer4 += random.nextInt(cgr.heightInterval);
        }
        return integer4;
    }
    
    private boolean checkIsFree(final LevelSimulatedReader bkc, final BlockPos fk, final int integer) {
        boolean boolean5 = true;
        if (fk.getY() < 1 || fk.getY() + integer + 1 > 256) {
            return false;
        }
        for (int integer2 = 0; integer2 <= 1 + integer; ++integer2) {
            int integer3 = 2;
            if (integer2 == 0) {
                integer3 = 1;
            }
            else if (integer2 >= 1 + integer - 2) {
                integer3 = 2;
            }
            for (int integer4 = -integer3; integer4 <= integer3 && boolean5; ++integer4) {
                for (int integer5 = -integer3; integer5 <= integer3 && boolean5; ++integer5) {
                    if (fk.getY() + integer2 < 0 || fk.getY() + integer2 >= 256 || !AbstractTreeFeature.isFree(bkc, fk.offset(integer4, integer2, integer5))) {
                        boolean5 = false;
                    }
                }
            }
        }
        return boolean5;
    }
    
    private boolean makeDirtFloor(final LevelSimulatedRW bkb, final BlockPos fk) {
        final BlockPos fk2 = fk.below();
        if (!AbstractTreeFeature.isGrassOrDirt(bkb, fk2) || fk.getY() < 2) {
            return false;
        }
        this.setDirtAt(bkb, fk2);
        this.setDirtAt(bkb, fk2.east());
        this.setDirtAt(bkb, fk2.south());
        this.setDirtAt(bkb, fk2.south().east());
        return true;
    }
    
    protected boolean prepareTree(final LevelSimulatedRW bkb, final BlockPos fk, final int integer) {
        return this.checkIsFree(bkb, fk, integer) && this.makeDirtFloor(bkb, fk);
    }
    
    protected void placeDoubleTrunkLeaves(final LevelSimulatedRW bkb, final Random random, final BlockPos fk, final int integer, final Set<BlockPos> set, final BoundingBox clb, final TreeConfiguration chl) {
        final int integer2 = integer * integer;
        for (int integer3 = -integer; integer3 <= integer + 1; ++integer3) {
            for (int integer4 = -integer; integer4 <= integer + 1; ++integer4) {
                final int integer5 = Math.min(Math.abs(integer3), Math.abs(integer3 - 1));
                final int integer6 = Math.min(Math.abs(integer4), Math.abs(integer4 - 1));
                if (integer5 + integer6 < 7) {
                    if (integer5 * integer5 + integer6 * integer6 <= integer2) {
                        this.placeLeaf(bkb, random, fk.offset(integer3, 0, integer4), set, clb, chl);
                    }
                }
            }
        }
    }
    
    protected void placeSingleTrunkLeaves(final LevelSimulatedRW bkb, final Random random, final BlockPos fk, final int integer, final Set<BlockPos> set, final BoundingBox clb, final TreeConfiguration chl) {
        final int integer2 = integer * integer;
        for (int integer3 = -integer; integer3 <= integer; ++integer3) {
            for (int integer4 = -integer; integer4 <= integer; ++integer4) {
                if (integer3 * integer3 + integer4 * integer4 <= integer2) {
                    this.placeLeaf(bkb, random, fk.offset(integer3, 0, integer4), set, clb, chl);
                }
            }
        }
    }
    
    protected void placeTrunk(final LevelSimulatedRW bkb, final Random random, final BlockPos fk, final int integer, final Set<BlockPos> set, final BoundingBox clb, final MegaTreeConfiguration cgr) {
        final BlockPos.MutableBlockPos a9 = new BlockPos.MutableBlockPos();
        for (int integer2 = 0; integer2 < integer; ++integer2) {
            a9.set(fk).move(0, integer2, 0);
            if (AbstractTreeFeature.isFree(bkb, a9)) {
                this.placeLog(bkb, random, a9, set, clb, cgr);
            }
            if (integer2 < integer - 1) {
                a9.set(fk).move(1, integer2, 0);
                if (AbstractTreeFeature.isFree(bkb, a9)) {
                    this.placeLog(bkb, random, a9, set, clb, cgr);
                }
                a9.set(fk).move(1, integer2, 1);
                if (AbstractTreeFeature.isFree(bkb, a9)) {
                    this.placeLog(bkb, random, a9, set, clb, cgr);
                }
                a9.set(fk).move(0, integer2, 1);
                if (AbstractTreeFeature.isFree(bkb, a9)) {
                    this.placeLog(bkb, random, a9, set, clb, cgr);
                }
            }
        }
    }
}
