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

package com.hypixel.hytale.builtin.adventure.stash;

import com.hypixel.hytale.component.RemoveReason;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.component.AddReason;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.component.query.Query;
import com.hypixel.hytale.component.dependency.SystemDependency;
import com.hypixel.hytale.component.dependency.Order;
import com.hypixel.hytale.component.dependency.Dependency;
import java.util.Set;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.component.system.RefSystem;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.inventory.transaction.ItemStackSlotTransaction;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import java.util.List;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.logging.Level;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import it.unimi.dsi.fastutil.shorts.ShortList;
import it.unimi.dsi.fastutil.shorts.ShortLists;
import java.util.Random;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import com.hypixel.hytale.server.core.modules.item.ItemModule;
import com.hypixel.hytale.server.core.inventory.transaction.ItemStackTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.system.ISystem;
import com.hypixel.hytale.server.core.universe.world.meta.state.ItemContainerState;
import com.hypixel.hytale.server.core.universe.world.meta.BlockStateModule;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;

public class StashPlugin extends JavaPlugin
{
    private static final HytaleLogger LOGGER;
    
    public StashPlugin(@Nonnull final JavaPluginInit init) {
        super(init);
    }
    
    @Override
    protected void setup() {
        this.getChunkStoreRegistry().registerSystem(new StashSystem(BlockStateModule.get().getComponentType(ItemContainerState.class)));
        this.getCodecRegistry(GameplayConfig.PLUGIN_CODEC).register(StashGameplayConfig.class, "Stash", StashGameplayConfig.CODEC);
    }
    
    @Nullable
    public static ListTransaction<ItemStackTransaction> stash(@Nonnull final ItemContainerState containerState, final boolean clearDropList) {
        final String droplist = containerState.getDroplist();
        if (droplist == null) {
            return null;
        }
        final List<ItemStack> stacks = ItemModule.get().getRandomItemDrops(droplist);
        if (!stacks.isEmpty()) {
            final ItemContainer itemContainer = containerState.getItemContainer();
            final short capacity = itemContainer.getCapacity();
            final ShortArrayList slots = new ShortArrayList(capacity);
            for (short s = 0; s < capacity; ++s) {
                slots.add(s);
            }
            final Vector3i blockPosition = containerState.getBlockPosition();
            final long positionHash = blockPosition.hashCode();
            final Random rnd = new Random(positionHash);
            ShortLists.shuffle(slots, rnd);
            boolean anySucceeded = false;
            for (int idx = 0; idx < stacks.size() && idx < slots.size(); ++idx) {
                final short slot = slots.getShort(idx);
                final ItemStackSlotTransaction transaction = itemContainer.addItemStackToSlot(slot, stacks.get(idx));
                if (transaction.getRemainder() == null || transaction.getRemainder().isEmpty()) {
                    anySucceeded = true;
                }
                else {
                    StashPlugin.LOGGER.at(Level.WARNING).log("Could not add Item to Stash at %d, %d, %d: %s", blockPosition.x, blockPosition.y, blockPosition.z, transaction.getRemainder());
                }
            }
            if (clearDropList && anySucceeded) {
                containerState.setDroplist(null);
            }
            return new ListTransaction<ItemStackTransaction>(anySucceeded, new ObjectArrayList<ItemStackTransaction>());
        }
        return ListTransaction.getEmptyTransaction(true);
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
    
    private static class StashSystem extends RefSystem<ChunkStore>
    {
        private final ComponentType<ChunkStore, ItemContainerState> componentType;
        @Nonnull
        private final Set<Dependency<ChunkStore>> dependencies;
        
        public StashSystem(final ComponentType<ChunkStore, ItemContainerState> componentType) {
            this.componentType = componentType;
            this.dependencies = (Set<Dependency<ChunkStore>>)Set.of(new SystemDependency(Order.AFTER, BlockStateModule.LegacyBlockStateRefSystem.class));
        }
        
        @Override
        public Query<ChunkStore> getQuery() {
            return this.componentType;
        }
        
        @Override
        public void onEntityAdded(@Nonnull final Ref<ChunkStore> ref, @Nonnull final AddReason reason, @Nonnull final Store<ChunkStore> store, @Nonnull final CommandBuffer<ChunkStore> commandBuffer) {
            final World world = store.getExternalData().getWorld();
            if (world.getWorldConfig().getGameMode() == GameMode.Creative) {
                return;
            }
            final StashGameplayConfig stashGameplayConfig = StashGameplayConfig.getOrDefault(world.getGameplayConfig());
            final boolean clearContainerDropList = stashGameplayConfig.isClearContainerDropList();
            StashPlugin.stash(store.getComponent(ref, this.componentType), clearContainerDropList);
        }
        
        @Override
        public void onEntityRemove(@Nonnull final Ref<ChunkStore> ref, @Nonnull final RemoveReason reason, @Nonnull final Store<ChunkStore> store, @Nonnull final CommandBuffer<ChunkStore> commandBuffer) {
        }
        
        @Nonnull
        @Override
        public Set<Dependency<ChunkStore>> getDependencies() {
            return this.dependencies;
        }
    }
}
