package common.item;

import java.text.DecimalFormat;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import common.attributes.Attribute;
import common.attributes.AttributeModifier;
import common.attributes.Attributes;
import common.block.Block;
import common.collect.Lists;
import common.collect.Maps;
import common.color.TextColor;
import common.enchantment.Enchantment;
import common.enchantment.EnchantmentDurability;
import common.enchantment.EnchantmentHelper;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.BlockRegistry;
import common.init.ItemRegistry;
import common.nbt.NBTBase;
import common.nbt.NBTTagCompound;
import common.nbt.NBTTagList;
import common.rng.Random;
import common.util.BlockPos;
import common.util.Facing;
import common.world.World;

import java.util.Set;

public final class ItemStack
{
    public static final int MAX_SIZE = 67108864;
    public static final DecimalFormat DECIMALFORMAT = new DecimalFormat("#.###");

    /** Size of the stack. */
    public int stackSize;

    /**
     * Number of animation frames to go when receiving an item (by walking into it, for example).
     */
//    public int animationsToGo;
    private Item item;

    /**
     * A NBTTagMap containing data about an ItemStack. Can only be used for non stackable items
     */
    private NBTTagCompound stackTagCompound;
    private int itemDamage;

    /** Item frame this stack is on, or null if not on an item frame. */
//    private EntityFrame itemFrame;
//    private Block canDestroyCacheBlock;
//    private boolean canDestroyCacheResult;
//    private Block canPlaceOnCacheBlock;
//    private boolean canPlaceOnCacheResult;

    public ItemStack(Block blockIn)
    {
        this((Block)blockIn, 1);
    }

    public ItemStack(Block blockIn, int amount)
    {
        this((Block)blockIn, amount, 0);
    }

    public ItemStack(Block blockIn, int amount, int meta)
    {
        this(ItemRegistry.getItemFromBlock(blockIn), amount, meta);
    }

    public ItemStack(Item itemIn)
    {
        this((Item)itemIn, 1);
    }

    public ItemStack(Item itemIn, int amount)
    {
        this((Item)itemIn, amount, 0);
    }

    public ItemStack(Item itemIn, int amount, int meta)
    {
//        this.canDestroyCacheBlock = null;
//        this.canDestroyCacheResult = false;
//        this.canPlaceOnCacheBlock = null;
//        this.canPlaceOnCacheResult = false;
        this.item = itemIn;
        this.stackSize = amount;
        this.itemDamage = meta;

        if (this.itemDamage < 0)
        {
            this.itemDamage = 0;
        }
    }
    
    public static String formatAmount(int amount) {
    	if(amount < 0)
    		return amount <= -1000000000 ? (amount / 1000000000) + "B" : ("-" + formatAmount(-amount));
    	if(amount < 1000)
    		return "" + amount;
    	else if(amount < 100000)
    		return (amount / 1000) + "K";
    	else if(amount < 1000000)
    		return "." + (amount / 100000) + "M";
    	else if(amount < 100000000)
    		return (amount / 1000000) + "M";
    	else if(amount < 1000000000)
    		return "." + (amount / 100000000) + "B";
    	else
    		return (amount / 1000000000) + "B+";
    }

    public static ItemStack loadItemStackFromNBT(NBTTagCompound nbt)
    {
        ItemStack itemstack = new ItemStack();
        itemstack.readFromNBT(nbt);
        return itemstack.getItem() != null ? itemstack : null;
    }

    private ItemStack()
    {
//        this.canDestroyCacheBlock = null;
//        this.canDestroyCacheResult = false;
//        this.canPlaceOnCacheBlock = null;
//        this.canPlaceOnCacheResult = false;
    }

    /**
     * Splits off a stack of the given amount of this stack and reduces this stack by the amount.
     */
    public ItemStack splitStack(int amount)
    {
        ItemStack itemstack = new ItemStack(this.item, amount, this.itemDamage);

        if (this.stackTagCompound != null)
        {
            itemstack.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
        }

        this.stackSize -= amount;
        return itemstack;
    }

    /**
     * Returns the object corresponding to the stack.
     */
    public Item getItem()
    {
        return this.item;
    }

    /**
     * Called when the player uses this ItemStack on a Block (right-click). Places blocks, etc. (Legacy name:
     * tryPlaceItemIntoWorld)
     */
    public boolean onItemUse(EntityNPC playerIn, World worldIn, BlockPos pos, Facing side, float hitX, float hitY, float hitZ)
    {
        boolean flag = this.getItem().onItemUse(this, playerIn, worldIn, pos, side, hitX, hitY, hitZ);

//        if (flag)
//        {
//            playerIn.triggerAchievement(StatRegistry.objectUseStats[ItemRegistry.getIdFromItem(this.item)]);
//        }

        return flag;
    }

    public float getStrVsBlock(Block blockIn)
    {
        return this.getItem().getStrVsBlock(this, blockIn);
    }

    /**
     * Called whenever this item stack is equipped and right clicked. Returns the new item stack to put in the position
     * where this item is. Args: world, player
     */
    public ItemStack useItemRightClick(World worldIn, EntityNPC playerIn)
    {
        return this.getItem().onItemRightClick(this, worldIn, playerIn);
    }

    /**
     * Called when the item in use count reach 0, e.g. item food eaten. Return the new ItemStack. Args : world, entity
     */
    public ItemStack onItemUseFinish(World worldIn, EntityNPC playerIn)
    {
        return this.getItem().onItemUseFinish(this, worldIn, playerIn);
    }

    /**
     * Write the stack fields to a NBT object. Return the new NBT object.
     */
    public NBTTagCompound writeToNBT(NBTTagCompound nbt)
    {
    	String resourcelocation = ItemRegistry.REGISTRY.getNameForObject(this.item);
        nbt.setString("id", resourcelocation == null ? "air" : resourcelocation.toString());
        nbt.setInteger("Count", this.stackSize);
        nbt.setShort("Damage", (short)this.itemDamage);

        if (this.stackTagCompound != null)
        {
            nbt.setTag("tag", this.stackTagCompound);
        }

        return nbt;
    }

    /**
     * Read the stack fields from a NBT object.
     */
    public void readFromNBT(NBTTagCompound nbt)
    {
        if (nbt.hasKey("id", 8))
        {
            this.item = ItemRegistry.getRegisteredItem(nbt.getString("id"));
        }
        else
        {
            this.item = ItemRegistry.getItemById(nbt.getShort("id"));
        }

        this.stackSize = nbt.getInteger("Count");
        this.itemDamage = nbt.getShort("Damage");

        if (this.itemDamage < 0)
        {
            this.itemDamage = 0;
        }

        if (nbt.hasKey("tag", 10))
        {
            this.stackTagCompound = nbt.getCompoundTag("tag");

            if (this.item != null)
            {
                this.item.updateItemStackNBT(this.stackTagCompound);
            }
        }
    }

    /**
     * Returns maximum size of the stack.
     */
    public int getMaxStackSize()
    {
        return this.getItem().getItemStackLimit();
    }

    /**
     * Returns true if the ItemStack can hold 2 or more units of the item.
     */
    public boolean isStackable()
    {
        return this.getMaxStackSize() > 1 && (!this.isItemStackDamageable() || !this.isItemDamaged());
    }

    /**
     * true if this itemStack is damageable
     */
    public boolean isItemStackDamageable()
    {
        return this.item != null && this.item.getMaxDamage() > 0;
    }
    
//    public void setItemStackDamageable(boolean breakable)
//    {
//    	if(!breakable) {
//    		if(this.stackTagCompound == null) {
//                this.setTagCompound(new NBTTagCompound());
//            }
//    		this.stackTagCompound.setBoolean("Unbreakable", true);
//    		this.setItemDamage(0);
//    	}
//    	else {
//	    	if(this.stackTagCompound != null) {
//	    		this.stackTagCompound.removeTag("Unbreakable");
//	        	if(this.stackTagCompound.hasNoTags()) {
//	        		this.stackTagCompound = null;
//	        	}
//	        }
//    	}
//    }

    public boolean getHasSubtypes()
    {
        return this.item.getHasSubtypes();
    }

    /**
     * returns true when a damageable item is damaged
     */
    public boolean isItemDamaged()
    {
        return this.isItemStackDamageable() && this.itemDamage > 0;
    }

    public int getItemDamage()
    {
        return this.itemDamage;
    }

    public int getMetadata()
    {
        return this.itemDamage;
    }

    public void setItemDamage(int meta)
    {
        this.itemDamage = meta;

        if (this.itemDamage < 0)
        {
            this.itemDamage = 0;
        }
    }

    /**
     * Returns the max damage an item in the stack can take.
     */
    public int getMaxDamage()
    {
        return this.item.getMaxDamage();
    }

    /**
     * Attempts to damage the ItemStack with par1 amount of damage, If the ItemStack has the Unbreaking enchantment
     * there is a chance for each point of damage to be negated. Returns true if it takes more damage than
     * getMaxDamage(). Returns false otherwise or if the ItemStack can't be damaged or if all points of damage are
     * negated.
     */
    public boolean attemptDamageItem(int amount, Random rand)
    {
        if (!this.isItemStackDamageable())
        {
            return false;
        }
        else
        {
            if (amount > 0)
            {
                int i = EnchantmentHelper.getEnchantmentLevel(Enchantment.unbreaking.effectId, this);
                int j = 0;

                for (int k = 0; i > 0 && k < amount; ++k)
                {
                    if (EnchantmentDurability.negateDamage(this, i, rand))
                    {
                        ++j;
                    }
                }

                amount -= j;

                if (amount <= 0)
                {
                    return false;
                }
            }

            this.itemDamage += amount;
            return this.itemDamage > this.getMaxDamage();
        }
    }

    /**
     * Damages the item in the ItemStack
     */
    public void damageItem(int amount, EntityLiving entityIn)
    {
//        if (!(entityIn.isPlayer()) || !((EntityNPC)entityIn).creative)
//        {
        if (this.isItemStackDamageable())
        {
            if (this.attemptDamageItem(amount, entityIn.getRNG()))
            {
                entityIn.renderBrokenItemStack(this);
                --this.stackSize;

                if (entityIn.isPlayer())
                {
                    EntityNPC entityplayer = (EntityNPC)entityIn;
//                    entityplayer.triggerAchievement(StatRegistry.objectBreakStats[ItemRegistry.getIdFromItem(this.item)]);

                    if (this.stackSize == 0 && this.getItem() instanceof ItemBow)
                    {
                        entityplayer.destroyCurrentEquippedItem();
                    }
                }

                if (this.stackSize < 0)
                {
                    this.stackSize = 0;
                }

                this.itemDamage = 0;
            }
        }
//        }
    }

    /**
     * Calls the corresponding fct in di
     */
    public void hitEntity(EntityLiving entityIn, EntityNPC playerIn)
    {
        boolean flag = this.item.hitEntity(this, entityIn, playerIn);

//        if (flag)
//        {
//            playerIn.triggerAchievement(StatRegistry.objectUseStats[ItemRegistry.getIdFromItem(this.item)]);
//        }
    }

    /**
     * Called when a Block is destroyed using this ItemStack
     */
    public void onBlockDestroyed(World worldIn, Block blockIn, BlockPos pos, EntityNPC playerIn)
    {
        boolean flag = this.item.onBlockDestroyed(this, worldIn, blockIn, pos, playerIn);

//        if (flag)
//        {
//            playerIn.triggerAchievement(StatRegistry.objectUseStats[ItemRegistry.getIdFromItem(this.item)]);
//        }
    }

    /**
     * Check whether the given Block can be harvested using this ItemStack.
     */
    public boolean canHarvestBlock(Block blockIn)
    {
        return this.item.canHarvestBlock(blockIn);
    }

    public boolean interactWithEntity(EntityNPC playerIn, EntityLiving entityIn)
    {
        return this.item.itemInteractionForEntity(this, playerIn, entityIn);
    }

    /**
     * Returns a new stack with the same properties.
     */
    public ItemStack copy()
    {
        ItemStack itemstack = new ItemStack(this.item, this.stackSize, this.itemDamage);

        if (this.stackTagCompound != null)
        {
            itemstack.stackTagCompound = (NBTTagCompound)this.stackTagCompound.copy();
        }

        return itemstack;
    }

    public static boolean areItemStackTagsEqual(ItemStack stackA, ItemStack stackB)
    {
        return stackA == null && stackB == null ? true : (stackA != null && stackB != null ? (stackA.stackTagCompound == null && stackB.stackTagCompound != null ? false : stackA.stackTagCompound == null || stackA.stackTagCompound.equals(stackB.stackTagCompound)) : false);
    }

    /**
     * compares ItemStack argument1 with ItemStack argument2; returns true if both ItemStacks are equal
     */
    public static boolean areItemStacksEqual(ItemStack stackA, ItemStack stackB)
    {
        return stackA == null && stackB == null ? true : (stackA != null && stackB != null ? stackA.isItemStackEqual(stackB) : false);
    }

    /**
     * compares ItemStack argument to the instance ItemStack; returns true if both ItemStacks are equal
     */
    private boolean isItemStackEqual(ItemStack other)
    {
        return this.stackSize != other.stackSize ? false : (this.item != other.item ? false : (this.itemDamage != other.itemDamage ? false : (this.stackTagCompound == null && other.stackTagCompound != null ? false : this.stackTagCompound == null || this.stackTagCompound.equals(other.stackTagCompound))));
    }

    /**
     * Compares Item and damage value of the two stacks
     */
    public static boolean areItemsEqual(ItemStack stackA, ItemStack stackB)
    {
        return stackA == null && stackB == null ? true : (stackA != null && stackB != null ? stackA.isItemEqual(stackB) : false);
    }

    /**
     * compares ItemStack argument to the instance ItemStack; returns true if the Items contained in both ItemStacks are
     * equal
     */
    public boolean isItemEqual(ItemStack other)
    {
        return other != null && this.item == other.item && this.itemDamage == other.itemDamage;
    }

//    public String getUnlocalizedName()
//    {
//        return this.item.getUnlocalizedName(this);
//    }

    /**
     * Creates a copy of a ItemStack, a null parameters will return a null.
     */
    public static ItemStack copyItemStack(ItemStack stack)
    {
        return stack == null ? null : stack.copy();
    }

//    public String toString()
//    {
//        return this.stackSize + "x" + this.item.getUnlocalizedName() + "@" + this.itemDamage;
//    }

//    /**
//     * Called each tick as long the ItemStack in on player inventory. Used to progress the pickup animation and update
//     * maps.
//     */
//    public void updateAnimation(World worldIn, Entity entityIn, int inventorySlot, boolean isCurrentItem)
//    {
//        if (this.animationsToGo > 0)
//        {
//            --this.animationsToGo;
//        }
//
//        this.item.onUpdate(this, worldIn, entityIn, inventorySlot, isCurrentItem);
//    }
//
//    public void onCrafting(World worldIn, EntityNPC playerIn, int amount)
//    {
////        playerIn.addStat(StatRegistry.objectCraftStats[ItemRegistry.getIdFromItem(this.item)], amount);
//        this.item.onCreated(this, worldIn, playerIn);
//    }

    public boolean getIsItemStackEqual(ItemStack p_179549_1_)
    {
        return this.isItemStackEqual(p_179549_1_);
    }

    public int getMaxItemUseDuration()
    {
        return this.getItem().getMaxItemUseDuration(this);
    }

    public ItemAction getItemUseAction()
    {
        return this.getItem().getItemUseAction(this);
    }

    public ItemAction getItemPosition()
    {
        return this.getItem().getItemPosition(this);
    }

    /**
     * Called when the player releases the use item button. Args: world, entityplayer, itemInUseCount
     */
    public void onPlayerStoppedUsing(World worldIn, EntityNPC playerIn, int timeLeft)
    {
        this.getItem().onPlayerStoppedUsing(this, worldIn, playerIn, timeLeft);
    }

    /**
     * Returns true if the ItemStack has an NBTTagCompound. Currently used to store enchantments.
     */
    public boolean hasTagCompound()
    {
        return this.stackTagCompound != null;
    }

    /**
     * Returns the NBTTagCompound of the ItemStack.
     */
    public NBTTagCompound getTagCompound()
    {
        return this.stackTagCompound;
    }

    /**
     * Get an NBTTagCompound from this stack's NBT data.
     */
    public NBTTagCompound getSubCompound(String key, boolean create)
    {
        if (this.stackTagCompound != null && this.stackTagCompound.hasKey(key, 10))
        {
            return this.stackTagCompound.getCompoundTag(key);
        }
        else if (create)
        {
            NBTTagCompound nbttagcompound = new NBTTagCompound();
            this.setTagInfo(key, nbttagcompound);
            return nbttagcompound;
        }
        else
        {
            return null;
        }
    }

    public NBTTagList getEnchantmentTagList()
    {
        return this.stackTagCompound == null ? null : this.stackTagCompound.getTagList("ench", 10);
    }

    /**
     * Assigns a NBTTagCompound to the ItemStack, does not validate that only non-stackable items can have it.
     */
    public void setTagCompound(NBTTagCompound nbt)
    {
        this.stackTagCompound = nbt;
    }

    /**
     * returns the display name of the itemstack
     */
    public String getDisplayName()
    {
        String s = this.getItem().getDisplay(this);

        if (this.stackTagCompound != null && this.stackTagCompound.hasKey("Name", 8))
        {
//            NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
//
//            if (nbttagcompound.hasKey("Name", 8))
//            {
            s = this.stackTagCompound.getString("Name");
//            }
        }

        return s;
    }

    public String getColoredName() {
    	return this.getColor() + this.getDisplayName();
    }

    public String getColoredName(TextColor reset) {
    	return TextColor.DGRAY + "[" + this.getColor() + this.getDisplayName() + TextColor.DGRAY + "]" + reset;
    }

    public ItemStack setStackDisplayName(String displayName)
    {
        if (this.stackTagCompound == null)
        {
            this.stackTagCompound = new NBTTagCompound();
        }

//        if (!this.stackTagCompound.hasKey("display", 10))
//        {
//            this.stackTagCompound.setTag("display", new NBTTagCompound());
//        }

        this.stackTagCompound.setString("Name", displayName);
        return this;
    }

//    public ItemStack setStackLore(String displayLore)
//    {
//        if (this.stackTagCompound == null)
//        {
//            this.stackTagCompound = new NBTTagCompound();
//        }
//
//        if (!this.stackTagCompound.hasKey("display", 10))
//        {
//            this.stackTagCompound.setTag("display", new NBTTagCompound());
//        }
//
//        NBTTagList nbttaglist = new NBTTagList();
//        for(String s : displayLore.split("\\n")) {
//        	nbttaglist.appendTag(new NBTTagString(s));
//        }
//        this.stackTagCompound.getCompoundTag("display").setTag("Lore", nbttaglist);
//        return this;
//    }
//
//    public String getStackLore()
//    {
//        if (this.stackTagCompound == null)
//        {
//            return null;
//        }
//
//        if (!this.stackTagCompound.hasKey("display", 10))
//        {
//        	return null;
//        }
//
//        NBTTagList nbttaglist = this.stackTagCompound.getCompoundTag("display").getTagList("Lore", 8);
//        StringBuilder sb = new StringBuilder();
//        for(int z = 0; z < nbttaglist.tagCount(); z++) {
//        	if(sb.length() > 0) {
//        		sb.append("\n");
//        	}
//        	sb.append(nbttaglist.getStringTagAt(z));
//        }
//        return sb.toString();
//    }

//    public ItemStack setStackFlags(int flags)
//    {
//    	if(flags != 0) {
//	        if (this.stackTagCompound == null)
//	        {
//	            this.stackTagCompound = new NBTTagCompound();
//	        }
//	        
//            this.stackTagCompound.setInteger("HideFlags", flags);
//    	}
//    	else {
//    		if (this.stackTagCompound != null)
//            {
//                this.stackTagCompound.removeTag("HideFlags");
//                if (this.stackTagCompound.hasNoTags())
//                {
//                    this.setTagCompound((NBTTagCompound)null);
//                }
//            }
//    	}
//        return this;
//    }

    /**
     * Clear any custom name set for this ItemStack
     */
    public void clearCustomName()
    {
        if (this.stackTagCompound != null)
        {
            if (this.stackTagCompound.hasKey("Name", 8))
            {
//                NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
                this.stackTagCompound.removeTag("Name");

                if (this.stackTagCompound.hasNoTags())
                {
//                    this.stackTagCompound.removeTag("display");
//
//                    if (this.stackTagCompound.hasNoTags())
//                    {
                    this.setTagCompound(null);
//                    }
                }
            }
        }
    }
    
//    public void clearLore()
//    {
//        if (this.stackTagCompound != null)
//        {
//            if (this.stackTagCompound.hasKey("display", 10))
//            {
//                NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
//                nbttagcompound.removeTag("Lore");
//
//                if (nbttagcompound.hasNoTags())
//                {
//                    this.stackTagCompound.removeTag("display");
//
//                    if (this.stackTagCompound.hasNoTags())
//                    {
//                        this.setTagCompound((NBTTagCompound)null);
//                    }
//                }
//            }
//        }
//    }

    /**
     * Returns true if the itemstack has a display name
     */
    public boolean hasDisplayName()
    {
        return this.stackTagCompound != null && this.stackTagCompound.hasKey("Name", 8);
    }

    public List<String> getTooltip(EntityNPC playerIn)
    {
        List<String> list = Lists.<String>newArrayList();
        String s = this.getColoredName();

//        if (this.hasDisplayName())
//        {
//            s = ChatFormat.ITALIC + s;
//        }
        
        if(this.stackSize != 1)
        	s = TextColor.YELLOW + "" + this.stackSize + " " + TextColor.RESET + s;

        s = s + TextColor.RESET;

//        if (advanced)
//        {
        String s1 = "";
        
        if(this.item.getBlock() != null) {
        	Block block = this.item.getBlock();
        	int j = BlockRegistry.getIdFromBlock(block);
//            	if(j != i) {
        	s1 = s1 + String.format("#%04d%s", j, this.getHasSubtypes() ? "/" : "");
//            	}
        }

//            int i = ItemRegistry.getIdFromItem(this.item);

        if (this.getHasSubtypes())
        {
            s1 = s1 + String.format("%d", this.itemDamage);
        }
//            else
//            {
//                s = s + String.format("#%04d", i);
//            }

        if (s1.length() > 0)
        {
            s = s + " (" + s1 + ")";
        }
        
//            s = s + s1;
//        }
//        else if (!this.hasDisplayName() && this.item == Items.filled_map)
//        {
//            s = s + " #" + this.itemDamage;
//        }

        list.add(s);
//        int i1 = 0;
//
//        if (this.hasTagCompound() && this.stackTagCompound.hasKey("HideFlags", 99))
//        {
//            i1 = this.stackTagCompound.getInteger("HideFlags");
//        }

//        if ((i1 & 32) == 0)
//        {
        this.item.addInformation(this, playerIn, list);
//        }

        if (this.hasTagCompound())
        {
//            if ((i1 & 1) == 0)
//            {
            NBTTagList nbttaglist = this.getEnchantmentTagList();

            if (nbttaglist != null)
            {
                for (int j = 0; j < nbttaglist.tagCount(); ++j)
                {
                    int k = nbttaglist.getCompoundTagAt(j).getShort("id");
                    int l = nbttaglist.getCompoundTagAt(j).getShort("lvl");

                    if (Enchantment.getEnchantmentById(k) != null)
                    {
                        list.add(Enchantment.getEnchantmentById(k).getFormattedName(l));
                    }
                }
            }
//            }

//            if (this.stackTagCompound.hasKey("display", 10))
//            {
//                NBTTagCompound nbttagcompound = this.stackTagCompound.getCompoundTag("display");
//
//                if (nbttagcompound.hasKey("color", 3))
//                {
//                    if (advanced)
//                    {
//                        list.add("Color: #" + Integer.toHexString(nbttagcompound.getInteger("color")).toUpperCase());
//                    }
//                    else
//                    {
//                        list.add(ChatFormat.ITALIC + I18n.translate("item.dyed"));
//                    }
//                }
//
////                if (nbttagcompound.getTagId("Lore") == 9)
////                {
////                    NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore", 8);
////
////                    if (nbttaglist1.tagCount() > 0)
////                    {
////                        for (int j1 = 0; j1 < nbttaglist1.tagCount(); ++j1)
////                        {
////                            list.add(ChatFormat.DARK_PURPLE + "" + ChatFormat.ITALIC + nbttaglist1.getStringTagAt(j1));
////                        }
////                    }
////                }
//            }
        }

        Map<Attribute, Set<AttributeModifier>> multimap = this.getAttributeModifiers(3);

        if (!multimap.isEmpty()) // && (i1 & 2) == 0)
        {
            list.add("");

            for (Entry<Attribute, Set<AttributeModifier>> entry : multimap.entrySet())
            {
                for(AttributeModifier mod : entry.getValue()) {
	                double amt = mod.getAmount();
	
	                if (mod.getID() == Attributes.ITEM_VAL_ID)
	                {
	                    amt += (double)EnchantmentHelper.getDamageModifier(this);
	                }
	
	                double num;
	
	                if (!mod.isMultiplied())
	                {
	                    num = amt;
	                }
	                else
	                {
	                    num = amt * 100.0D;
	                }
	                
	                if(mod.isInventory() && this.stackSize != 1) {
	                	double total = num * (double)this.stackSize;
	                	if (amt > 0.0D)
		                    list.add(TextColor.BLUE + String.format("+%s" + (mod.isMultiplied() ? "%%" : "") + " %s [%dx +%s" + (mod.isMultiplied() ? "%%" : "") + "]", DECIMALFORMAT.format(total), entry.getKey().getDisplayName(), this.stackSize, DECIMALFORMAT.format(num)));
		                else if (amt < 0.0D)
		                    list.add(TextColor.RED + String.format("-%s" + (mod.isMultiplied() ? "%%" : "") + " %s [%dx -%s" + (mod.isMultiplied() ? "%%" : "") + "]", DECIMALFORMAT.format(total * -1.0), entry.getKey().getDisplayName(), this.stackSize, DECIMALFORMAT.format(num * -1.0)));
	                }
	                else {
		                if (amt > 0.0D)
		                    list.add(TextColor.BLUE + String.format("+%s" + (mod.isMultiplied() ? "%%" : "") + " %s", DECIMALFORMAT.format(num), entry.getKey().getDisplayName()));
		                else if (amt < 0.0D)
		                    list.add(TextColor.RED + String.format("-%s" + (mod.isMultiplied() ? "%%" : "") + " %s", DECIMALFORMAT.format(num * -1.0), entry.getKey().getDisplayName()));
	                }
                }
            }
        }

        if (this.hasTagCompound() && this.getTagCompound().getBoolean("Unbreakable")) // && (i1 & 4) == 0)
        {
            list.add(TextColor.BLUE + "Unzerstörbar");
        }

//        if (this.hasTagCompound() && this.stackTagCompound.hasKey("CanDestroy", 9) && (i1 & 8) == 0)
//        {
//            NBTTagList nbttaglist2 = this.stackTagCompound.getTagList("CanDestroy", 8);
//
//            if (nbttaglist2.tagCount() > 0)
//            {
//                list.add("");
//                list.add(ChatFormat.GRAY + I18n.formatKey("item.canBreak"));
//
//                for (int k1 = 0; k1 < nbttaglist2.tagCount(); ++k1)
//                {
//                    Block block = BlockRegistry.getByIdFallback(nbttaglist2.getStringTagAt(k1));
//
//                    if (block != null)
//                    {
//                        list.add(ChatFormat.DARK_GRAY + block.getLocalizedName());
//                    }
//                    else
//                    {
//                        list.add(ChatFormat.DARK_GRAY + "missingno");
//                    }
//                }
//            }
//        }
//
//        if (this.hasTagCompound() && this.stackTagCompound.hasKey("CanPlaceOn", 9) && (i1 & 16) == 0)
//        {
//            NBTTagList nbttaglist3 = this.stackTagCompound.getTagList("CanPlaceOn", 8);
//
//            if (nbttaglist3.tagCount() > 0)
//            {
//                list.add("");
//                list.add(ChatFormat.GRAY + I18n.formatKey("item.canPlace"));
//
//                for (int l1 = 0; l1 < nbttaglist3.tagCount(); ++l1)
//                {
//                    Block block1 = BlockRegistry.getByIdFallback(nbttaglist3.getStringTagAt(l1));
//
//                    if (block1 != null)
//                    {
//                        list.add(ChatFormat.DARK_GRAY + block1.getLocalizedName());
//                    }
//                    else
//                    {
//                        list.add(ChatFormat.DARK_GRAY + "missingno");
//                    }
//                }
//            }
//        }

//        if (advanced)
//        {
        if (this.isItemStackDamageable())
        {
            list.add(String.format("Haltbarkeit: %d" + (this.isItemDamaged() ? " / %d" : ""), 
            		this.isItemDamaged() ? (this.getMaxDamage() - this.getItemDamage()) : this.getMaxDamage(), this.getMaxDamage()));
        }

        list.add(TextColor.GRAY + ItemRegistry.REGISTRY.getNameForObject(this.item));

        if (this.hasTagCompound())
        {
            list.add(TextColor.GRAY + String.format("NBT-Tags: %d", this.getTagCompound().getKeySet().size()));
        }
//        }

        return list;
    }

    public boolean hasEffect()
    {
        return this.getItem().hasEffect(this);
    }

    public TextColor getColor()
    {
        return this.getItem().getColor(this);
    }

    /**
     * True if it is a tool and has no enchantments to begin with
     */
    public boolean isItemEnchantable()
    {
        return !this.getItem().isItemTool(this) ? false : !this.isItemEnchanted();
    }

    /**
     * Adds an enchantment with a desired level on the ItemStack.
     */
    public void addEnchantment(Enchantment ench, int level)
    {
        if (this.stackTagCompound == null)
        {
            this.setTagCompound(new NBTTagCompound());
        }

        if (!this.stackTagCompound.hasKey("ench", 9))
        {
            this.stackTagCompound.setTag("ench", new NBTTagList());
        }

        NBTTagList nbttaglist = this.stackTagCompound.getTagList("ench", 10);
        NBTTagCompound nbttagcompound = new NBTTagCompound();
        nbttagcompound.setShort("id", (short)ench.effectId);
        nbttagcompound.setShort("lvl", (short)(/* (byte) */ level));
        nbttaglist.appendTag(nbttagcompound);
    }

    /**
     * Removes an enchantment from the ItemStack.
     */
    public boolean removeEnchantment(Enchantment ench) {
        if(this.stackTagCompound == null) {
            return false;
        }
        if(!this.stackTagCompound.hasKey("ench", 9)) {
            return false;
        }
        NBTTagList oldEnch = this.stackTagCompound.getTagList("ench", 10);
        NBTTagList newEnch = new NBTTagList();
        boolean changed = false;
        NBTTagCompound tag;
        for(int z = 0; z < oldEnch.tagCount(); z++) {
        	tag = oldEnch.getCompoundTagAt(z);
        	if(tag.getShort("id") != ench.effectId) {
        		newEnch.appendTag(tag);
        	}
        	else {
        		changed = true;
        	}
        }
        if(!changed) {
        	return false;
        }
        if(newEnch.tagCount() == 0) {
        	this.stackTagCompound.removeTag("ench");
        	if(this.stackTagCompound.hasNoTags()) {
        		this.stackTagCompound = null;
        	}
        }
        else {
        	this.stackTagCompound.setTag("ench", newEnch);
        }
        return true;
    }

    /**
     * Removes all enchantments from the ItemStack.
     */
    public boolean clearEnchantments() {
        if(this.stackTagCompound == null) {
            return false;
        }
        if(!this.stackTagCompound.hasKey("ench", 9)) {
            return false;
        }
    	this.stackTagCompound.removeTag("ench");
    	if(this.stackTagCompound.hasNoTags()) {
    		this.stackTagCompound = null;
    	}
    	return true;
    }

    /**
     * True if the item has enchantment data
     */
    public boolean isItemEnchanted()
    {
        return this.stackTagCompound != null && this.stackTagCompound.hasKey("ench", 9);
    }

    public void setTagInfo(String key, NBTBase value)
    {
        if (this.stackTagCompound == null)
        {
            this.setTagCompound(new NBTTagCompound());
        }

        this.stackTagCompound.setTag(key, value);
    }

//    public boolean canEditBlocks()
//    {
//        return this.getItem().canItemEditBlocks();
//    }

    /**
     * Return whether this stack is on an item frame.
     */
//    public boolean isOnItemFrame()
//    {
//        return this.itemFrame != null;
//    }
//
//    /**
//     * Set the item frame this stack is on.
//     */
//    public void setItemFrame(EntityFrame frame)
//    {
//        this.itemFrame = frame;
//    }
//
//    /**
//     * Return the item frame this stack is on. Returns null if not on an item frame.
//     */
//    public EntityFrame getItemFrame()
//    {
//        return this.itemFrame;
//    }

    /**
     * Get this stack's repair cost, or 0 if no repair cost is defined.
     */
    public int getRepairCost()
    {
        return this.hasTagCompound() && this.stackTagCompound.hasKey("RepairCost", 3) ? this.stackTagCompound.getInteger("RepairCost") : 0;
    }

    /**
     * Set this stack's repair cost.
     */
    public void setRepairCost(int cost)
    {
    	if(cost == 0) {
    		if(this.stackTagCompound == null) {
                return;
            }
            if(!this.stackTagCompound.hasKey("RepairCost", 3)) {
                return;
            }
        	this.stackTagCompound.removeTag("RepairCost");
        	if(this.stackTagCompound.hasNoTags()) {
        		this.stackTagCompound = null;
        	}
            return;
    	}
    	
        if (!this.hasTagCompound())
        {
            this.stackTagCompound = new NBTTagCompound();
        }

        this.stackTagCompound.setInteger("RepairCost", cost);
    }

    public Map<Attribute, Set<AttributeModifier>> getAttributeModifiers(int type)
    {
    	Map<Attribute, Set<AttributeModifier>> multimap;

//        if ((type & 1) == 1 && this.hasTagCompound() && this.stackTagCompound.hasKey("AttributeModifiers", 9))
//        {
//            multimap = HashMultimap.<String, AttributeModifier>create();
//            NBTTagList nbttaglist = this.stackTagCompound.getTagList("AttributeModifiers", 10);
//
//            for (int i = 0; i < nbttaglist.tagCount(); ++i)
//            {
//                NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i);
//                AttributeModifier attributemodifier = Attributes.readAttributeModifierFromNBT(nbttagcompound);
//
//                if (attributemodifier != null && attributemodifier.getID() != 0L)
//                {
//                    multimap.put(nbttagcompound.getString("AttributeName"), attributemodifier);
//                }
//            }
//        }
//        else
        if((type & 1) == 1) 
        {
            multimap = this.getItem().getItemAttributeModifiers();
        }
        else {
        	multimap = Maps.newHashMap();
        }
        
        if((type & 2) == 2) {
        	multimap.putAll(this.getItem().getItemInventoryModifiers());
        }

        return multimap;
    }

    public void setItem(Item newItem)
    {
        this.item = newItem;
    }

//    public boolean canDestroy(Block blockIn)
//    {
//        if (blockIn == this.canDestroyCacheBlock)
//        {
//            return this.canDestroyCacheResult;
//        }
//        else
//        {
//            this.canDestroyCacheBlock = blockIn;
//
//            if (this.hasTagCompound() && this.stackTagCompound.hasKey("CanDestroy", 9))
//            {
//                NBTTagList nbttaglist = this.stackTagCompound.getTagList("CanDestroy", 8);
//
//                for (int i = 0; i < nbttaglist.tagCount(); ++i)
//                {
//                    Block block = BlockRegistry.getByIdFallback(nbttaglist.getStringTagAt(i));
//
//                    if (block == blockIn)
//                    {
//                        this.canDestroyCacheResult = true;
//                        return true;
//                    }
//                }
//            }
//
//            this.canDestroyCacheResult = false;
//            return false;
//        }
//    }

//    public boolean canPlaceOn(Block blockIn)
//    {
//        if (blockIn == this.canPlaceOnCacheBlock)
//        {
//            return this.canPlaceOnCacheResult;
//        }
//        else
//        {
//            this.canPlaceOnCacheBlock = blockIn;
//
//            if (this.hasTagCompound() && this.stackTagCompound.hasKey("CanPlaceOn", 9))
//            {
//                NBTTagList nbttaglist = this.stackTagCompound.getTagList("CanPlaceOn", 8);
//
//                for (int i = 0; i < nbttaglist.tagCount(); ++i)
//                {
//                    Block block = BlockRegistry.getByIdFallback(nbttaglist.getStringTagAt(i));
//
//                    if (block == blockIn)
//                    {
//                        this.canPlaceOnCacheResult = true;
//                        return true;
//                    }
//                }
//            }
//
//            this.canPlaceOnCacheResult = false;
//            return false;
//        }
//    }
    
//    public boolean validate() {
//    	return this.item != null && this.item.validate(this);
//    }
    
//    public StackID getStackId() {
//    	return new StackID(this);
//    }
}
