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

package com.hypixel.hytale.builtin.crafting.window;

import java.lang.invoke.CallSite;
import java.lang.reflect.UndeclaredThrowableException;
import java.lang.invoke.MethodHandle;
import java.lang.runtime.SwitchBootstraps;
import java.lang.invoke.MethodType;
import java.lang.invoke.MethodHandles;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import com.hypixel.hytale.server.core.inventory.container.filter.SlotFilter;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterActionType;
import com.hypixel.hytale.event.EventPriority;
import com.hypixel.hytale.server.core.inventory.container.filter.FilterType;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.builtin.crafting.CraftingPlugin;
import com.hypixel.hytale.server.core.universe.world.SoundUtil;
import com.hypixel.hytale.protocol.SoundCategory;
import com.hypixel.hytale.protocol.packets.window.CraftItemAction;
import com.hypixel.hytale.server.core.Message;
import com.hypixel.hytale.protocol.packets.window.UpdateCategoryAction;
import com.hypixel.hytale.protocol.packets.window.CancelCraftingAction;
import java.util.Objects;
import com.hypixel.hytale.server.core.universe.PlayerRef;
import com.hypixel.hytale.protocol.packets.window.WindowAction;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.builtin.crafting.component.CraftingManager;
import it.unimi.dsi.fastutil.objects.ObjectList;
import com.hypixel.hytale.server.core.inventory.Inventory;
import com.google.gson.JsonElement;
import java.util.List;
import com.hypixel.hytale.server.core.asset.type.item.config.CraftingRecipe;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.DiagramCraftingBench;
import com.hypixel.hytale.protocol.packets.window.WindowType;
import com.hypixel.hytale.builtin.crafting.state.BenchState;
import com.hypixel.hytale.component.ComponentAccessor;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.event.EventRegistration;
import com.hypixel.hytale.server.core.inventory.container.CombinedItemContainer;
import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer;
import javax.annotation.Nullable;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.bench.CraftingBench;
import com.hypixel.hytale.logger.HytaleLogger;
import com.hypixel.hytale.server.core.entity.entities.player.windows.ItemContainerWindow;

public class DiagramCraftingWindow extends CraftingWindow implements ItemContainerWindow
{
    private static final HytaleLogger LOGGER;
    private String category;
    private String itemCategory;
    @Nullable
    private CraftingBench.BenchItemCategory benchItemCategory;
    private SimpleItemContainer inputPrimaryContainer;
    private SimpleItemContainer inputSecondaryContainer;
    private CombinedItemContainer combinedInputItemContainer;
    private SimpleItemContainer outputContainer;
    private CombinedItemContainer combinedItemContainer;
    private EventRegistration<?, ?> inventoryRegistration;
    
    public DiagramCraftingWindow(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> store, @Nonnull final BenchState benchState) {
        super(WindowType.DiagramCrafting, benchState);
        final DiagramCraftingBench bench = (DiagramCraftingBench)this.bench;
        if (bench.getCategories() != null && bench.getCategories().length > 0) {
            final CraftingBench.BenchCategory benchCategory = bench.getCategories()[0];
            this.category = benchCategory.getId();
            if (benchCategory.getItemCategories() != null && benchCategory.getItemCategories().length > 0) {
                this.itemCategory = benchCategory.getItemCategories()[0].getId();
            }
        }
        this.benchItemCategory = this.getBenchItemCategory(this.category, this.itemCategory);
        if (this.benchItemCategory == null) {
            throw new IllegalArgumentException("Failed to get category!");
        }
        this.updateInventory(ref, store, this.benchItemCategory);
    }
    
    @Override
    protected void finalize() {
        if (this.inventoryRegistration.isRegistered()) {
            throw new IllegalStateException("Failed to unregister inventory event!");
        }
    }
    
    public boolean onOpen0(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        final boolean result = super.onOpen0(ref, store);
        final Player playerComponent = store.getComponent(ref, Player.getComponentType());
        assert playerComponent != null;
        final Inventory inventory = playerComponent.getInventory();
        this.updateInput(null, ref, store);
        this.inventoryRegistration = inventory.getCombinedHotbarFirst().registerChangeEvent(event -> {
            final ObjectList<CraftingRecipe> recipes = new ObjectArrayList<CraftingRecipe>();
            this.windowData.add("slots", this.generateSlots(inventory.getCombinedHotbarFirst(), recipes));
            this.invalidate();
            return;
        });
        return result;
    }
    
    @Override
    public void onClose0(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final Player playerComponent = componentAccessor.getComponent(ref, Player.getComponentType());
        assert playerComponent != null;
        final List<ItemStack> itemStacks = this.combinedInputItemContainer.dropAllItemStacks();
        SimpleItemContainer.addOrDropItemStacks(componentAccessor, ref, playerComponent.getInventory().getCombinedHotbarFirst(), itemStacks);
        final CraftingManager craftingManagerComponent = componentAccessor.getComponent(ref, CraftingManager.getComponentType());
        assert craftingManagerComponent != null;
        craftingManagerComponent.cancelAllCrafting(ref, componentAccessor);
        this.inventoryRegistration.unregister();
        super.onClose0(ref, componentAccessor);
    }
    
    @Override
    public void handleAction(@Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store, @Nonnull final WindowAction action) {
        final World world = store.getExternalData().getWorld();
        final PlayerRef playerRefComponent = store.getComponent(ref, PlayerRef.getComponentType());
        assert playerRefComponent != null;
        final CraftingManager craftingManagerComponent = store.getComponent(ref, CraftingManager.getComponentType());
        assert craftingManagerComponent != null;
        Objects.requireNonNull(action);
        switch (/* invokedynamic(!) */ProcyonInvokeDynamicHelper_13.invoke(action, false)) {
            case 0: {
                final CancelCraftingAction ignored = (CancelCraftingAction)action;
                craftingManagerComponent.cancelAllCrafting(ref, store);
                break;
            }
            case 1: {
                final UpdateCategoryAction updateAction = (UpdateCategoryAction)action;
                this.category = updateAction.category;
                this.itemCategory = updateAction.itemCategory;
                this.benchItemCategory = this.getBenchItemCategory(this.category, this.itemCategory);
                if (this.benchItemCategory != null) {
                    this.updateInventory(ref, store, this.benchItemCategory);
                    break;
                }
                playerRefComponent.sendMessage(Message.translation("server.ui.diagramcraftingwindow.invalidCategory"));
                this.close(ref, store);
                break;
            }
            case 2: {
                final CraftItemAction ignored2 = (CraftItemAction)action;
                final ItemStack itemStack = this.outputContainer.getItemStack((short)0);
                if (itemStack == null || itemStack.isEmpty()) {
                    playerRefComponent.sendMessage(Message.translation("server.ui.diagramcraftingwindow.noOutputItem"));
                    return;
                }
                final ObjectList<CraftingRecipe> recipes = new ObjectArrayList<CraftingRecipe>();
                final boolean allSlotsFull = this.collectRecipes(ref, recipes, store);
                if (recipes.size() != 1 || !allSlotsFull) {
                    playerRefComponent.sendMessage(Message.translation("server.ui.diagramcraftingwindow.failedVerifyRecipy"));
                    return;
                }
                final CraftingRecipe recipe = recipes.getFirst();
                craftingManagerComponent.queueCraft(ref, store, this, 0, recipe, 1, this.combinedInputItemContainer, CraftingManager.InputRemovalType.ORDERED);
                final String completedState = (recipe.getTimeSeconds() > 0.0f) ? "CraftCompleted" : "CraftCompletedInstant";
                this.setBlockInteractionState(completedState, world);
                if (this.bench.getCompletedSoundEventIndex() != 0) {
                    SoundUtil.playSoundEvent3d(this.bench.getCompletedSoundEventIndex(), SoundCategory.SFX, this.x + 0.5, this.y + 0.5, this.z + 0.5, store);
                }
                if (CraftingPlugin.learnRecipe(ref, recipe.getId(), store)) {
                    this.updateInput(this.outputContainer, ref, store);
                }
                break;
            }
        }
    }
    
    @Nonnull
    @Override
    public ItemContainer getItemContainer() {
        return this.combinedItemContainer;
    }
    
    @Nullable
    private CraftingBench.BenchItemCategory getBenchItemCategory(@Nullable final String category, @Nullable final String itemCategory) {
        if (category == null || itemCategory == null) {
            return null;
        }
        final DiagramCraftingBench craftingBench = (DiagramCraftingBench)this.bench;
        for (final CraftingBench.BenchCategory benchCategory : craftingBench.getCategories()) {
            if (category.equals(benchCategory.getId())) {
                for (final CraftingBench.BenchItemCategory benchItemCategory : benchCategory.getItemCategories()) {
                    if (itemCategory.equals(benchItemCategory.getId())) {
                        return benchItemCategory;
                    }
                }
            }
        }
        return null;
    }
    
    private void updateInventory(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor, @Nonnull final CraftingBench.BenchItemCategory benchItemCategory) {
        if (this.combinedInputItemContainer != null) {
            final Player playerComponent = componentAccessor.getComponent(ref, Player.getComponentType());
            assert playerComponent != null;
            final List<ItemStack> itemStacks = this.combinedInputItemContainer.dropAllItemStacks();
            SimpleItemContainer.addOrDropItemStacks(componentAccessor, ref, playerComponent.getInventory().getCombinedHotbarFirst(), itemStacks);
        }
        this.inputPrimaryContainer = new SimpleItemContainer((short)1);
        (this.inputSecondaryContainer = new SimpleItemContainer((short)(benchItemCategory.getSlots() + (benchItemCategory.isSpecialSlot() ? 1 : 0)))).setGlobalFilter(FilterType.ALLOW_OUTPUT_ONLY);
        (this.combinedInputItemContainer = new CombinedItemContainer(new ItemContainer[] { this.inputPrimaryContainer, this.inputSecondaryContainer })).registerChangeEvent(EventPriority.LAST, this::updateInput);
        (this.outputContainer = new SimpleItemContainer((short)1)).setGlobalFilter(FilterType.DENY_ALL);
        this.combinedItemContainer = new CombinedItemContainer(new ItemContainer[] { this.combinedInputItemContainer, this.outputContainer });
    }
    
    private void updateInput(@Nonnull final ItemContainer.ItemContainerChangeEvent event) {
        final PlayerRef playerRef = this.getPlayerRef();
        if (playerRef == null) {
            return;
        }
        final Ref<EntityStore> ref = playerRef.getReference();
        if (ref == null || !ref.isValid()) {
            return;
        }
        final Store<EntityStore> store = ref.getStore();
        this.updateInput(event.container(), ref, store);
    }
    
    private void updateInput(@Nullable final ItemContainer container, @Nonnull final Ref<EntityStore> ref, @Nonnull final Store<EntityStore> store) {
        final Player playerComponent = store.getComponent(ref, Player.getComponentType());
        assert playerComponent != null;
        final ItemStack primaryItemStack = this.inputPrimaryContainer.getItemStack((short)0);
        final CombinedItemContainer combinedStorage = playerComponent.getInventory().getCombinedHotbarFirst();
        if (primaryItemStack != null && !primaryItemStack.isEmpty()) {
            this.inputSecondaryContainer.setGlobalFilter(FilterType.ALLOW_ALL);
            boolean needsDropSlot = true;
            for (short i = 0; i < this.inputSecondaryContainer.getCapacity(); ++i) {
                final ItemStack itemStack = this.inputSecondaryContainer.getItemStack(i);
                if (itemStack != null && !itemStack.isEmpty()) {
                    this.inputSecondaryContainer.setSlotFilter(FilterActionType.ADD, i, null);
                }
                else if (needsDropSlot) {
                    this.inputSecondaryContainer.setSlotFilter(FilterActionType.ADD, i, null);
                    needsDropSlot = false;
                }
                else {
                    this.inputSecondaryContainer.setSlotFilter(FilterActionType.ADD, i, SlotFilter.DENY);
                }
            }
        }
        else {
            this.inputSecondaryContainer.setGlobalFilter(FilterType.ALLOW_OUTPUT_ONLY);
            if (container != this.inputSecondaryContainer && !this.inputSecondaryContainer.isEmpty()) {
                final List<ItemStack> itemStacks = this.inputSecondaryContainer.dropAllItemStacks();
                SimpleItemContainer.addOrDropItemStacks(store, ref, combinedStorage, itemStacks);
            }
        }
        final List<CraftingRecipe> recipes = new ObjectArrayList<CraftingRecipe>();
        final boolean allSlotsFull = this.collectRecipes(ref, recipes, store);
        this.windowData.add("slots", this.generateSlots(combinedStorage, recipes));
        if (recipes.size() == 1 && allSlotsFull) {
            final CraftingRecipe recipe = recipes.getFirst();
            final ItemStack output = CraftingManager.getOutputItemStacks(recipe).getFirst();
            if (playerComponent.getPlayerConfigData().getKnownRecipes().contains(recipe.getId())) {
                this.outputContainer.setItemStackForSlot((short)0, output);
            }
            else {
                this.outputContainer.setItemStackForSlot((short)0, new ItemStack("Unknown", 1));
            }
        }
        else {
            if (!recipes.isEmpty() && allSlotsFull) {
                DiagramCraftingWindow.LOGGER.at(Level.WARNING).log("Multiple recipes defined for the same materials! %s", recipes);
            }
            this.outputContainer.setItemStackForSlot((short)0, ItemStack.EMPTY);
        }
        this.invalidate();
    }
    
    private boolean collectRecipes(@Nonnull final Ref<EntityStore> ref, @Nonnull final List<CraftingRecipe> recipes, @Nonnull final Store<EntityStore> store) {
        assert this.benchItemCategory != null;
        final ItemStack primaryItemStack = this.inputPrimaryContainer.getItemStack((short)0);
        if (primaryItemStack == null || primaryItemStack.isEmpty()) {
            return false;
        }
        final Player playerComponent = store.getComponent(ref, Player.getComponentType());
        assert playerComponent != null;
        final Set<String> knownRecipes = playerComponent.getPlayerConfigData().getKnownRecipes();
        final short inputCapacity = this.combinedInputItemContainer.getCapacity();
        boolean allSlotsFull = true;
    Label_0111:
        for (final CraftingRecipe recipe : this.getBenchRecipes()) {
            if (recipe.getInput().length != inputCapacity && (!this.benchItemCategory.isSpecialSlot() || recipe.getInput().length != inputCapacity - 1)) {
                DiagramCraftingWindow.LOGGER.at(Level.WARNING).log("Recipe for %s has different input length than the diagram! %s - %s, %s, %s", recipe.getId(), recipe, this.bench, this.category, this.itemCategory);
            }
            else {
                if (recipe.isKnowledgeRequired() && !knownRecipes.contains(recipe.getId())) {
                    continue;
                }
                for (short i = 0; i < inputCapacity; ++i) {
                    final ItemStack itemStack = this.combinedInputItemContainer.getItemStack(i);
                    if (itemStack == null || itemStack.isEmpty()) {
                        if (!this.benchItemCategory.isSpecialSlot() && i == inputCapacity - 1) {
                            allSlotsFull = false;
                        }
                    }
                    else if (!CraftingManager.matches(recipe.getInput()[i], itemStack)) {
                        continue Label_0111;
                    }
                }
                recipes.add(recipe);
            }
        }
        return allSlotsFull;
    }
    
    @Nonnull
    private JsonArray generateSlots(@Nonnull final CombinedItemContainer combinedStorage, @Nonnull final List<CraftingRecipe> recipes) {
        final JsonArray slots = new JsonArray();
        if (recipes.isEmpty()) {
            final List<CraftingRecipe> benchRecipes = this.getBenchRecipes();
            final JsonObject slot = new JsonObject();
            slot.add("inventoryHints", CraftingManager.generateInventoryHints(benchRecipes, 0, combinedStorage));
            slots.add(slot);
        }
        else {
            for (short i = 0; i < this.combinedInputItemContainer.getCapacity(); ++i) {
                final JsonObject slot = new JsonObject();
                final ItemStack itemStack = this.combinedInputItemContainer.getItemStack(i);
                if (itemStack == null || itemStack.isEmpty()) {
                    slot.add("inventoryHints", CraftingManager.generateInventoryHints(recipes, i, combinedStorage));
                }
                int requiredAmount = -1;
                if (recipes.size() == 1) {
                    final CraftingRecipe recipe = recipes.getFirst();
                    if (i < recipe.getInput().length) {
                        requiredAmount = recipe.getInput()[i].getQuantity();
                    }
                }
                slot.addProperty("requiredAmount", requiredAmount);
                slots.add(slot);
            }
        }
        return slots;
    }
    
    @Nonnull
    public List<CraftingRecipe> getBenchRecipes() {
        return CraftingPlugin.getBenchRecipes(this.bench.getType(), this.bench.getId(), this.category + "." + this.itemCategory);
    }
    
    static {
        LOGGER = HytaleLogger.forEnclosingClass();
    }
    
    // This helper class was generated by Procyon to approximate the behavior of an
    // 'invokedynamic' instruction that it doesn't know how to interpret.
    private static final class ProcyonInvokeDynamicHelper_13
    {
        private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
        private static MethodHandle handle;
        private static volatile int fence;
        
        private static MethodHandle handle() {
            final MethodHandle handle = ProcyonInvokeDynamicHelper_13.handle;
            if (handle != null)
                return handle;
            return ProcyonInvokeDynamicHelper_13.ensureHandle();
        }
        
        private static MethodHandle ensureHandle() {
            ProcyonInvokeDynamicHelper_13.fence = 0;
            MethodHandle handle = ProcyonInvokeDynamicHelper_13.handle;
            if (handle == null) {
                MethodHandles.Lookup lookup = ProcyonInvokeDynamicHelper_13.LOOKUP;
                try {
                    handle = ((CallSite)SwitchBootstraps.typeSwitch(lookup, "typeSwitch", MethodType.methodType(int.class, Object.class, int.class), CancelCraftingAction.class, UpdateCategoryAction.class, CraftItemAction.class)).dynamicInvoker();
                }
                catch (Throwable t) {
                    throw new UndeclaredThrowableException(t);
                }
                ProcyonInvokeDynamicHelper_13.fence = 1;
                ProcyonInvokeDynamicHelper_13.handle = handle;
                ProcyonInvokeDynamicHelper_13.fence = 0;
            }
            return handle;
        }
        
        private static int invoke(Object p0, int p1) {
            try {
                return ProcyonInvokeDynamicHelper_13.handle().invokeExact(p0, p1);
            }
            catch (Throwable t) {
                throw new UndeclaredThrowableException(t);
            }
        }
    }
}
