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

import java.util.Map;
import com.google.common.collect.ImmutableMap;
import java.util.stream.Stream;
import com.mojang.datafixers.types.DynamicOps;
import java.util.function.Consumer;
import net.minecraft.world.level.levelgen.structure.templatesystem.JigsawReplacementProcessor;
import net.minecraft.world.level.levelgen.structure.templatesystem.BlockIgnoreProcessor;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import java.util.Collections;
import java.util.Random;
import java.util.Iterator;
import net.minecraft.world.level.block.state.properties.StructureMode;
import com.google.common.collect.Lists;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessorType;
import net.minecraft.util.Deserializer;
import net.minecraft.core.Registry;
import net.minecraft.world.level.levelgen.structure.templatesystem.NopProcessor;
import com.mojang.datafixers.Dynamic;
import java.util.Collection;
import java.util.List;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureProcessor;
import com.google.common.collect.ImmutableList;
import net.minecraft.resources.ResourceLocation;

public class SinglePoolElement extends StructurePoolElement {
    protected final ResourceLocation location;
    protected final ImmutableList<StructureProcessor> processors;
    
    @Deprecated
    public SinglePoolElement(final String string, final List<StructureProcessor> list) {
        this(string, list, StructureTemplatePool.Projection.RIGID);
    }
    
    public SinglePoolElement(final String string, final List<StructureProcessor> list, final StructureTemplatePool.Projection a) {
        super(a);
        this.location = new ResourceLocation(string);
        this.processors = ImmutableList.<StructureProcessor>copyOf(list);
    }
    
    @Deprecated
    public SinglePoolElement(final String string) {
        this(string, ImmutableList.of());
    }
    
    public SinglePoolElement(final Dynamic<?> dynamic) {
        super(dynamic);
        this.location = new ResourceLocation(dynamic.get("location").asString(""));
        this.processors = ImmutableList.<StructureProcessor>copyOf(dynamic.get("processors").asList(dynamic -> Deserializer.<Object, NopProcessor, StructureProcessorType>deserialize(dynamic, Registry.STRUCTURE_PROCESSOR, "processor_type", NopProcessor.INSTANCE)));
    }
    
    public List<StructureTemplate.StructureBlockInfo> getDataMarkers(final StructureManager cmo, final BlockPos fk, final Rotation btu, final boolean boolean4) {
        final StructureTemplate cms6 = cmo.getOrCreate(this.location);
        final List<StructureTemplate.StructureBlockInfo> list7 = cms6.filterBlocks(fk, new StructurePlaceSettings().setRotation(btu), Blocks.STRUCTURE_BLOCK, boolean4);
        final List<StructureTemplate.StructureBlockInfo> list8 = Lists.newArrayList();
        for (final StructureTemplate.StructureBlockInfo b10 : list7) {
            if (b10.nbt == null) {
                continue;
            }
            final StructureMode bzr11 = StructureMode.valueOf(b10.nbt.getString("mode"));
            if (bzr11 != StructureMode.DATA) {
                continue;
            }
            list8.add(b10);
        }
        return list8;
    }
    
    @Override
    public List<StructureTemplate.StructureBlockInfo> getShuffledJigsawBlocks(final StructureManager cmo, final BlockPos fk, final Rotation btu, final Random random) {
        final StructureTemplate cms6 = cmo.getOrCreate(this.location);
        final List<StructureTemplate.StructureBlockInfo> list7 = cms6.filterBlocks(fk, new StructurePlaceSettings().setRotation(btu), Blocks.JIGSAW, true);
        Collections.shuffle(list7, random);
        return list7;
    }
    
    @Override
    public BoundingBox getBoundingBox(final StructureManager cmo, final BlockPos fk, final Rotation btu) {
        final StructureTemplate cms5 = cmo.getOrCreate(this.location);
        return cms5.getBoundingBox(new StructurePlaceSettings().setRotation(btu), fk);
    }
    
    @Override
    public boolean place(final StructureManager cmo, final LevelAccessor bjx, final ChunkGenerator<?> caa, final BlockPos fk, final Rotation btu, final BoundingBox clb, final Random random) {
        final StructureTemplate cms9 = cmo.getOrCreate(this.location);
        final StructurePlaceSettings cmp10 = this.getSettings(btu, clb);
        if (cms9.placeInWorld(bjx, fk, cmp10, 18)) {
            final List<StructureTemplate.StructureBlockInfo> list11 = StructureTemplate.processBlockInfos(bjx, fk, cmp10, this.getDataMarkers(cmo, fk, btu, false));
            for (final StructureTemplate.StructureBlockInfo b13 : list11) {
                this.handleDataMarker(bjx, b13, fk, btu, random, clb);
            }
            return true;
        }
        return false;
    }
    
    protected StructurePlaceSettings getSettings(final Rotation btu, final BoundingBox clb) {
        final StructurePlaceSettings cmp4 = new StructurePlaceSettings();
        cmp4.setBoundingBox(clb);
        cmp4.setRotation(btu);
        cmp4.setKnownShape(true);
        cmp4.setIgnoreEntities(false);
        cmp4.addProcessor(BlockIgnoreProcessor.STRUCTURE_AND_AIR);
        cmp4.addProcessor(JigsawReplacementProcessor.INSTANCE);
        this.processors.forEach(cmp4::addProcessor);
        this.getProjection().getProcessors().forEach(cmp4::addProcessor);
        return cmp4;
    }
    
    @Override
    public StructurePoolElementType getType() {
        return StructurePoolElementType.SINGLE;
    }
    
    public <T> Dynamic<T> getDynamic(final DynamicOps<T> dynamicOps) {
        return (Dynamic<T>)new Dynamic((DynamicOps)dynamicOps, dynamicOps.createMap((Map)ImmutableMap.of(dynamicOps.createString("location"), dynamicOps.createString(this.location.toString()), dynamicOps.createString("processors"), dynamicOps.createList((Stream)this.processors.stream().map(cmq -> cmq.<T>serialize(dynamicOps).getValue())))));
    }
    
    @Override
    public String toString() {
        return "Single[" + this.location + "]";
    }
}
