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.world.damagesource.DamageSource;
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.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 net.minecraft.world.ContainerHelper;
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 bec) {
        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 = bec;
    }
    
    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 bki1, final ItemStack bki2) {
        return !bki1.isEmpty() && this.isSameItem(bki1, bki2) && bki1.isStackable() && bki1.getCount() < bki1.getMaxStackSize() && bki1.getCount() < this.getMaxStackSize();
    }
    
    private boolean isSameItem(final ItemStack bki1, final ItemStack bki2) {
        return bki1.getItem() == bki2.getItem() && ItemStack.tagMatches(bki1, bki2);
    }
    
    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 bki) {
        final int integer3 = this.findSlotMatchingItem(bki);
        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, bki);
        }
        else {
            this.pickSlot(integer3);
        }
    }
    
    public void pickSlot(final int integer) {
        this.selected = this.getSuitableHotbarSlot();
        final ItemStack bki3 = this.items.get(this.selected);
        this.items.set(this.selected, this.items.get(integer));
        this.items.set(integer, bki3);
    }
    
    public static boolean isHotbarSlot(final int integer) {
        return integer >= 0 && integer < 9;
    }
    
    public int findSlotMatchingItem(final ItemStack bki) {
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            if (!this.items.get(integer3).isEmpty() && this.isSameItem(bki, this.items.get(integer3))) {
                return integer3;
            }
        }
        return -1;
    }
    
    public int findSlotMatchingUnusedItem(final ItemStack bki) {
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            final ItemStack bki2 = this.items.get(integer3);
            if (!this.items.get(integer3).isEmpty() && this.isSameItem(bki, this.items.get(integer3)) && !this.items.get(integer3).isDamaged() && !bki2.isEnchanted() && !bki2.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 clearOrCountMatchingItems(final Predicate<ItemStack> predicate, final int integer, final Container amz) {
        int integer2 = 0;
        final boolean boolean6 = integer == 0;
        integer2 += ContainerHelper.clearOrCountMatchingItems(this, predicate, integer - integer2, boolean6);
        integer2 += ContainerHelper.clearOrCountMatchingItems(amz, predicate, integer - integer2, boolean6);
        integer2 += ContainerHelper.clearOrCountMatchingItems(this.carried, predicate, integer - integer2, boolean6);
        if (this.carried.isEmpty()) {
            this.carried = ItemStack.EMPTY;
        }
        return integer2;
    }
    
    private int addResource(final ItemStack bki) {
        int integer3 = this.getSlotWithRemainingSpace(bki);
        if (integer3 == -1) {
            integer3 = this.getFreeSlot();
        }
        if (integer3 == -1) {
            return bki.getCount();
        }
        return this.addResource(integer3, bki);
    }
    
    private int addResource(final int integer, final ItemStack bki) {
        final Item bke4 = bki.getItem();
        int integer2 = bki.getCount();
        ItemStack bki2 = this.getItem(integer);
        if (bki2.isEmpty()) {
            bki2 = new ItemStack(bke4, 0);
            if (bki.hasTag()) {
                bki2.setTag(bki.getTag().copy());
            }
            this.setItem(integer, bki2);
        }
        int integer3 = integer2;
        if (integer3 > bki2.getMaxStackSize() - bki2.getCount()) {
            integer3 = bki2.getMaxStackSize() - bki2.getCount();
        }
        if (integer3 > this.getMaxStackSize() - bki2.getCount()) {
            integer3 = this.getMaxStackSize() - bki2.getCount();
        }
        if (integer3 == 0) {
            return integer2;
        }
        integer2 -= integer3;
        bki2.grow(integer3);
        bki2.setPopTime(5);
        return integer2;
    }
    
    public int getSlotWithRemainingSpace(final ItemStack bki) {
        if (this.hasRemainingSpaceForItem(this.getItem(this.selected), bki)) {
            return this.selected;
        }
        if (this.hasRemainingSpaceForItem(this.getItem(40), bki)) {
            return 40;
        }
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            if (this.hasRemainingSpaceForItem(this.items.get(integer3), bki)) {
                return integer3;
            }
        }
        return -1;
    }
    
    public void tick() {
        for (final NonNullList<ItemStack> gi3 : this.compartments) {
            for (int integer4 = 0; integer4 < gi3.size(); ++integer4) {
                if (!gi3.get(integer4).isEmpty()) {
                    gi3.get(integer4).inventoryTick(this.player.level, this.player, integer4, this.selected == integer4);
                }
            }
        }
    }
    
    public boolean add(final ItemStack bki) {
        return this.add(-1, bki);
    }
    
    public boolean add(int integer, final ItemStack bki) {
        if (bki.isEmpty()) {
            return false;
        }
        try {
            if (!bki.isDamaged()) {
                int integer2;
                do {
                    integer2 = bki.getCount();
                    if (integer == -1) {
                        bki.setCount(this.addResource(bki));
                    }
                    else {
                        bki.setCount(this.addResource(integer, bki));
                    }
                } while (!bki.isEmpty() && bki.getCount() < integer2);
                if (bki.getCount() == integer2 && this.player.abilities.instabuild) {
                    bki.setCount(0);
                    return true;
                }
                return bki.getCount() < integer2;
            }
            else {
                if (integer == -1) {
                    integer = this.getFreeSlot();
                }
                if (integer >= 0) {
                    this.items.set(integer, bki.copy());
                    this.items.get(integer).setPopTime(5);
                    bki.setCount(0);
                    return true;
                }
                if (this.player.abilities.instabuild) {
                    bki.setCount(0);
                    return true;
                }
                return false;
            }
        }
        catch (Throwable throwable4) {
            final CrashReport j5 = CrashReport.forThrowable(throwable4, "Adding item to inventory");
            final CrashReportCategory k6 = j5.addCategory("Item being added");
            k6.setDetail("Item ID", Item.getId(bki.getItem()));
            k6.setDetail("Item data", bki.getDamageValue());
            k6.setDetail("Item name", () -> bki.getHoverName().getString());
            throw new ReportedException(j5);
        }
    }
    
    public void placeItemBackInInventory(final Level bqb, final ItemStack bki) {
        if (bqb.isClientSide) {
            return;
        }
        while (!bki.isEmpty()) {
            int integer4 = this.getSlotWithRemainingSpace(bki);
            if (integer4 == -1) {
                integer4 = this.getFreeSlot();
            }
            if (integer4 == -1) {
                this.player.drop(bki, false);
                break;
            }
            final int integer5 = bki.getMaxStackSize() - this.getItem(integer4).getCount();
            if (!this.add(integer4, bki.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> gi6 : this.compartments) {
            if (integer1 < gi6.size()) {
                list4 = gi6;
                break;
            }
            integer1 -= gi6.size();
        }
        if (list4 != null && !list4.get(integer1).isEmpty()) {
            return ContainerHelper.removeItem(list4, integer1, integer2);
        }
        return ItemStack.EMPTY;
    }
    
    public void removeItem(final ItemStack bki) {
        for (final NonNullList<ItemStack> gi4 : this.compartments) {
            for (int integer5 = 0; integer5 < gi4.size(); ++integer5) {
                if (gi4.get(integer5) == bki) {
                    gi4.set(integer5, ItemStack.EMPTY);
                    break;
                }
            }
        }
    }
    
    @Override
    public ItemStack removeItemNoUpdate(int integer) {
        NonNullList<ItemStack> gi3 = null;
        for (final NonNullList<ItemStack> gi4 : this.compartments) {
            if (integer < gi4.size()) {
                gi3 = gi4;
                break;
            }
            integer -= gi4.size();
        }
        if (gi3 != null && !gi3.get(integer).isEmpty()) {
            final ItemStack bki4 = gi3.get(integer);
            gi3.set(integer, ItemStack.EMPTY);
            return bki4;
        }
        return ItemStack.EMPTY;
    }
    
    @Override
    public void setItem(int integer, final ItemStack bki) {
        NonNullList<ItemStack> gi4 = null;
        for (final NonNullList<ItemStack> gi5 : this.compartments) {
            if (integer < gi5.size()) {
                gi4 = gi5;
                break;
            }
            integer -= gi5.size();
        }
        if (gi4 != null) {
            gi4.set(integer, bki);
        }
    }
    
    public float getDestroySpeed(final BlockState cfj) {
        return this.items.get(this.selected).getDestroySpeed(cfj);
    }
    
    public ListTag save(final ListTag lk) {
        for (int integer3 = 0; integer3 < this.items.size(); ++integer3) {
            if (!this.items.get(integer3).isEmpty()) {
                final CompoundTag le4 = new CompoundTag();
                le4.putByte("Slot", (byte)integer3);
                this.items.get(integer3).save(le4);
                ((AbstractList<CompoundTag>)lk).add(le4);
            }
        }
        for (int integer3 = 0; integer3 < this.armor.size(); ++integer3) {
            if (!this.armor.get(integer3).isEmpty()) {
                final CompoundTag le4 = new CompoundTag();
                le4.putByte("Slot", (byte)(integer3 + 100));
                this.armor.get(integer3).save(le4);
                ((AbstractList<CompoundTag>)lk).add(le4);
            }
        }
        for (int integer3 = 0; integer3 < this.offhand.size(); ++integer3) {
            if (!this.offhand.get(integer3).isEmpty()) {
                final CompoundTag le4 = new CompoundTag();
                le4.putByte("Slot", (byte)(integer3 + 150));
                this.offhand.get(integer3).save(le4);
                ((AbstractList<CompoundTag>)lk).add(le4);
            }
        }
        return lk;
    }
    
    public void load(final ListTag lk) {
        this.items.clear();
        this.armor.clear();
        this.offhand.clear();
        for (int integer3 = 0; integer3 < lk.size(); ++integer3) {
            final CompoundTag le4 = lk.getCompound(integer3);
            final int integer4 = le4.getByte("Slot") & 0xFF;
            final ItemStack bki6 = ItemStack.of(le4);
            if (!bki6.isEmpty()) {
                if (integer4 >= 0 && integer4 < this.items.size()) {
                    this.items.set(integer4, bki6);
                }
                else if (integer4 >= 100 && integer4 < this.armor.size() + 100) {
                    this.armor.set(integer4 - 100, bki6);
                }
                else if (integer4 >= 150 && integer4 < this.offhand.size() + 150) {
                    this.offhand.set(integer4 - 150, bki6);
                }
            }
        }
    }
    
    @Override
    public int getContainerSize() {
        return this.items.size() + this.armor.size() + this.offhand.size();
    }
    
    @Override
    public boolean isEmpty() {
        for (final ItemStack bki3 : this.items) {
            if (!bki3.isEmpty()) {
                return false;
            }
        }
        for (final ItemStack bki3 : this.armor) {
            if (!bki3.isEmpty()) {
                return false;
            }
        }
        for (final ItemStack bki3 : this.offhand) {
            if (!bki3.isEmpty()) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public ItemStack getItem(int integer) {
        List<ItemStack> list3 = null;
        for (final NonNullList<ItemStack> gi5 : this.compartments) {
            if (integer < gi5.size()) {
                list3 = gi5;
                break;
            }
            integer -= gi5.size();
        }
        return (list3 == null) ? ItemStack.EMPTY : list3.get(integer);
    }
    
    @Override
    public Component getName() {
        return new TranslatableComponent("container.inventory");
    }
    
    public ItemStack getArmor(final int integer) {
        return this.armor.get(integer);
    }
    
    public void hurtArmor(final DamageSource anw, float float2) {
        if (float2 <= 0.0f) {
            return;
        }
        float2 /= 4.0f;
        if (float2 < 1.0f) {
            float2 = 1.0f;
        }
        for (int integer4 = 0; integer4 < this.armor.size(); ++integer4) {
            final ItemStack bki5 = this.armor.get(integer4);
            if (!anw.isFire() || !bki5.getItem().isFireResistant()) {
                if (bki5.getItem() instanceof ArmorItem) {
                    final int integer5 = integer4;
                    bki5.<Player>hurtAndBreak((int)float2, this.player, bec -> bec.broadcastBreakEvent(EquipmentSlot.byTypeAndIndex(EquipmentSlot.Type.ARMOR, integer5)));
                }
            }
        }
    }
    
    public void dropAll() {
        for (final List<ItemStack> list3 : this.compartments) {
            for (int integer4 = 0; integer4 < list3.size(); ++integer4) {
                final ItemStack bki5 = list3.get(integer4);
                if (!bki5.isEmpty()) {
                    this.player.drop(bki5, true, false);
                    list3.set(integer4, ItemStack.EMPTY);
                }
            }
        }
    }
    
    @Override
    public void setChanged() {
        ++this.timesChanged;
    }
    
    public int getTimesChanged() {
        return this.timesChanged;
    }
    
    public void setCarried(final ItemStack bki) {
        this.carried = bki;
    }
    
    public ItemStack getCarried() {
        return this.carried;
    }
    
    @Override
    public boolean stillValid(final Player bec) {
        return !this.player.removed && bec.distanceToSqr(this.player) <= 64.0;
    }
    
    public boolean contains(final ItemStack bki) {
        for (final List<ItemStack> list4 : this.compartments) {
            for (final ItemStack bki2 : list4) {
                if (!bki2.isEmpty() && bki2.sameItem(bki)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    public boolean contains(final Tag<Item> adf) {
        for (final List<ItemStack> list4 : this.compartments) {
            for (final ItemStack bki6 : list4) {
                if (!bki6.isEmpty() && adf.contains(bki6.getItem())) {
                    return true;
                }
            }
        }
        return false;
    }
    
    public void replaceWith(final Inventory beb) {
        for (int integer3 = 0; integer3 < this.getContainerSize(); ++integer3) {
            this.setItem(integer3, beb.getItem(integer3));
        }
        this.selected = beb.selected;
    }
    
    @Override
    public void clearContent() {
        for (final List<ItemStack> list3 : this.compartments) {
            list3.clear();
        }
    }
    
    public void fillStackedContents(final StackedContents bee) {
        for (final ItemStack bki4 : this.items) {
            bee.accountSimpleStack(bki4);
        }
    }
}
