package net.minecraft.world.entity.player;

import java.util.AbstractList;
import net.minecraft.tags.Tag;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.chat.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.ContainerHelper;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.CrashReport;
import java.util.Iterator;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import java.util.function.Predicate;
import com.google.common.collect.ImmutableList;
import java.util.List;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.NonNullList;
import net.minecraft.world.Nameable;
import net.minecraft.world.Container;

public class Inventory implements Container, Nameable {
    public final NonNullList<ItemStack> items;
    public final NonNullList<ItemStack> armor;
    public final NonNullList<ItemStack> offhand;
    private final List<NonNullList<ItemStack>> compartments;
    public int selected;
    public final Player player;
    private ItemStack carried;
    private int timesChanged;
    
    public Inventory(final Player ayj) {
        this.items = NonNullList.<ItemStack>withSize(36, ItemStack.EMPTY);
        this.armor = NonNullList.<ItemStack>withSize(4, ItemStack.EMPTY);
        this.offhand = NonNullList.<ItemStack>withSize(1, ItemStack.EMPTY);
        this.compartments = ImmutableList.<NonNullList<ItemStack>>of(this.items, this.armor, this.offhand);
        this.carried = ItemStack.EMPTY;
        this.player = ayj;
    }
    
    public ItemStack getSelected() {
        if (isHotbarSlot(this.selected)) {
            return this.items.get(this.selected);
        }
        return ItemStack.EMPTY;
    }
    
    public static int getSelectionSize() {
        return 9;
    }
    
    private boolean hasRemainingSpaceForItem(final ItemStack ben1, final ItemStack ben2) {
        return !ben1.isEmpty() && this.isSameItem(ben1, ben2) && ben1.isStackable() && ben1.getCount() < ben1.getMaxStackSize() && ben1.getCount() < this.getMaxStackSize();
    }
    
    private boolean isSameItem(final ItemStack ben1, final ItemStack ben2) {
        return ben1.getItem() == ben2.getItem() && ItemStack.tagMatches(ben1, ben2);
    }
    
    public int getFreeSlot() {
        for (int integer2 = 0; integer2 < this.items.size(); ++integer2) {
            if (this.items.get(integer2).isEmpty()) {
                return integer2;
            }
        }
        return -1;
    }
    
    public void setPickedItem(final ItemStack ben) {
        final int integer3 = this.findSlotMatchingItem(ben);
        if (isHotbarSlot(integer3)) {
            this.selected = integer3;
            return;
        }
        if (integer3 == -1) {
            this.selected = this.getSuitableHotbarSlot();
            if (!this.items.get(this.selected).isEmpty()) {
                final int integer4 = this.getFreeSlot();
                if (integer4 != -1) {
                    this.items.set(integer4, this.items.get(this.selected));
                }
            }
            this.items.set(this.selected, ben);
        }
        else {
            this.pickSlot(integer3);
        }
    }
    
    public void pickSlot(final int integer) {
        this.selected = this.getSuitableHotbarSlot();
        final ItemStack ben3 = this.items.get(this.selected);
        this.items.set(this.selected, this.items.get(integer));
        this.items.set(integer, ben3);
    }
    
    public static boolean isHotbarSlot(final int integer) {
        return integer >= 0 && integer < 9;
    }
    
    public int findSlotMatchingItem(final ItemStack ben) {
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            if (!this.items.get(integer3).isEmpty() && this.isSameItem(ben, this.items.get(integer3))) {
                return integer3;
            }
        }
        return -1;
    }
    
    public int findSlotMatchingUnusedItem(final ItemStack ben) {
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            final ItemStack ben2 = this.items.get(integer3);
            if (!this.items.get(integer3).isEmpty() && this.isSameItem(ben, this.items.get(integer3)) && !this.items.get(integer3).isDamaged() && !ben2.isEnchanted() && !ben2.hasCustomHoverName()) {
                return integer3;
            }
        }
        return -1;
    }
    
    public int getSuitableHotbarSlot() {
        for (int integer2 = 0; integer2 < 9; ++integer2) {
            final int integer3 = (this.selected + integer2) % 9;
            if (this.items.get(integer3).isEmpty()) {
                return integer3;
            }
        }
        for (int integer2 = 0; integer2 < 9; ++integer2) {
            final int integer3 = (this.selected + integer2) % 9;
            if (!this.items.get(integer3).isEnchanted()) {
                return integer3;
            }
        }
        return this.selected;
    }
    
    public void swapPaint(double double1) {
        if (double1 > 0.0) {
            double1 = 1.0;
        }
        if (double1 < 0.0) {
            double1 = -1.0;
        }
        this.selected -= (int)double1;
        while (this.selected < 0) {
            this.selected += 9;
        }
        while (this.selected >= 9) {
            this.selected -= 9;
        }
    }
    
    public int clearInventory(final Predicate<ItemStack> predicate, final int integer) {
        int integer2 = 0;
        for (int integer3 = 0; integer3 < this.getContainerSize(); ++integer3) {
            final ItemStack ben6 = this.getItem(integer3);
            if (!ben6.isEmpty()) {
                if (predicate.test(ben6)) {
                    final int integer4 = (integer <= 0) ? ben6.getCount() : Math.min(integer - integer2, ben6.getCount());
                    integer2 += integer4;
                    if (integer != 0) {
                        ben6.shrink(integer4);
                        if (ben6.isEmpty()) {
                            this.setItem(integer3, ItemStack.EMPTY);
                        }
                        if (integer > 0 && integer2 >= integer) {
                            return integer2;
                        }
                    }
                }
            }
        }
        if (!this.carried.isEmpty() && predicate.test(this.carried)) {
            final int integer3 = (integer <= 0) ? this.carried.getCount() : Math.min(integer - integer2, this.carried.getCount());
            integer2 += integer3;
            if (integer != 0) {
                this.carried.shrink(integer3);
                if (this.carried.isEmpty()) {
                    this.carried = ItemStack.EMPTY;
                }
                if (integer > 0 && integer2 >= integer) {
                    return integer2;
                }
            }
        }
        return integer2;
    }
    
    private int addResource(final ItemStack ben) {
        int integer3 = this.getSlotWithRemainingSpace(ben);
        if (integer3 == -1) {
            integer3 = this.getFreeSlot();
        }
        if (integer3 == -1) {
            return ben.getCount();
        }
        return this.addResource(integer3, ben);
    }
    
    private int addResource(final int integer, final ItemStack ben) {
        final Item bei4 = ben.getItem();
        int integer2 = ben.getCount();
        ItemStack ben2 = this.getItem(integer);
        if (ben2.isEmpty()) {
            ben2 = new ItemStack(bei4, 0);
            if (ben.hasTag()) {
                ben2.setTag(ben.getTag().copy());
            }
            this.setItem(integer, ben2);
        }
        int integer3 = integer2;
        if (integer3 > ben2.getMaxStackSize() - ben2.getCount()) {
            integer3 = ben2.getMaxStackSize() - ben2.getCount();
        }
        if (integer3 > this.getMaxStackSize() - ben2.getCount()) {
            integer3 = this.getMaxStackSize() - ben2.getCount();
        }
        if (integer3 == 0) {
            return integer2;
        }
        integer2 -= integer3;
        ben2.grow(integer3);
        ben2.setPopTime(5);
        return integer2;
    }
    
    public int getSlotWithRemainingSpace(final ItemStack ben) {
        if (this.hasRemainingSpaceForItem(this.getItem(this.selected), ben)) {
            return this.selected;
        }
        if (this.hasRemainingSpaceForItem(this.getItem(40), ben)) {
            return 40;
        }
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            if (this.hasRemainingSpaceForItem(this.items.get(integer3), ben)) {
                return integer3;
            }
        }
        return -1;
    }
    
    public void tick() {
        for (final NonNullList<ItemStack> fy3 : this.compartments) {
            for (int integer4 = 0; integer4 < fy3.size(); ++integer4) {
                if (!fy3.get(integer4).isEmpty()) {
                    fy3.get(integer4).inventoryTick(this.player.level, this.player, integer4, this.selected == integer4);
                }
            }
        }
    }
    
    public boolean add(final ItemStack ben) {
        return this.add(-1, ben);
    }
    
    public boolean add(int integer, final ItemStack ben) {
        if (ben.isEmpty()) {
            return false;
        }
        try {
            if (!ben.isDamaged()) {
                int integer2;
                do {
                    integer2 = ben.getCount();
                    if (integer == -1) {
                        ben.setCount(this.addResource(ben));
                    }
                    else {
                        ben.setCount(this.addResource(integer, ben));
                    }
                } while (!ben.isEmpty() && ben.getCount() < integer2);
                if (ben.getCount() == integer2 && this.player.abilities.instabuild) {
                    ben.setCount(0);
                    return true;
                }
                return ben.getCount() < integer2;
            }
            else {
                if (integer == -1) {
                    integer = this.getFreeSlot();
                }
                if (integer >= 0) {
                    this.items.set(integer, ben.copy());
                    this.items.get(integer).setPopTime(5);
                    ben.setCount(0);
                    return true;
                }
                if (this.player.abilities.instabuild) {
                    ben.setCount(0);
                    return true;
                }
                return false;
            }
        }
        catch (Throwable throwable4) {
            final CrashReport h5 = CrashReport.forThrowable(throwable4, "Adding item to inventory");
            final CrashReportCategory i6 = h5.addCategory("Item being added");
            i6.setDetail("Item ID", Item.getId(ben.getItem()));
            i6.setDetail("Item data", ben.getDamageValue());
            i6.setDetail("Item name", () -> ben.getHoverName().getString());
            throw new ReportedException(h5);
        }
    }
    
    public void placeItemBackInInventory(final Level bjw, final ItemStack ben) {
        if (bjw.isClientSide) {
            return;
        }
        while (!ben.isEmpty()) {
            int integer4 = this.getSlotWithRemainingSpace(ben);
            if (integer4 == -1) {
                integer4 = this.getFreeSlot();
            }
            if (integer4 == -1) {
                this.player.drop(ben, false);
                break;
            }
            final int integer5 = ben.getMaxStackSize() - this.getItem(integer4).getCount();
            if (!this.add(integer4, ben.split(integer5))) {
                continue;
            }
            ((ServerPlayer)this.player).connection.send(new ClientboundContainerSetSlotPacket(-2, integer4, this.getItem(integer4)));
        }
    }
    
    @Override
    public ItemStack removeItem(int integer1, final int integer2) {
        List<ItemStack> list4 = null;
        for (final NonNullList<ItemStack> fy6 : this.compartments) {
            if (integer1 < fy6.size()) {
                list4 = fy6;
                break;
            }
            integer1 -= fy6.size();
        }
        if (list4 != null && !list4.get(integer1).isEmpty()) {
            return ContainerHelper.removeItem(list4, integer1, integer2);
        }
        return ItemStack.EMPTY;
    }
    
    public void removeItem(final ItemStack ben) {
        for (final NonNullList<ItemStack> fy4 : this.compartments) {
            for (int integer5 = 0; integer5 < fy4.size(); ++integer5) {
                if (fy4.get(integer5) == ben) {
                    fy4.set(integer5, ItemStack.EMPTY);
                    break;
                }
            }
        }
    }
    
    @Override
    public ItemStack removeItemNoUpdate(int integer) {
        NonNullList<ItemStack> fy3 = null;
        for (final NonNullList<ItemStack> fy4 : this.compartments) {
            if (integer < fy4.size()) {
                fy3 = fy4;
                break;
            }
            integer -= fy4.size();
        }
        if (fy3 != null && !fy3.get(integer).isEmpty()) {
            final ItemStack ben4 = fy3.get(integer);
            fy3.set(integer, ItemStack.EMPTY);
            return ben4;
        }
        return ItemStack.EMPTY;
    }
    
    @Override
    public void setItem(int integer, final ItemStack ben) {
        NonNullList<ItemStack> fy4 = null;
        for (final NonNullList<ItemStack> fy5 : this.compartments) {
            if (integer < fy5.size()) {
                fy4 = fy5;
                break;
            }
            integer -= fy5.size();
        }
        if (fy4 != null) {
            fy4.set(integer, ben);
        }
    }
    
    public float getDestroySpeed(final BlockState byj) {
        return this.items.get(this.selected).getDestroySpeed(byj);
    }
    
    public ListTag save(final ListTag jz) {
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            if (!this.items.get(integer3).isEmpty()) {
                final CompoundTag jt4 = new CompoundTag();
                jt4.putByte("Slot", (byte)integer3);
                this.items.get(integer3).save(jt4);
                ((AbstractList<CompoundTag>)jz).add(jt4);
            }
        }
        for (int integer3 = 0; integer3 < this.armor.size(); ++integer3) {
            if (!this.armor.get(integer3).isEmpty()) {
                final CompoundTag jt4 = new CompoundTag();
                jt4.putByte("Slot", (byte)(integer3 + 100));
                this.armor.get(integer3).save(jt4);
                ((AbstractList<CompoundTag>)jz).add(jt4);
            }
        }
        for (int integer3 = 0; integer3 < this.offhand.size(); ++integer3) {
            if (!this.offhand.get(integer3).isEmpty()) {
                final CompoundTag jt4 = new CompoundTag();
                jt4.putByte("Slot", (byte)(integer3 + 150));
                this.offhand.get(integer3).save(jt4);
                ((AbstractList<CompoundTag>)jz).add(jt4);
            }
        }
        return jz;
    }
    
    public void load(final ListTag jz) {
        this.items.clear();
        this.armor.clear();
        this.offhand.clear();
        for (int integer3 = 0; integer3 < jz.size(); ++integer3) {
            final CompoundTag jt4 = jz.getCompound(integer3);
            final int integer4 = jt4.getByte("Slot") & 0xFF;
            final ItemStack ben6 = ItemStack.of(jt4);
            if (!ben6.isEmpty()) {
                if (integer4 >= 0 && integer4 < this.items.size()) {
                    this.items.set(integer4, ben6);
                }
                else if (integer4 >= 100 && integer4 < this.armor.size() + 100) {
                    this.armor.set(integer4 - 100, ben6);
                }
                else if (integer4 >= 150 && integer4 < this.offhand.size() + 150) {
                    this.offhand.set(integer4 - 150, ben6);
                }
            }
        }
    }
    
    @Override
    public int getContainerSize() {
        return this.items.size() + this.armor.size() + this.offhand.size();
    }
    
    @Override
    public boolean isEmpty() {
        for (final ItemStack ben3 : this.items) {
            if (!ben3.isEmpty()) {
                return false;
            }
        }
        for (final ItemStack ben3 : this.armor) {
            if (!ben3.isEmpty()) {
                return false;
            }
        }
        for (final ItemStack ben3 : this.offhand) {
            if (!ben3.isEmpty()) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public ItemStack getItem(int integer) {
        List<ItemStack> list3 = null;
        for (final NonNullList<ItemStack> fy5 : this.compartments) {
            if (integer < fy5.size()) {
                list3 = fy5;
                break;
            }
            integer -= fy5.size();
        }
        return (list3 == null) ? ItemStack.EMPTY : list3.get(integer);
    }
    
    @Override
    public Component getName() {
        return new TranslatableComponent("container.inventory", new Object[0]);
    }
    
    public boolean canDestroy(final BlockState byj) {
        return this.getItem(this.selected).canDestroySpecial(byj);
    }
    
    public ItemStack getArmor(final int integer) {
        return this.armor.get(integer);
    }
    
    public void hurtArmor(float float1) {
        if (float1 <= 0.0f) {
            return;
        }
        float1 /= 4.0f;
        if (float1 < 1.0f) {
            float1 = 1.0f;
        }
        for (int integer3 = 0; integer3 < this.armor.size(); ++integer3) {
            final ItemStack ben4 = this.armor.get(integer3);
            if (ben4.getItem() instanceof ArmorItem) {
                final int integer4 = integer3;
                ben4.<Player>hurtAndBreak((int)float1, this.player, ayj -> ayj.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, integer4)));
            }
        }
    }
    
    public void dropAll() {
        for (final List<ItemStack> list3 : this.compartments) {
            for (int integer4 = 0; integer4 < list3.size(); ++integer4) {
                final ItemStack ben5 = list3.get(integer4);
                if (!ben5.isEmpty()) {
                    this.player.drop(ben5, true, false);
                    list3.set(integer4, ItemStack.EMPTY);
                }
            }
        }
    }
    
    @Override
    public void setChanged() {
        ++this.timesChanged;
    }
    
    public int getTimesChanged() {
        return this.timesChanged;
    }
    
    public void setCarried(final ItemStack ben) {
        this.carried = ben;
    }
    
    public ItemStack getCarried() {
        return this.carried;
    }
    
    @Override
    public boolean stillValid(final Player ayj) {
        return !this.player.removed && ayj.distanceToSqr(this.player) <= 64.0;
    }
    
    public boolean contains(final ItemStack ben) {
        for (final List<ItemStack> list4 : this.compartments) {
            for (final ItemStack ben2 : list4) {
                if (!ben2.isEmpty() && ben2.sameItem(ben)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    public boolean contains(final Tag<Item> aaz) {
        for (final List<ItemStack> list4 : this.compartments) {
            for (final ItemStack ben6 : list4) {
                if (!ben6.isEmpty() && aaz.contains(ben6.getItem())) {
                    return true;
                }
            }
        }
        return false;
    }
    
    public void replaceWith(final Inventory ayi) {
        for (int integer3 = 0; integer3 < this.getContainerSize(); ++integer3) {
            this.setItem(integer3, ayi.getItem(integer3));
        }
        this.selected = ayi.selected;
    }
    
    @Override
    public void clearContent() {
        for (final List<ItemStack> list3 : this.compartments) {
            list3.clear();
        }
    }
    
    public void fillStackedContents(final StackedContents ayl) {
        for (final ItemStack ben4 : this.items) {
            ayl.accountSimpleStack(ben4);
        }
    }
}
