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

import java.util.AbstractList;
import net.minecraft.world.level.levelgen.feature.Feature;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import java.util.Iterator;
import net.minecraft.world.level.ChunkPos;
import java.util.Random;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.chunk.ChunkGenerator;
import com.google.common.collect.Lists;
import net.minecraft.world.level.levelgen.WorldgenRandom;
import java.util.List;
import net.minecraft.world.level.levelgen.feature.StructureFeature;

public abstract class StructureStart {
    public static final StructureStart INVALID_START;
    private final StructureFeature<?> feature;
    protected final List<StructurePiece> pieces;
    protected BoundingBox boundingBox;
    private final int chunkX;
    private final int chunkZ;
    private int references;
    protected final WorldgenRandom random;
    
    public StructureStart(final StructureFeature<?> cfl, final int integer2, final int integer3, final BoundingBox clb, final int integer5, final long long6) {
        this.pieces = Lists.newArrayList();
        this.feature = cfl;
        this.chunkX = integer2;
        this.chunkZ = integer3;
        this.references = integer5;
        (this.random = new WorldgenRandom()).setLargeFeatureSeed(long6, integer2, integer3);
        this.boundingBox = clb;
    }
    
    public abstract void generatePieces(final ChunkGenerator<?> caa, final StructureManager cmo, final int integer3, final int integer4, final Biome bkt);
    
    public BoundingBox getBoundingBox() {
        return this.boundingBox;
    }
    
    public List<StructurePiece> getPieces() {
        return this.pieces;
    }
    
    public void postProcess(final LevelAccessor bjx, final ChunkGenerator<?> caa, final Random random, final BoundingBox clb, final ChunkPos bjh) {
        synchronized (this.pieces) {
            final Iterator<StructurePiece> iterator8 = this.pieces.iterator();
            while (iterator8.hasNext()) {
                final StructurePiece clu9 = iterator8.next();
                if (clu9.getBoundingBox().intersects(clb) && !clu9.postProcess(bjx, caa, random, clb, bjh)) {
                    iterator8.remove();
                }
            }
            this.calculateBoundingBox();
        }
    }
    
    protected void calculateBoundingBox() {
        this.boundingBox = BoundingBox.getUnknownBox();
        for (final StructurePiece clu3 : this.pieces) {
            this.boundingBox.expand(clu3.getBoundingBox());
        }
    }
    
    public CompoundTag createTag(final int integer1, final int integer2) {
        final CompoundTag jt4 = new CompoundTag();
        if (this.isValid()) {
            jt4.putString("id", Registry.STRUCTURE_FEATURE.getKey(this.getFeature()).toString());
            jt4.putInt("ChunkX", integer1);
            jt4.putInt("ChunkZ", integer2);
            jt4.putInt("references", this.references);
            jt4.put("BB", this.boundingBox.createTag());
            final ListTag jz5 = new ListTag();
            synchronized (this.pieces) {
                for (final StructurePiece clu8 : this.pieces) {
                    ((AbstractList<CompoundTag>)jz5).add(clu8.createTag());
                }
            }
            jt4.put("Children", jz5);
            return jt4;
        }
        jt4.putString("id", "INVALID");
        return jt4;
    }
    
    protected void moveBelowSeaLevel(final int integer1, final Random random, final int integer3) {
        final int integer4 = integer1 - integer3;
        int integer5 = this.boundingBox.getYSpan() + 1;
        if (integer5 < integer4) {
            integer5 += random.nextInt(integer4 - integer5);
        }
        final int integer6 = integer5 - this.boundingBox.y1;
        this.boundingBox.move(0, integer6, 0);
        for (final StructurePiece clu9 : this.pieces) {
            clu9.move(0, integer6, 0);
        }
    }
    
    protected void moveInsideHeights(final Random random, final int integer2, final int integer3) {
        final int integer4 = integer3 - integer2 + 1 - this.boundingBox.getYSpan();
        int integer5;
        if (integer4 > 1) {
            integer5 = integer2 + random.nextInt(integer4);
        }
        else {
            integer5 = integer2;
        }
        final int integer6 = integer5 - this.boundingBox.y0;
        this.boundingBox.move(0, integer6, 0);
        for (final StructurePiece clu9 : this.pieces) {
            clu9.move(0, integer6, 0);
        }
    }
    
    public boolean isValid() {
        return !this.pieces.isEmpty();
    }
    
    public int getChunkX() {
        return this.chunkX;
    }
    
    public int getChunkZ() {
        return this.chunkZ;
    }
    
    public BlockPos getLocatePos() {
        return new BlockPos(this.chunkX << 4, 0, this.chunkZ << 4);
    }
    
    public boolean canBeReferenced() {
        return this.references < this.getMaxReferences();
    }
    
    public void addReference() {
        ++this.references;
    }
    
    public int getReferences() {
        return this.references;
    }
    
    protected int getMaxReferences() {
        return 1;
    }
    
    public StructureFeature<?> getFeature() {
        return this.feature;
    }
    
    static {
        INVALID_START = new StructureStart(Feature.MINESHAFT, 0, 0, BoundingBox.getUnknownBox(), 0, 0L) {
            @Override
            public void generatePieces(final ChunkGenerator<?> caa, final StructureManager cmo, final int integer3, final int integer4, final Biome bkt) {
            }
        };
    }
}
