package net.minecraft.world.inventory;

import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.util.Mth;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.core.Registry;
import net.minecraft.CrashReport;
import java.util.Iterator;
import net.minecraft.world.Container;
import net.minecraft.world.level.block.Block;
import com.google.common.collect.Sets;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.player.Player;
import java.util.Set;
import javax.annotation.Nullable;
import java.util.List;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.NonNullList;

public abstract class AbstractContainerMenu {
    private final NonNullList<ItemStack> lastSlots;
    public final List<Slot> slots;
    private final List<DataSlot> dataSlots;
    @Nullable
    private final MenuType<?> menuType;
    public final int containerId;
    private short changeUid;
    private int quickcraftType;
    private int quickcraftStatus;
    private final Set<Slot> quickcraftSlots;
    private final List<ContainerListener> containerListeners;
    private final Set<Player> unSynchedPlayers;
    
    protected AbstractContainerMenu(@Nullable final MenuType<?> bhk, final int integer) {
        this.lastSlots = NonNullList.<ItemStack>create();
        this.slots = Lists.newArrayList();
        this.dataSlots = Lists.newArrayList();
        this.quickcraftType = -1;
        this.quickcraftSlots = Sets.newHashSet();
        this.containerListeners = Lists.newArrayList();
        this.unSynchedPlayers = Sets.newHashSet();
        this.menuType = bhk;
        this.containerId = integer;
    }
    
    protected static boolean stillValid(final ContainerLevelAccess bgs, final Player bec, final Block bvr) {
        return bgs.<Boolean>evaluate((bqb, fu) -> {
            if (!bqb.getBlockState(fu).is(bvr)) {
                return false;
            }
            else {
                return bec.distanceToSqr(fu.getX() + 0.5, fu.getY() + 0.5, fu.getZ() + 0.5) <= 64.0;
            }
        }, Boolean.valueOf(true));
    }
    
    public MenuType<?> getType() {
        if (this.menuType == null) {
            throw new UnsupportedOperationException("Unable to construct this menu by type");
        }
        return this.menuType;
    }
    
    protected static void checkContainerSize(final Container amz, final int integer) {
        final int integer2 = amz.getContainerSize();
        if (integer2 < integer) {
            throw new IllegalArgumentException("Container size " + integer2 + " is smaller than expected " + integer);
        }
    }
    
    protected static void checkContainerDataCount(final ContainerData bgr, final int integer) {
        final int integer2 = bgr.getCount();
        if (integer2 < integer) {
            throw new IllegalArgumentException("Container data count " + integer2 + " is smaller than expected " + integer);
        }
    }
    
    protected Slot addSlot(final Slot bhw) {
        bhw.index = this.slots.size();
        this.slots.add(bhw);
        this.lastSlots.add(ItemStack.EMPTY);
        return bhw;
    }
    
    protected DataSlot addDataSlot(final DataSlot bgw) {
        this.dataSlots.add(bgw);
        return bgw;
    }
    
    protected void addDataSlots(final ContainerData bgr) {
        for (int integer3 = 0; integer3 < bgr.getCount(); ++integer3) {
            this.addDataSlot(DataSlot.forContainer(bgr, integer3));
        }
    }
    
    public void addSlotListener(final ContainerListener bgt) {
        if (this.containerListeners.contains(bgt)) {
            return;
        }
        this.containerListeners.add(bgt);
        bgt.refreshContainer(this, this.getItems());
        this.broadcastChanges();
    }
    
    public void removeSlotListener(final ContainerListener bgt) {
        this.containerListeners.remove(bgt);
    }
    
    public NonNullList<ItemStack> getItems() {
        final NonNullList<ItemStack> gi2 = NonNullList.<ItemStack>create();
        for (int integer3 = 0; integer3 < this.slots.size(); ++integer3) {
            gi2.add(this.slots.get(integer3).getItem());
        }
        return gi2;
    }
    
    public void broadcastChanges() {
        for (int integer2 = 0; integer2 < this.slots.size(); ++integer2) {
            final ItemStack bki3 = this.slots.get(integer2).getItem();
            final ItemStack bki4 = this.lastSlots.get(integer2);
            if (!ItemStack.matches(bki4, bki3)) {
                final ItemStack bki5 = bki3.copy();
                this.lastSlots.set(integer2, bki5);
                for (final ContainerListener bgt7 : this.containerListeners) {
                    bgt7.slotChanged(this, integer2, bki5);
                }
            }
        }
        for (int integer2 = 0; integer2 < this.dataSlots.size(); ++integer2) {
            final DataSlot bgw3 = this.dataSlots.get(integer2);
            if (bgw3.checkAndClearUpdateFlag()) {
                for (final ContainerListener bgt8 : this.containerListeners) {
                    bgt8.setContainerData(this, integer2, bgw3.get());
                }
            }
        }
    }
    
    public boolean clickMenuButton(final Player bec, final int integer) {
        return false;
    }
    
    public Slot getSlot(final int integer) {
        return this.slots.get(integer);
    }
    
    public ItemStack quickMoveStack(final Player bec, final int integer) {
        final Slot bhw4 = this.slots.get(integer);
        if (bhw4 != null) {
            return bhw4.getItem();
        }
        return ItemStack.EMPTY;
    }
    
    public ItemStack clicked(final int integer1, final int integer2, final ClickType bgq, final Player bec) {
        try {
            return this.doClick(integer1, integer2, bgq, bec);
        }
        catch (Exception exception6) {
            final CrashReport j7 = CrashReport.forThrowable(exception6, "Container click");
            final CrashReportCategory k8 = j7.addCategory("Click info");
            k8.setDetail("Menu Type", () -> (this.menuType != null) ? Registry.MENU.getKey(this.menuType).toString() : "<no type>");
            k8.setDetail("Menu Class", () -> this.getClass().getCanonicalName());
            k8.setDetail("Slot Count", this.slots.size());
            k8.setDetail("Slot", integer1);
            k8.setDetail("Button", integer2);
            k8.setDetail("Type", bgq);
            throw new ReportedException(j7);
        }
    }
    
    private ItemStack doClick(final int integer1, final int integer2, final ClickType bgq, final Player bec) {
        ItemStack bki6 = ItemStack.EMPTY;
        final Inventory beb7 = bec.inventory;
        if (bgq == ClickType.QUICK_CRAFT) {
            final int integer3 = this.quickcraftStatus;
            this.quickcraftStatus = getQuickcraftHeader(integer2);
            if ((integer3 != 1 || this.quickcraftStatus != 2) && integer3 != this.quickcraftStatus) {
                this.resetQuickCraft();
            }
            else if (beb7.getCarried().isEmpty()) {
                this.resetQuickCraft();
            }
            else if (this.quickcraftStatus == 0) {
                this.quickcraftType = getQuickcraftType(integer2);
                if (isValidQuickcraftType(this.quickcraftType, bec)) {
                    this.quickcraftStatus = 1;
                    this.quickcraftSlots.clear();
                }
                else {
                    this.resetQuickCraft();
                }
            }
            else if (this.quickcraftStatus == 1) {
                final Slot bhw9 = this.slots.get(integer1);
                final ItemStack bki7 = beb7.getCarried();
                if (bhw9 != null && canItemQuickReplace(bhw9, bki7, true) && bhw9.mayPlace(bki7) && (this.quickcraftType == 2 || bki7.getCount() > this.quickcraftSlots.size()) && this.canDragTo(bhw9)) {
                    this.quickcraftSlots.add(bhw9);
                }
            }
            else if (this.quickcraftStatus == 2) {
                if (!this.quickcraftSlots.isEmpty()) {
                    final ItemStack bki8 = beb7.getCarried().copy();
                    int integer4 = beb7.getCarried().getCount();
                    for (final Slot bhw10 : this.quickcraftSlots) {
                        final ItemStack bki9 = beb7.getCarried();
                        if (bhw10 != null && canItemQuickReplace(bhw10, bki9, true) && bhw10.mayPlace(bki9) && (this.quickcraftType == 2 || bki9.getCount() >= this.quickcraftSlots.size()) && this.canDragTo(bhw10)) {
                            final ItemStack bki10 = bki8.copy();
                            final int integer5 = bhw10.hasItem() ? bhw10.getItem().getCount() : 0;
                            getQuickCraftSlotCount(this.quickcraftSlots, this.quickcraftType, bki10, integer5);
                            final int integer6 = Math.min(bki10.getMaxStackSize(), bhw10.getMaxStackSize(bki10));
                            if (bki10.getCount() > integer6) {
                                bki10.setCount(integer6);
                            }
                            integer4 -= bki10.getCount() - integer5;
                            bhw10.set(bki10);
                        }
                    }
                    bki8.setCount(integer4);
                    beb7.setCarried(bki8);
                }
                this.resetQuickCraft();
            }
            else {
                this.resetQuickCraft();
            }
        }
        else if (this.quickcraftStatus != 0) {
            this.resetQuickCraft();
        }
        else if ((bgq == ClickType.PICKUP || bgq == ClickType.QUICK_MOVE) && (integer2 == 0 || integer2 == 1)) {
            if (integer1 == -999) {
                if (!beb7.getCarried().isEmpty()) {
                    if (integer2 == 0) {
                        bec.drop(beb7.getCarried(), true);
                        beb7.setCarried(ItemStack.EMPTY);
                    }
                    if (integer2 == 1) {
                        bec.drop(beb7.getCarried().split(1), true);
                    }
                }
            }
            else if (bgq == ClickType.QUICK_MOVE) {
                if (integer1 < 0) {
                    return ItemStack.EMPTY;
                }
                final Slot bhw11 = this.slots.get(integer1);
                if (bhw11 == null || !bhw11.mayPickup(bec)) {
                    return ItemStack.EMPTY;
                }
                for (ItemStack bki8 = this.quickMoveStack(bec, integer1); !bki8.isEmpty() && ItemStack.isSame(bhw11.getItem(), bki8); bki8 = this.quickMoveStack(bec, integer1)) {
                    bki6 = bki8.copy();
                }
            }
            else {
                if (integer1 < 0) {
                    return ItemStack.EMPTY;
                }
                final Slot bhw11 = this.slots.get(integer1);
                if (bhw11 != null) {
                    ItemStack bki8 = bhw11.getItem();
                    final ItemStack bki7 = beb7.getCarried();
                    if (!bki8.isEmpty()) {
                        bki6 = bki8.copy();
                    }
                    if (bki8.isEmpty()) {
                        if (!bki7.isEmpty() && bhw11.mayPlace(bki7)) {
                            int integer7 = (integer2 == 0) ? bki7.getCount() : 1;
                            if (integer7 > bhw11.getMaxStackSize(bki7)) {
                                integer7 = bhw11.getMaxStackSize(bki7);
                            }
                            bhw11.set(bki7.split(integer7));
                        }
                    }
                    else if (bhw11.mayPickup(bec)) {
                        if (bki7.isEmpty()) {
                            if (bki8.isEmpty()) {
                                bhw11.set(ItemStack.EMPTY);
                                beb7.setCarried(ItemStack.EMPTY);
                            }
                            else {
                                final int integer7 = (integer2 == 0) ? bki8.getCount() : ((bki8.getCount() + 1) / 2);
                                beb7.setCarried(bhw11.remove(integer7));
                                if (bki8.isEmpty()) {
                                    bhw11.set(ItemStack.EMPTY);
                                }
                                bhw11.onTake(bec, beb7.getCarried());
                            }
                        }
                        else if (bhw11.mayPlace(bki7)) {
                            if (consideredTheSameItem(bki8, bki7)) {
                                int integer7 = (integer2 == 0) ? bki7.getCount() : 1;
                                if (integer7 > bhw11.getMaxStackSize(bki7) - bki8.getCount()) {
                                    integer7 = bhw11.getMaxStackSize(bki7) - bki8.getCount();
                                }
                                if (integer7 > bki7.getMaxStackSize() - bki8.getCount()) {
                                    integer7 = bki7.getMaxStackSize() - bki8.getCount();
                                }
                                bki7.shrink(integer7);
                                bki8.grow(integer7);
                            }
                            else if (bki7.getCount() <= bhw11.getMaxStackSize(bki7)) {
                                bhw11.set(bki7);
                                beb7.setCarried(bki8);
                            }
                        }
                        else if (bki7.getMaxStackSize() > 1 && consideredTheSameItem(bki8, bki7) && !bki8.isEmpty()) {
                            final int integer7 = bki8.getCount();
                            if (integer7 + bki7.getCount() <= bki7.getMaxStackSize()) {
                                bki7.grow(integer7);
                                bki8 = bhw11.remove(integer7);
                                if (bki8.isEmpty()) {
                                    bhw11.set(ItemStack.EMPTY);
                                }
                                bhw11.onTake(bec, beb7.getCarried());
                            }
                        }
                    }
                    bhw11.setChanged();
                }
            }
        }
        else if (bgq == ClickType.SWAP) {
            final Slot bhw11 = this.slots.get(integer1);
            final ItemStack bki8 = beb7.getItem(integer2);
            final ItemStack bki7 = bhw11.getItem();
            if (!bki8.isEmpty() || !bki7.isEmpty()) {
                if (bki8.isEmpty()) {
                    if (bhw11.mayPickup(bec)) {
                        beb7.setItem(integer2, bki7);
                        bhw11.onSwapCraft(bki7.getCount());
                        bhw11.set(ItemStack.EMPTY);
                        bhw11.onTake(bec, bki7);
                    }
                }
                else if (bki7.isEmpty()) {
                    if (bhw11.mayPlace(bki8)) {
                        final int integer7 = bhw11.getMaxStackSize(bki8);
                        if (bki8.getCount() > integer7) {
                            bhw11.set(bki8.split(integer7));
                        }
                        else {
                            bhw11.set(bki8);
                            beb7.setItem(integer2, ItemStack.EMPTY);
                        }
                    }
                }
                else if (bhw11.mayPickup(bec) && bhw11.mayPlace(bki8)) {
                    final int integer7 = bhw11.getMaxStackSize(bki8);
                    if (bki8.getCount() > integer7) {
                        bhw11.set(bki8.split(integer7));
                        bhw11.onTake(bec, bki7);
                        if (!beb7.add(bki7)) {
                            bec.drop(bki7, true);
                        }
                    }
                    else {
                        bhw11.set(bki8);
                        beb7.setItem(integer2, bki7);
                        bhw11.onTake(bec, bki7);
                    }
                }
            }
        }
        else if (bgq == ClickType.CLONE && bec.abilities.instabuild && beb7.getCarried().isEmpty() && integer1 >= 0) {
            final Slot bhw11 = this.slots.get(integer1);
            if (bhw11 != null && bhw11.hasItem()) {
                final ItemStack bki8 = bhw11.getItem().copy();
                bki8.setCount(bki8.getMaxStackSize());
                beb7.setCarried(bki8);
            }
        }
        else if (bgq == ClickType.THROW && beb7.getCarried().isEmpty() && integer1 >= 0) {
            final Slot bhw11 = this.slots.get(integer1);
            if (bhw11 != null && bhw11.hasItem() && bhw11.mayPickup(bec)) {
                final ItemStack bki8 = bhw11.remove((integer2 == 0) ? 1 : bhw11.getItem().getCount());
                bhw11.onTake(bec, bki8);
                bec.drop(bki8, true);
            }
        }
        else if (bgq == ClickType.PICKUP_ALL && integer1 >= 0) {
            final Slot bhw11 = this.slots.get(integer1);
            final ItemStack bki8 = beb7.getCarried();
            if (!bki8.isEmpty() && (bhw11 == null || !bhw11.hasItem() || !bhw11.mayPickup(bec))) {
                final int integer4 = (integer2 == 0) ? 0 : (this.slots.size() - 1);
                final int integer7 = (integer2 == 0) ? 1 : -1;
                for (int integer8 = 0; integer8 < 2; ++integer8) {
                    for (int integer9 = integer4; integer9 >= 0 && integer9 < this.slots.size() && bki8.getCount() < bki8.getMaxStackSize(); integer9 += integer7) {
                        final Slot bhw12 = this.slots.get(integer9);
                        if (bhw12.hasItem() && canItemQuickReplace(bhw12, bki8, true) && bhw12.mayPickup(bec) && this.canTakeItemForPickAll(bki8, bhw12)) {
                            final ItemStack bki11 = bhw12.getItem();
                            if (integer8 != 0 || bki11.getCount() != bki11.getMaxStackSize()) {
                                final int integer6 = Math.min(bki8.getMaxStackSize() - bki8.getCount(), bki11.getCount());
                                final ItemStack bki12 = bhw12.remove(integer6);
                                bki8.grow(integer6);
                                if (bki12.isEmpty()) {
                                    bhw12.set(ItemStack.EMPTY);
                                }
                                bhw12.onTake(bec, bki12);
                            }
                        }
                    }
                }
            }
            this.broadcastChanges();
        }
        return bki6;
    }
    
    public static boolean consideredTheSameItem(final ItemStack bki1, final ItemStack bki2) {
        return bki1.getItem() == bki2.getItem() && ItemStack.tagMatches(bki1, bki2);
    }
    
    public boolean canTakeItemForPickAll(final ItemStack bki, final Slot bhw) {
        return true;
    }
    
    public void removed(final Player bec) {
        final Inventory beb3 = bec.inventory;
        if (!beb3.getCarried().isEmpty()) {
            bec.drop(beb3.getCarried(), false);
            beb3.setCarried(ItemStack.EMPTY);
        }
    }
    
    protected void clearContainer(final Player bec, final Level bqb, final Container amz) {
        if (!bec.isAlive() || (bec instanceof ServerPlayer && ((ServerPlayer)bec).hasDisconnected())) {
            for (int integer5 = 0; integer5 < amz.getContainerSize(); ++integer5) {
                bec.drop(amz.removeItemNoUpdate(integer5), false);
            }
            return;
        }
        for (int integer5 = 0; integer5 < amz.getContainerSize(); ++integer5) {
            bec.inventory.placeItemBackInInventory(bqb, amz.removeItemNoUpdate(integer5));
        }
    }
    
    public void slotsChanged(final Container amz) {
        this.broadcastChanges();
    }
    
    public void setItem(final int integer, final ItemStack bki) {
        this.getSlot(integer).set(bki);
    }
    
    public void setAll(final List<ItemStack> list) {
        for (int integer3 = 0; integer3 < list.size(); ++integer3) {
            this.getSlot(integer3).set(list.get(integer3));
        }
    }
    
    public void setData(final int integer1, final int integer2) {
        this.dataSlots.get(integer1).set(integer2);
    }
    
    public short backup(final Inventory beb) {
        return (short)(++this.changeUid);
    }
    
    public boolean isSynched(final Player bec) {
        return !this.unSynchedPlayers.contains(bec);
    }
    
    public void setSynched(final Player bec, final boolean boolean2) {
        if (boolean2) {
            this.unSynchedPlayers.remove(bec);
        }
        else {
            this.unSynchedPlayers.add(bec);
        }
    }
    
    public abstract boolean stillValid(final Player bec);
    
    protected boolean moveItemStackTo(final ItemStack bki, final int integer2, final int integer3, final boolean boolean4) {
        boolean boolean5 = false;
        int integer4 = integer2;
        if (boolean4) {
            integer4 = integer3 - 1;
        }
        if (bki.isStackable()) {
            while (!bki.isEmpty()) {
                if (boolean4) {
                    if (integer4 < integer2) {
                        break;
                    }
                }
                else if (integer4 >= integer3) {
                    break;
                }
                final Slot bhw8 = this.slots.get(integer4);
                final ItemStack bki2 = bhw8.getItem();
                if (!bki2.isEmpty() && consideredTheSameItem(bki, bki2)) {
                    final int integer5 = bki2.getCount() + bki.getCount();
                    if (integer5 <= bki.getMaxStackSize()) {
                        bki.setCount(0);
                        bki2.setCount(integer5);
                        bhw8.setChanged();
                        boolean5 = true;
                    }
                    else if (bki2.getCount() < bki.getMaxStackSize()) {
                        bki.shrink(bki.getMaxStackSize() - bki2.getCount());
                        bki2.setCount(bki.getMaxStackSize());
                        bhw8.setChanged();
                        boolean5 = true;
                    }
                }
                if (boolean4) {
                    --integer4;
                }
                else {
                    ++integer4;
                }
            }
        }
        if (!bki.isEmpty()) {
            if (boolean4) {
                integer4 = integer3 - 1;
            }
            else {
                integer4 = integer2;
            }
            while (true) {
                if (boolean4) {
                    if (integer4 < integer2) {
                        break;
                    }
                }
                else if (integer4 >= integer3) {
                    break;
                }
                final Slot bhw8 = this.slots.get(integer4);
                final ItemStack bki2 = bhw8.getItem();
                if (bki2.isEmpty() && bhw8.mayPlace(bki)) {
                    if (bki.getCount() > bhw8.getMaxStackSize()) {
                        bhw8.set(bki.split(bhw8.getMaxStackSize()));
                    }
                    else {
                        bhw8.set(bki.split(bki.getCount()));
                    }
                    bhw8.setChanged();
                    boolean5 = true;
                    break;
                }
                if (boolean4) {
                    --integer4;
                }
                else {
                    ++integer4;
                }
            }
        }
        return boolean5;
    }
    
    public static int getQuickcraftType(final int integer) {
        return integer >> 2 & 0x3;
    }
    
    public static int getQuickcraftHeader(final int integer) {
        return integer & 0x3;
    }
    
    public static int getQuickcraftMask(final int integer1, final int integer2) {
        return (integer1 & 0x3) | (integer2 & 0x3) << 2;
    }
    
    public static boolean isValidQuickcraftType(final int integer, final Player bec) {
        return integer == 0 || integer == 1 || (integer == 2 && bec.abilities.instabuild);
    }
    
    protected void resetQuickCraft() {
        this.quickcraftStatus = 0;
        this.quickcraftSlots.clear();
    }
    
    public static boolean canItemQuickReplace(@Nullable final Slot bhw, final ItemStack bki, final boolean boolean3) {
        final boolean boolean4 = bhw == null || !bhw.hasItem();
        if (!boolean4 && bki.sameItem(bhw.getItem()) && ItemStack.tagMatches(bhw.getItem(), bki)) {
            return bhw.getItem().getCount() + (boolean3 ? 0 : bki.getCount()) <= bki.getMaxStackSize();
        }
        return boolean4;
    }
    
    public static void getQuickCraftSlotCount(final Set<Slot> set, final int integer2, final ItemStack bki, final int integer4) {
        switch (integer2) {
            case 0: {
                bki.setCount(Mth.floor(bki.getCount() / (float)set.size()));
                break;
            }
            case 1: {
                bki.setCount(1);
                break;
            }
            case 2: {
                bki.setCount(bki.getItem().getMaxStackSize());
                break;
            }
        }
        bki.grow(integer4);
    }
    
    public boolean canDragTo(final Slot bhw) {
        return true;
    }
    
    public static int getRedstoneSignalFromBlockEntity(@Nullable final BlockEntity cdl) {
        if (cdl instanceof Container) {
            return getRedstoneSignalFromContainer((Container)cdl);
        }
        return 0;
    }
    
    public static int getRedstoneSignalFromContainer(@Nullable final Container amz) {
        if (amz == null) {
            return 0;
        }
        int integer2 = 0;
        float float3 = 0.0f;
        for (int integer3 = 0; integer3 < amz.getContainerSize(); ++integer3) {
            final ItemStack bki5 = amz.getItem(integer3);
            if (!bki5.isEmpty()) {
                float3 += bki5.getCount() / (float)Math.min(amz.getMaxStackSize(), bki5.getMaxStackSize());
                ++integer2;
            }
        }
        float3 /= amz.getContainerSize();
        return Mth.floor(float3 * 14.0f) + ((integer2 > 0) ? 1 : 0);
    }
}
