package common.item;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import common.attributes.Attribute;
import common.attributes.AttributeModifier;
import common.attributes.Attributes;
import common.block.BlockDispenser;
import common.collect.Sets;
import common.dispenser.BehaviorDefaultDispenseItem;
import common.dispenser.IBehaviorDispenseItem;
import common.dispenser.IBlockSource;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.DispenserRegistry;
import common.init.ToolMaterial;
import common.model.Model;
import common.model.ModelProvider;
import common.model.Transforms;
import common.nbt.NBTTagCompound;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.world.World;

public class ItemArmor extends Item
{
//    public static final String[] EMPTY_SLOT_NAMES = new String[] {"items/empty_armor_slot_helmet", "items/empty_armor_slot_chestplate", "items/empty_armor_slot_leggings", "items/empty_armor_slot_boots"};
    private static final IBehaviorDispenseItem dispenserBehavior = new BehaviorDefaultDispenseItem()
    {
        protected ItemStack dispenseStack(IBlockSource source, ItemStack stack)
        {
            BlockPos blockpos = source.getBlockPos().offset(BlockDispenser.getFacing(source.getBlockMetadata()));
            int i = blockpos.getX();
            int j = blockpos.getY();
            int k = blockpos.getZ();
            BoundingBox axisalignedbb = new BoundingBox((double)i, (double)j, (double)k, (double)(i + 1), (double)(j + 1), (double)(k + 1));
            List<EntityLiving> list = source.getWorld().<EntityLiving>getEntitiesWithinAABB(EntityLiving.class, axisalignedbb, new Predicate<EntityLiving>() {
				public boolean test(EntityLiving entity) {
					return entity.isEntityAlive() && entity instanceof EntityNPC && 
							entity.getItem(ItemArmor.getArmorPosition(stack)) != null; // || entitylivingbase.isPlayer());
				}
            });

            if (list.size() > 0)
            {
                EntityLiving entitylivingbase = (EntityLiving)list.get(0);
                int l = entitylivingbase.isPlayer() ? 1 : 0;
                int i1 = ItemArmor.getArmorPosition(stack);
                ItemStack itemstack = stack.copy();
                itemstack.stackSize = 1;
                entitylivingbase.setItem(i1 - l, itemstack);

//                if (entitylivingbase instanceof EntityLiving)
//                {
//                    ((EntityLiving)entitylivingbase).setDropChance(i1, 2.0F);
//                }

                --stack.stackSize;
                return stack;
            }
            else
            {
                return super.dispenseStack(source, stack);
            }
        }
    };

    /**
     * Stores the armor type: 0 is helmet, 1 is plate, 2 is legs and 3 is boots
     */
    public final int armorType;

    /** Holds the amount of damage that the armor reduces at full durability. */
    public final int damageReduceAmount;

    /**
     * Used on RenderPlayer to select the correspondent armor to be rendered on the player: 0 is cloth, 1 is chain, 2 is
     * iron, 3 is diamond and 4 is gold.
     */
//    public final int renderIndex;

    /** The EnumArmorMaterial used for this ItemArmor */
    private final ToolMaterial material;
    private final String texture;

    public ItemArmor(ToolMaterial material, String texture, int armorType)
    {
        this.material = material;
        this.texture = texture;
        this.armorType = armorType;
//        this.renderIndex = renderIndex;
        this.damageReduceAmount = material.getDamageReductionAmount(armorType);
        this.setMaxDamage(material.getDurability(armorType));
        this.maxStackSize = 1;
        this.setTab(CheatTab.tabCombat);
        DispenserRegistry.REGISTRY.putObject(this, dispenserBehavior);
    }

    public int getColorFromItemStack(ItemStack stack, int renderPass)
    {
        if (renderPass > 0)
        {
            return 16777215;
        }
        else
        {
            int i = this.getArmorColor(stack);

            if (i < 0)
            {
                i = 16777215;
            }

            return i;
        }
    }

    /**
     * Return the enchantability factor of the item, most of the time is based on material.
     */
    public int getItemEnchantability()
    {
        return this.material.getArmorEnchantability();
    }

    /**
     * Return the armor material for this armor item.
     */
    public ToolMaterial getArmorMaterial()
    {
        return this.material;
    }
    
    public String getArmorTexture()
    {
        return this.texture;
    }

    /**
     * Return whether the specified armor ItemStack has a color.
     */
    public boolean hasColor(ItemStack stack)
    {
        return this.material.canBeDyed() && stack.hasTagCompound() && stack.getTagCompound().hasKey("color", 3);
    }

    /**
     * Return the color for the specified armor ItemStack.
     */
    public int getArmorColor(ItemStack stack)
    {
        if (!this.material.canBeDyed())
        {
            return -1;
        }
        else
        {
            NBTTagCompound nbttagcompound = stack.getTagCompound();

            if (nbttagcompound != null && nbttagcompound.hasKey("color", 3))
            {
//                NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("display");
//
//                if (nbttagcompound1 != null && nbttagcompound1.hasKey("color", 3))
//                {
                return nbttagcompound.getInteger("color");
//                }
            }

            return this.material.getDefaultColor();
        }
    }

    /**
     * Remove the color from the specified armor ItemStack.
     */
    public void removeColor(ItemStack stack)
    {
        if (this.material.canBeDyed())
        {
            NBTTagCompound nbttagcompound = stack.getTagCompound();

            if (nbttagcompound != null)
            {
//                NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("display");

                if (nbttagcompound.hasKey("color"))
                {
                    nbttagcompound.removeTag("color");
                    if(nbttagcompound.hasNoTags())
                    	stack.setTagCompound(null);
                }
            }
        }
    }

    /**
     * Sets the color of the specified armor ItemStack
     */
    public void setColor(ItemStack stack, int color)
    {
        if (!this.material.canBeDyed())
        {
            throw new UnsupportedOperationException("Kann diese Rüstung nicht färben!");
        }
        else
        {
            NBTTagCompound nbttagcompound = stack.getTagCompound();

            if (nbttagcompound == null)
            {
                nbttagcompound = new NBTTagCompound();
                stack.setTagCompound(nbttagcompound);
            }

//            NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("display");
//
//            if (!nbttagcompound.hasKey("display", 10))
//            {
//                nbttagcompound.setTag("display", nbttagcompound1);
//            }

            nbttagcompound.setInteger("color", color);
        }
    }

    /**
     * Return whether this item is repairable in an anvil.
     */
    public boolean getIsRepairable(ItemStack toRepair, ItemStack repair)
    {
        return this.material.isRepairItem(repair.getItem()) ? true : super.getIsRepairable(toRepair, repair);
    }

    /**
     * Called whenever this item is equipped and the right mouse button is pressed. Args: itemStack, world, entityPlayer
     */
    public ItemStack onItemRightClick(ItemStack itemStackIn, World worldIn, EntityNPC playerIn)
    {
        int i = ItemArmor.getArmorPosition(itemStackIn) - 1;
        ItemStack itemstack = playerIn.getArmor(i);

        if (itemstack == null)
        {
            playerIn.setItem(i, itemStackIn.copy());
            itemStackIn.stackSize = 0;
        }

        return itemStackIn;
    }
    
//    public boolean canBeDyed() {
//    	return this.material.canBeDyed();
//    }

    public Map<Attribute, Set<AttributeModifier>> getItemAttributeModifiers()
    {
    	Map<Attribute, Set<AttributeModifier>> multimap = super.getItemAttributeModifiers();
        if(this.material.getRadiationReduction(this.armorType) > 0.0f)
        	multimap.put(Attributes.RADIATION_RESISTANCE, 
        			Sets.newHashSet(new AttributeModifier(Attributes.ITEM_VAL_ID + (long)this.armorType + 1L, "Armor modifier " + (this.armorType + 1), 
        			(double)this.material.getRadiationReduction(this.armorType), false)));
        if(this.material.getMagicReduction(this.armorType) > 0.0f)
        	multimap.put(Attributes.MAGIC_RESISTANCE, 
        			Sets.newHashSet(new AttributeModifier(Attributes.ITEM_VAL_ID + (long)this.armorType + 1L, "Armor modifier " + (this.armorType + 1), 
        			(double)this.material.getMagicReduction(this.armorType), false)));
        return multimap;
    }
    
    public boolean isMagnetic() {
    	return this.material.isMagnetic();
    }

    public Transforms getTransform() {
    	return this.armorType == 0 ? Transforms.OFFSET2 : (this.armorType == 3 ? Transforms.OFFSET1 : 
    			super.getTransform());
    }

    public Model getModel(ModelProvider provider, String name, int meta) {
    	if(this.material.canBeDyed())
    		return provider.getModel(this.getTransform(), name, name + "_overlay");
    	else
    		return super.getModel(provider, name, meta);
    }

    public void addInformation(ItemStack stack, EntityNPC playerIn, List<String> tooltip) {
    	if(this.material.canBeDyed()) {
    		int color = this.material.getDefaultColor();
    		if(stack.hasTagCompound() && stack.getTagCompound().hasKey("color", 3))
    			color = stack.getTagCompound().getInteger("color");
            tooltip.add("Farbe: #" + Integer.toHexString(color).toUpperCase());
    	}
    }
    
//    public Set<String> getValidTags() {
//    	return Sets.newHashSet("color");
//    }

	public static int getArmorPosition(ItemStack stack) {
//		if(stack.getItem() != ItemRegistry.getItemFromBlock(Blocks.pumpkin) && stack.getItem() != Items.skull) {
		if(stack.getItem() instanceof ItemArmor) {
			switch(((ItemArmor)stack.getItem()).armorType) {
			case 0:
				return 4;

			case 1:
				return 3;

			case 2:
				return 2;

			case 3:
				return 1;
			}
		}

		return 0;
//		}
//		else {
//			return 4;
//		}
	}
}
