package net.minecraft.recipebook;

import org.apache.logging.log4j.LogManager;
import java.util.List;
import com.google.common.collect.Lists;
import net.minecraft.world.inventory.Slot;
import it.unimi.dsi.fastutil.ints.IntListIterator;
import java.util.Iterator;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.inventory.CraftingMenu;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundPlaceGhostRecipePacket;
import it.unimi.dsi.fastutil.ints.IntList;
import javax.annotation.Nullable;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.RecipeBookMenu;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.StackedContents;
import org.apache.logging.log4j.Logger;
import net.minecraft.world.Container;

public class ServerPlaceRecipe<C extends Container> implements PlaceRecipe<Integer> {
    protected static final Logger LOGGER;
    protected final StackedContents stackedContents;
    protected Inventory inventory;
    protected RecipeBookMenu<C> menu;
    
    public ServerPlaceRecipe(final RecipeBookMenu<C> bhp) {
        this.stackedContents = new StackedContents();
        this.menu = bhp;
    }
    
    public void recipeClicked(final ServerPlayer ze, @Nullable final Recipe<C> bmu, final boolean boolean3) {
        if (bmu == null || !ze.getRecipeBook().contains(bmu)) {
            return;
        }
        this.inventory = ze.inventory;
        if (!this.testClearGrid() && !ze.isCreative()) {
            return;
        }
        this.stackedContents.clear();
        ze.inventory.fillStackedContents(this.stackedContents);
        this.menu.fillCraftSlotsStackedContents(this.stackedContents);
        if (this.stackedContents.canCraft(bmu, null)) {
            this.handleRecipeClicked(bmu, boolean3);
        }
        else {
            this.clearGrid();
            ze.connection.send(new ClientboundPlaceGhostRecipePacket(ze.containerMenu.containerId, bmu));
        }
        ze.inventory.setChanged();
    }
    
    protected void clearGrid() {
        for (int integer2 = 0; integer2 < this.menu.getGridWidth() * this.menu.getGridHeight() + 1; ++integer2) {
            if (integer2 == this.menu.getResultSlotIndex()) {
                if (this.menu instanceof CraftingMenu) {
                    continue;
                }
                if (this.menu instanceof InventoryMenu) {
                    continue;
                }
            }
            this.moveItemToInventory(integer2);
        }
        this.menu.clearCraftingContent();
    }
    
    protected void moveItemToInventory(final int integer) {
        final ItemStack bki3 = this.menu.getSlot(integer).getItem();
        if (bki3.isEmpty()) {
            return;
        }
        while (bki3.getCount() > 0) {
            int integer2 = this.inventory.getSlotWithRemainingSpace(bki3);
            if (integer2 == -1) {
                integer2 = this.inventory.getFreeSlot();
            }
            final ItemStack bki4 = bki3.copy();
            bki4.setCount(1);
            if (!this.inventory.add(integer2, bki4)) {
                ServerPlaceRecipe.LOGGER.error("Can't find any space for item in the inventory");
            }
            this.menu.getSlot(integer).remove(1);
        }
    }
    
    protected void handleRecipeClicked(final Recipe<C> bmu, final boolean boolean2) {
        final boolean boolean3 = this.menu.recipeMatches(bmu);
        final int integer5 = this.stackedContents.getBiggestCraftableStack(bmu, null);
        if (boolean3) {
            for (int integer6 = 0; integer6 < this.menu.getGridHeight() * this.menu.getGridWidth() + 1; ++integer6) {
                if (integer6 != this.menu.getResultSlotIndex()) {
                    final ItemStack bki7 = this.menu.getSlot(integer6).getItem();
                    if (!bki7.isEmpty() && Math.min(integer5, bki7.getMaxStackSize()) < bki7.getCount() + 1) {
                        return;
                    }
                }
            }
        }
        int integer6 = this.getStackSize(boolean2, integer5, boolean3);
        final IntList intList7 = (IntList)new IntArrayList();
        if (this.stackedContents.canCraft(bmu, intList7, integer6)) {
            int integer7 = integer6;
            for (final int integer8 : intList7) {
                final int integer9 = StackedContents.fromStackingIndex(integer8).getMaxStackSize();
                if (integer9 < integer7) {
                    integer7 = integer9;
                }
            }
            integer6 = integer7;
            if (this.stackedContents.canCraft(bmu, intList7, integer6)) {
                this.clearGrid();
                this.placeRecipe(this.menu.getGridWidth(), this.menu.getGridHeight(), this.menu.getResultSlotIndex(), bmu, (Iterator<Integer>)intList7.iterator(), integer6);
            }
        }
    }
    
    @Override
    public void addItemToSlot(final Iterator<Integer> iterator, final int integer2, final int integer3, final int integer4, final int integer5) {
        final Slot bhw7 = this.menu.getSlot(integer2);
        final ItemStack bki8 = StackedContents.fromStackingIndex(iterator.next());
        if (!bki8.isEmpty()) {
            for (int integer6 = 0; integer6 < integer3; ++integer6) {
                this.moveItemToGrid(bhw7, bki8);
            }
        }
    }
    
    protected int getStackSize(final boolean boolean1, final int integer, final boolean boolean3) {
        int integer2 = 1;
        if (boolean1) {
            integer2 = integer;
        }
        else if (boolean3) {
            integer2 = 64;
            for (int integer3 = 0; integer3 < this.menu.getGridWidth() * this.menu.getGridHeight() + 1; ++integer3) {
                if (integer3 != this.menu.getResultSlotIndex()) {
                    final ItemStack bki7 = this.menu.getSlot(integer3).getItem();
                    if (!bki7.isEmpty() && integer2 > bki7.getCount()) {
                        integer2 = bki7.getCount();
                    }
                }
            }
            if (integer2 < 64) {
                ++integer2;
            }
        }
        return integer2;
    }
    
    protected void moveItemToGrid(final Slot bhw, final ItemStack bki) {
        final int integer4 = this.inventory.findSlotMatchingUnusedItem(bki);
        if (integer4 == -1) {
            return;
        }
        final ItemStack bki2 = this.inventory.getItem(integer4).copy();
        if (bki2.isEmpty()) {
            return;
        }
        if (bki2.getCount() > 1) {
            this.inventory.removeItem(integer4, 1);
        }
        else {
            this.inventory.removeItemNoUpdate(integer4);
        }
        bki2.setCount(1);
        if (bhw.getItem().isEmpty()) {
            bhw.set(bki2);
        }
        else {
            bhw.getItem().grow(1);
        }
    }
    
    private boolean testClearGrid() {
        final List<ItemStack> list2 = Lists.newArrayList();
        final int integer3 = this.getAmountOfFreeSlotsInInventory();
        for (int integer4 = 0; integer4 < this.menu.getGridWidth() * this.menu.getGridHeight() + 1; ++integer4) {
            if (integer4 != this.menu.getResultSlotIndex()) {
                final ItemStack bki5 = this.menu.getSlot(integer4).getItem().copy();
                if (!bki5.isEmpty()) {
                    final int integer5 = this.inventory.getSlotWithRemainingSpace(bki5);
                    if (integer5 == -1 && list2.size() <= integer3) {
                        for (final ItemStack bki6 : list2) {
                            if (bki6.sameItem(bki5) && bki6.getCount() != bki6.getMaxStackSize() && bki6.getCount() + bki5.getCount() <= bki6.getMaxStackSize()) {
                                bki6.grow(bki5.getCount());
                                bki5.setCount(0);
                                break;
                            }
                        }
                        if (!bki5.isEmpty()) {
                            if (list2.size() >= integer3) {
                                return false;
                            }
                            list2.add(bki5);
                        }
                    }
                    else if (integer5 == -1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    private int getAmountOfFreeSlotsInInventory() {
        int integer2 = 0;
        for (final ItemStack bki4 : this.inventory.items) {
            if (bki4.isEmpty()) {
                ++integer2;
            }
        }
        return integer2;
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
