// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.core.universe.world.meta.state;

import com.hypixel.hytale.codec.KeyedCodec;
import com.hypixel.hytale.codec.builder.BuilderCodec;
import com.hypixel.hytale.math.vector.Vector3d;
import com.hypixel.hytale.server.core.entity.entities.player.windows.WindowManager;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.Holder;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import java.util.List;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.StateData;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.core.modules.entity.item.ItemComponent;
import com.hypixel.hytale.math.vector.Vector3f;
import java.util.logging.Level;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.event.EventPriority;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import java.util.concurrent.ConcurrentHashMap;
import com.hypixel.hytale.server.core.universe.world.worldmap.WorldMapManager;
import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.entity.entities.player.windows.ContainerBlockWindow;
import java.util.UUID;
import java.util.Map;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.server.core.universe.world.meta.BlockState;

public class ItemContainerState extends BlockState implements ItemContainerBlockState, DestroyableBlockState, MarkerBlockState
{
    public static final Codec<ItemContainerState> CODEC;
    private final Map<UUID, ContainerBlockWindow> windows;
    protected boolean custom;
    protected boolean allowViewing;
    @Nullable
    protected String droplist;
    protected SimpleItemContainer itemContainer;
    protected WorldMapManager.MarkerReference marker;
    
    public ItemContainerState() {
        this.windows = new ConcurrentHashMap<UUID, ContainerBlockWindow>();
        this.allowViewing = true;
    }
    
    @Override
    public boolean initialize(@Nonnull final BlockType blockType) {
        if (!super.initialize(blockType)) {
            return false;
        }
        if (this.custom) {
            return true;
        }
        short capacity = 20;
        final StateData state = blockType.getState();
        if (state instanceof final ItemContainerStateData itemContainerStateData) {
            capacity = itemContainerStateData.getCapacity();
        }
        final List<ItemStack> remainder = new ObjectArrayList<ItemStack>();
        (this.itemContainer = ItemContainer.ensureContainerCapacity(this.itemContainer, capacity, SimpleItemContainer::new, remainder)).registerChangeEvent(EventPriority.LAST, this::onItemChange);
        if (!remainder.isEmpty()) {
            final WorldChunk chunk = this.getChunk();
            final World world = chunk.getWorld();
            final Store<EntityStore> store = world.getEntityStore().getStore();
            HytaleLogger.getLogger().at(Level.WARNING).withCause(new Throwable()).log("Dropping %d excess items from item container: %s at world: %s, chunk: %s, block: %s", remainder.size(), blockType.getId(), chunk.getWorld().getName(), chunk, this.getPosition());
            final Vector3i blockPosition = this.getBlockPosition();
            final Holder<EntityStore>[] itemEntityHolders = ItemComponent.generateItemDrops(store, remainder, blockPosition.toVector3d(), Vector3f.ZERO);
            store.addEntities(itemEntityHolders, AddReason.SPAWN);
        }
        return true;
    }
    
    public boolean canOpen(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        return true;
    }
    
    public void onOpen(@Nonnull final Ref<EntityStore> ref, @Nonnull final World world, @Nonnull final Store<EntityStore> store) {
    }
    
    @Override
    public void onDestroy() {
        WindowManager.closeAndRemoveAll(this.windows);
        final WorldChunk chunk = this.getChunk();
        final World world = chunk.getWorld();
        final Store<EntityStore> store = world.getEntityStore().getStore();
        final List<ItemStack> allItemStacks = this.itemContainer.dropAllItemStacks();
        final Vector3d dropPosition = this.getBlockPosition().toVector3d().add(0.5, 0.0, 0.5);
        final Holder<EntityStore>[] itemEntityHolders = ItemComponent.generateItemDrops(store, allItemStacks, dropPosition, Vector3f.ZERO);
        if (itemEntityHolders.length > 0) {
            world.execute(() -> store.addEntities(itemEntityHolders, AddReason.SPAWN));
        }
        if (this.marker != null) {
            this.marker.remove();
        }
    }
    
    public void setCustom(final boolean custom) {
        this.custom = custom;
        this.markNeedsSave();
    }
    
    public void setAllowViewing(final boolean allowViewing) {
        this.allowViewing = allowViewing;
        this.markNeedsSave();
    }
    
    public boolean isAllowViewing() {
        return this.allowViewing;
    }
    
    public void setItemContainer(final SimpleItemContainer itemContainer) {
        this.itemContainer = itemContainer;
        this.markNeedsSave();
    }
    
    @Nullable
    public String getDroplist() {
        return this.droplist;
    }
    
    public void setDroplist(@Nullable final String droplist) {
        this.droplist = droplist;
        this.markNeedsSave();
    }
    
    @Override
    public void setMarker(final WorldMapManager.MarkerReference marker) {
        this.marker = marker;
        this.markNeedsSave();
    }
    
    @Nonnull
    public Map<UUID, ContainerBlockWindow> getWindows() {
        return this.windows;
    }
    
    @Override
    public ItemContainer getItemContainer() {
        return this.itemContainer;
    }
    
    public void onItemChange(final ItemContainer.ItemContainerChangeEvent event) {
        this.markNeedsSave();
    }
    
    static {
        CODEC = BuilderCodec.builder(ItemContainerState.class, ItemContainerState::new, BlockState.BASE_CODEC).addField(new KeyedCodec<Boolean>("Custom", Codec.BOOLEAN), (state, o) -> state.custom = o, state -> state.custom).addField(new KeyedCodec("AllowViewing", Codec.BOOLEAN), (state, o) -> state.allowViewing = o, state -> state.allowViewing).addField(new KeyedCodec("Droplist", Codec.STRING), (state, o) -> state.droplist = o, state -> state.droplist).addField(new KeyedCodec("Marker", WorldMapManager.MarkerReference.CODEC), (state, o) -> state.marker = o, state -> state.marker).addField(new KeyedCodec("ItemContainer", SimpleItemContainer.CODEC), (state, o) -> state.itemContainer = o, state -> state.itemContainer).build();
    }
    
    public static class ItemContainerStateData extends StateData
    {
        public static final BuilderCodec<ItemContainerStateData> CODEC;
        private short capacity;
        
        protected ItemContainerStateData() {
            this.capacity = 20;
        }
        
        public short getCapacity() {
            return this.capacity;
        }
        
        @Nonnull
        @Override
        public String toString() {
            return "ItemContainerStateData{capacity=" + this.capacity + "} " + super.toString();
        }
        
        static {
            // 
            // This method could not be decompiled.
            // 
            // Original Bytecode:
            // 
            //     2: invokedynamic   BootstrapMethod #1, get:()Ljava/util/function/Supplier;
            //     7: getstatic       com/hypixel/hytale/server/core/asset/type/blocktype/config/StateData.DEFAULT_CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //    10: invokestatic    com/hypixel/hytale/codec/builder/BuilderCodec.builder:(Ljava/lang/Class;Ljava/util/function/Supplier;Lcom/hypixel/hytale/codec/builder/BuilderCodec;)Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    13: new             Lcom/hypixel/hytale/codec/KeyedCodec;
            //    16: dup            
            //    17: ldc             "Capacity"
            //    19: getstatic       com/hypixel/hytale/codec/Codec.INTEGER:Lcom/hypixel/hytale/codec/codecs/simple/IntegerCodec;
            //    22: invokespecial   com/hypixel/hytale/codec/KeyedCodec.<init>:(Ljava/lang/String;Lcom/hypixel/hytale/codec/Codec;)V
            //    25: invokedynamic   BootstrapMethod #2, accept:()Ljava/util/function/BiConsumer;
            //    30: invokedynamic   BootstrapMethod #3, apply:()Ljava/util/function/Function;
            //    35: invokedynamic   BootstrapMethod #4, accept:()Ljava/util/function/BiConsumer;
            //    40: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.appendInherited:(Lcom/hypixel/hytale/codec/KeyedCodec;Ljava/util/function/BiConsumer;Ljava/util/function/Function;Ljava/util/function/BiConsumer;)Lcom/hypixel/hytale/codec/builder/BuilderField$FieldBuilder;
            //    43: invokevirtual   com/hypixel/hytale/codec/builder/BuilderField$FieldBuilder.add:()Lcom/hypixel/hytale/codec/builder/BuilderCodec$BuilderBase;
            //    46: checkcast       Lcom/hypixel/hytale/codec/builder/BuilderCodec$Builder;
            //    49: invokevirtual   com/hypixel/hytale/codec/builder/BuilderCodec$Builder.build:()Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //    52: putstatic       com/hypixel/hytale/server/core/universe/world/meta/state/ItemContainerState$ItemContainerStateData.CODEC:Lcom/hypixel/hytale/codec/builder/BuilderCodec;
            //    55: return         
            // 
            // The error that occurred was:
            // 
            // java.lang.UnsupportedOperationException: The requested operation is not supported.
            //     at com.strobel.util.ContractUtils.unsupported(ContractUtils.java:27)
            //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:284)
            //     at com.strobel.assembler.metadata.TypeReference.getRawType(TypeReference.java:279)
            //     at com.strobel.assembler.metadata.TypeReference.makeGenericType(TypeReference.java:154)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:225)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
            //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:211)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitParameterizedType(TypeSubstitutionVisitor.java:25)
            //     at com.strobel.assembler.metadata.ParameterizedType.accept(ParameterizedType.java:103)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visit(TypeSubstitutionVisitor.java:40)
            //     at com.strobel.assembler.metadata.TypeSubstitutionVisitor.visitMethod(TypeSubstitutionVisitor.java:314)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2611)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1510)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:782)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:778)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferCall(TypeAnalysis.java:2483)
            //     at com.strobel.decompiler.ast.TypeAnalysis.doInferTypeForExpression(TypeAnalysis.java:1040)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypeForExpression(TypeAnalysis.java:815)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:684)
            //     at com.strobel.decompiler.ast.TypeAnalysis.inferTypesForVariables(TypeAnalysis.java:593)
            //     at com.strobel.decompiler.ast.TypeAnalysis.runInference(TypeAnalysis.java:405)
            //     at com.strobel.decompiler.ast.TypeAnalysis.run(TypeAnalysis.java:95)
            //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:109)
            //     at com.strobel.decompiler.ast.AstOptimizer.optimize(AstOptimizer.java:42)
            //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:206)
            //     at com.strobel.decompiler.languages.java.ast.AstMethodBodyBuilder.createMethodBody(AstMethodBodyBuilder.java:93)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethodBody(AstBuilder.java:868)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createMethod(AstBuilder.java:761)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:638)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addTypeMembers(AstBuilder.java:662)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeCore(AstBuilder.java:605)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createTypeNoCache(AstBuilder.java:195)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.createType(AstBuilder.java:162)
            //     at com.strobel.decompiler.languages.java.ast.AstBuilder.addType(AstBuilder.java:137)
            //     at com.strobel.decompiler.languages.java.JavaLanguage.buildAst(JavaLanguage.java:71)
            //     at com.strobel.decompiler.languages.java.JavaLanguage.decompileType(JavaLanguage.java:59)
            //     at com.strobel.decompiler.DecompilerDriver.decompileType(DecompilerDriver.java:333)
            //     at com.strobel.decompiler.DecompilerDriver.decompileJar(DecompilerDriver.java:254)
            //     at com.strobel.decompiler.DecompilerDriver.main(DecompilerDriver.java:129)
            // 
            throw new IllegalStateException("An error occurred while decompiling this method.");
        }
    }
}
