package common.item.tool;

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

import common.attributes.Attribute;
import common.attributes.UsageSlot;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.ToolMaterial;
import common.item.CheatTab;
import common.item.Item;
import common.item.ItemStack;
import common.model.Model;
import common.model.ModelProvider;
import common.model.Transforms;
import common.tags.TagObject;
import common.tileentity.TileEntity;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.Facing;
import common.util.Vec3;
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"};

    /**
     * Stores the armor type: 0 is helmet, 1 is plate, 2 is legs and 3 is boots
     */
    public final UsageSlot 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, UsageSlot armorType)
    {
        this.material = material;
        this.texture = texture;
        this.armorType = armorType;
//        this.renderIndex = renderIndex;
        this.damageReduceAmount = material.getDamageReduction(armorType);
        this.setMaxDamage(material.getDurability(armorType));
        this.setTab(CheatTab.COMBAT);
    }

    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().hasInt("color");
    }

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

            if (nbttagcompound != null && nbttagcompound.hasInt("color"))
            {
//                NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("display");
//
//                if (nbttagcompound1 != null && nbttagcompound1.hasInt("color"))
//                {
                return nbttagcompound.getInt("color");
//                }
            }

            return this.material.getDefaultColor();
        }
    }

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

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

                if (nbttagcompound.hasInt("color"))
                {
                    nbttagcompound.remove("color");
                    if(nbttagcompound.isEmpty())
                    	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
        {
            TagObject nbttagcompound = stack.getTagCompound();

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

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

            nbttagcompound.setInt("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.size = 0;
        }

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

    public void getModifiers(Map<Attribute, Float> map, UsageSlot slot)
    {
    	if(slot != null && slot != this.armorType)
    		return;
        if(this.material.getRadiationReduction(this.armorType) > 0.0f)
        	map.put(Attribute.RADIATION_RESISTANCE, this.material.getRadiationReduction(this.armorType));
        if(this.material.getMagicReduction(this.armorType) > 0.0f)
        	map.put(Attribute.MAGIC_RESISTANCE, this.material.getMagicReduction(this.armorType));
    }
    
    public boolean isMagnetic() {
    	return this.material.isMagnetic();
    }

    public Transforms getTransform() {
    	return this.armorType == UsageSlot.HEAD ? Transforms.OFFSET2 : (this.armorType == UsageSlot.FEET ? Transforms.OFFSET1 : 
    			super.getTransform());
    }

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

    public void addInformation(ItemStack stack, EntityNPC playerIn, List<String> tooltip) {
    	if(this.material.canBeDyed()) {
    		int color = this.material.getDefaultColor();
    		if(stack.hasTagCompound() && stack.getTagCompound().hasInt("color"))
    			color = stack.getTagCompound().getInt("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() != Items.pumpkin && stack.getItem() != Items.skull) {
		if(stack.getItem() instanceof ItemArmor) {
			switch(((ItemArmor)stack.getItem()).armorType) {
			case HEAD:
				return 4;

			case BODY:
				return 3;

			case LEGS:
				return 2;

			case FEET:
				return 1;
			}
		}

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

	public ItemStack dispenseStack(World world, TileEntity source, Vec3 position, BlockPos blockpos, Facing facing, ItemStack stack) {
        BlockPos pos = blockpos.offset(facing);
        int i = pos.getX();
        int j = pos.getY();
        int k = pos.getZ();
        BoundingBox axisalignedbb = new BoundingBox((double)i, (double)j, (double)k, (double)(i + 1), (double)(j + 1), (double)(k + 1));
        List<EntityLiving> list = world.<EntityLiving>getEntitiesWithinAABB(EntityLiving.class, axisalignedbb, new Predicate<EntityLiving>() {
			public boolean test(EntityLiving entity) {
				return entity.isEntityAlive() && entity instanceof EntityNPC && 
						entity.getItem(getArmorPosition(stack)) != null;
			}
        });

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

            --stack.size;
            return stack;
        }
        else
        {
            return super.dispenseStack(world, source, position, blockpos, facing, stack);
        }
    }
}
