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> bbt) {
        this.stackedContents = new StackedContents();
        this.menu = bbt;
    }
    
    public void recipeClicked(final ServerPlayer xe, @Nullable final Recipe<C> bgw, final boolean boolean3) {
        if (bgw == null || !xe.getRecipeBook().contains(bgw)) {
            return;
        }
        this.inventory = xe.inventory;
        if (!this.testClearGrid() && !xe.isCreative()) {
            return;
        }
        this.stackedContents.clear();
        xe.inventory.fillStackedContents(this.stackedContents);
        this.menu.fillCraftSlotsStackedContents(this.stackedContents);
        if (this.stackedContents.canCraft(bgw, null)) {
            this.handleRecipeClicked(bgw, boolean3);
        }
        else {
            this.clearGrid();
            xe.connection.send(new ClientboundPlaceGhostRecipePacket(xe.containerMenu.containerId, bgw));
        }
        xe.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 ben3 = this.menu.getSlot(integer).getItem();
        if (ben3.isEmpty()) {
            return;
        }
        while (ben3.getCount() > 0) {
            int integer2 = this.inventory.getSlotWithRemainingSpace(ben3);
            if (integer2 == -1) {
                integer2 = this.inventory.getFreeSlot();
            }
            final ItemStack ben4 = ben3.copy();
            ben4.setCount(1);
            if (!this.inventory.add(integer2, ben4)) {
                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> bgw, final boolean boolean2) {
        final boolean boolean3 = this.menu.recipeMatches(bgw);
        final int integer5 = this.stackedContents.getBiggestCraftableStack(bgw, null);
        if (boolean3) {
            for (int integer6 = 0; integer6 < this.menu.getGridHeight() * this.menu.getGridWidth() + 1; ++integer6) {
                if (integer6 != this.menu.getResultSlotIndex()) {
                    final ItemStack ben7 = this.menu.getSlot(integer6).getItem();
                    if (!ben7.isEmpty() && Math.min(integer5, ben7.getMaxStackSize()) < ben7.getCount() + 1) {
                        return;
                    }
                }
            }
        }
        int integer6 = this.getStackSize(boolean2, integer5, boolean3);
        final IntList intList7 = (IntList)new IntArrayList();
        if (this.stackedContents.canCraft(bgw, 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(bgw, intList7, integer6)) {
                this.clearGrid();
                this.placeRecipe(this.menu.getGridWidth(), this.menu.getGridHeight(), this.menu.getResultSlotIndex(), bgw, (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 bca7 = this.menu.getSlot(integer2);
        final ItemStack ben8 = StackedContents.fromStackingIndex(iterator.next());
        if (!ben8.isEmpty()) {
            for (int integer6 = 0; integer6 < integer3; ++integer6) {
                this.moveItemToGrid(bca7, ben8);
            }
        }
    }
    
    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 ben7 = this.menu.getSlot(integer3).getItem();
                    if (!ben7.isEmpty() && integer2 > ben7.getCount()) {
                        integer2 = ben7.getCount();
                    }
                }
            }
            if (integer2 < 64) {
                ++integer2;
            }
        }
        return integer2;
    }
    
    protected void moveItemToGrid(final Slot bca, final ItemStack ben) {
        final int integer4 = this.inventory.findSlotMatchingUnusedItem(ben);
        if (integer4 == -1) {
            return;
        }
        final ItemStack ben2 = this.inventory.getItem(integer4).copy();
        if (ben2.isEmpty()) {
            return;
        }
        if (ben2.getCount() > 1) {
            this.inventory.removeItem(integer4, 1);
        }
        else {
            this.inventory.removeItemNoUpdate(integer4);
        }
        ben2.setCount(1);
        if (bca.getItem().isEmpty()) {
            bca.set(ben2);
        }
        else {
            bca.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 ben5 = this.menu.getSlot(integer4).getItem().copy();
                if (!ben5.isEmpty()) {
                    final int integer5 = this.inventory.getSlotWithRemainingSpace(ben5);
                    if (integer5 == -1 && list2.size() <= integer3) {
                        for (final ItemStack ben6 : list2) {
                            if (ben6.sameItem(ben5) && ben6.getCount() != ben6.getMaxStackSize() && ben6.getCount() + ben5.getCount() <= ben6.getMaxStackSize()) {
                                ben6.grow(ben5.getCount());
                                ben5.setCount(0);
                                break;
                            }
                        }
                        if (!ben5.isEmpty()) {
                            if (list2.size() >= integer3) {
                                return false;
                            }
                            list2.add(ben5);
                        }
                    }
                    else if (integer5 == -1) {
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    private int getAmountOfFreeSlotsInInventory() {
        int integer2 = 0;
        for (final ItemStack ben4 : this.inventory.items) {
            if (ben4.isEmpty()) {
                ++integer2;
            }
        }
        return integer2;
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
