package common.item;

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

import common.attributes.Attribute;
import common.attributes.AttributeModifier;
import common.block.Block;
import common.collect.Maps;
import common.collect.Sets;
import common.color.TextColor;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.model.ItemMeshDefinition;
import common.model.Model;
import common.model.ModelProvider;
import common.model.Transforms;
import common.nbt.NBTTagCompound;
import common.rng.Random;
import common.util.BlockPos;
import common.util.ExtMath;
import common.util.Facing;
import common.util.HitPosition;
import common.util.Vec3;
import common.world.World;

public class Item
{
    protected static final Random itemRand = new Random();
    
    protected int maxStackSize = 64;
    private int maxDamage;
    protected boolean hasSubtypes;
    private Item containerItem;
    private String potionEffect;
    private String display;
    private CheatTab tabToDisplayOn;
    private TextColor color = null;

    public Item setMaxStackSize(int maxStackSize)
    {
        this.maxStackSize = maxStackSize;
        return this;
    }

    public Item setHasSubtypes(boolean hasSubtypes)
    {
        this.hasSubtypes = hasSubtypes;
        return this;
    }

    /**
     * set max damage of an Item
     */
    public Item setMaxDamage(int maxDamageIn)
    {
        this.maxDamage = maxDamageIn;
        return this;
    }
    
    public Item setDisplay(String name)
    {
        this.display = name;
        return this;
    }

    public Item setContainerItem(Item containerItem)
    {
        this.containerItem = containerItem;
        return this;
    }

    /**
     * Sets the string representing this item's effect on a potion when used as an ingredient.
     */
    public Item setPotionEffect(String potionEffect)
    {
        this.potionEffect = potionEffect;
        return this;
    }

    /**
     * returns this;
     */
    public Item setTab(CheatTab tab)
    {
        this.tabToDisplayOn = tab;
        return this;
    }

    public Item setColor(TextColor color)
    {
        this.color = color;
        return this;
    }
    


    public Block getBlock()
    {
        return null;
    }

    /**
     * Called when an ItemStack with NBT data is read to potentially that ItemStack's NBT data
     */
    public boolean updateItemStackNBT(NBTTagCompound nbt)
    {
        return false;
    }

    /**
     * Called when a Block is right-clicked with this Item
     */
    public boolean onItemUse(ItemStack stack, EntityNPC playerIn, World worldIn, BlockPos pos, Facing side, float hitX, float hitY, float hitZ)
    {
        return false;
    }
    
    public boolean onAction(ItemStack stack, EntityNPC player, World world, ItemControl control, BlockPos block) {
    	return false;
    }

    public float getStrVsBlock(ItemStack stack, Block state)
    {
        return 1.0F;
    }

    /**
     * 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)
    {
        return itemStackIn;
    }

    /**
     * Called when the player finishes using this Item (E.g. finishes eating.). Not called when the player stops using
     * the Item before the action is complete.
     */
    public ItemStack onItemUseFinish(ItemStack stack, World worldIn, EntityNPC playerIn)
    {
        return stack;
    }

    /**
     * Returns the maximum size of the stack for a specific item. *Isn't this more a Set than a Get?*
     */
    public int getItemStackLimit()
    {
        return this.maxStackSize;
    }

    /**
     * Converts the given ItemStack damage value into a metadata value to be placed in the world when this Item is
     * placed as a Block (mostly used with ItemBlocks).
     */
    public int getMetadata(int damage)
    {
        return 0;
    }

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

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

    public boolean isDamageable()
    {
        return this.maxDamage > 0 && !this.hasSubtypes;
    }

    /**
     * Current implementations of this method in child classes do not use the entry argument beside ev. They just raise
     * the damage on the stack.
     */
    public boolean hitEntity(ItemStack stack, EntityLiving target, EntityLiving attacker)
    {
        return false;
    }

    /**
     * Called when a Block is destroyed using this Item. Return true to trigger the "Use Item" statistic.
     */
    public boolean onBlockDestroyed(ItemStack stack, World worldIn, Block blockIn, BlockPos pos, EntityLiving playerIn)
    {
        return false;
    }

    /**
     * Check whether this Item can harvest the given Block
     */
    public boolean canHarvestBlock(Block blockIn)
    {
        return false;
    }

    /**
     * Returns true if the item can be used on the given entity, e.g. shears on sheep.
     */
    public boolean itemInteractionForEntity(ItemStack stack, EntityNPC playerIn, EntityLiving target)
    {
        return false;
    }
    
//    public String getUnlocalizedNameInefficiently(ItemStack stack)
//    {
//        String s = this.getUnlocalizedName(stack);
//        return s == null ? "" : s; // I18n.translate(s);
//    }

//    /**
//     * Returns the unlocalized name of this item.
//     */
//    public String getUnlocalizedName()
//    {
//        return "item." + this.unlocalizedName;
//    }
    
    public String getDisplay(ItemStack stack)
    {
        return this.display;
    }

    /**
     * If this function returns true (or the item is damageable), the ItemStack's NBT tag will be sent to the client.
     */
    public boolean getShareTag()
    {
        return true;
    }

    public Item getContainerItem()
    {
        return this.containerItem;
    }

    /**
     * True if this Item has a container item (a.k.a. crafting result)
     */
    public boolean hasContainerItem()
    {
        return this.containerItem != null;
    }

    public int getColorFromItemStack(ItemStack stack, int renderPass)
    {
        return 16777215;
    }

//    /**
//     * Called each tick as long the item is on a player inventory. Uses by maps to check if is on a player hand and
//     * update it's contents.
//     */
//    public void onUpdate(ItemStack stack, World worldIn, Entity entityIn, int itemSlot, boolean isSelected)
//    {
//    }
//
//    /**
//     * Called when item is crafted/smelted. Used only by maps so far.
//     */
//    public void onCreated(ItemStack stack, World worldIn, EntityNPC playerIn)
//    {
//    }

    /**
     * returns the action that specifies what animation to play when the items is being used
     */
    public ItemAction getItemUseAction(ItemStack stack)
    {
        return ItemAction.NONE;
    }

    public ItemAction getItemPosition(ItemStack stack)
    {
        return ItemAction.NONE;
    }

    /**
     * How long it takes to use or consume an item
     */
    public int getMaxItemUseDuration(ItemStack stack)
    {
        return 0;
    }

    /**
     * Called when the player stops using an Item (stops holding the right mouse button).
     */
    public void onPlayerStoppedUsing(ItemStack stack, World worldIn, EntityNPC playerIn, int timeLeft)
    {
    }

    public String getPotionEffect(ItemStack stack)
    {
        return this.potionEffect;
    }

    public boolean isPotionIngredient(ItemStack stack)
    {
        return this.getPotionEffect(stack) != null;
    }

    /**
     * allows items to add custom lines of information to the mouseover description
     */
    public void addInformation(ItemStack stack, EntityNPC playerIn, List<String> tooltip)
    {
    }

//    public String getItemStackDisplayName(ItemStack stack)
//    {
//        return this.getUnlocalizedName(stack);
//    }

    public boolean hasEffect(ItemStack stack)
    {
        return stack.isItemEnchanted();
    }
    
    public TextColor getColor(ItemStack stack)
    {
        return this.color != null ? this.color : (stack.isItemEnchanted() ? TextColor.NEON : TextColor.WHITE);
    }

    /**
     * Checks isDamagable and if it cannot be stacked
     */
    public boolean isItemTool(ItemStack stack)
    {
        return this.getItemStackLimit() == 1 && this.isDamageable();
    }

    protected HitPosition getMovingObjectPositionFromPlayer(World worldIn, EntityNPC playerIn, boolean useLiquids)
    {
        float f = playerIn.rotPitch;
        float f1 = playerIn.rotYaw;
        double d0 = playerIn.posX;
        double d1 = playerIn.posY + (double)playerIn.getEyeHeight();
        double d2 = playerIn.posZ;
        Vec3 vec3 = new Vec3(d0, d1, d2);
        float f2 = ExtMath.cos(-f1 * 0.017453292F - (float)Math.PI);
        float f3 = ExtMath.sin(-f1 * 0.017453292F - (float)Math.PI);
        float f4 = -ExtMath.cos(-f * 0.017453292F);
        float f5 = ExtMath.sin(-f * 0.017453292F);
        float f6 = f3 * f4;
        float f7 = f2 * f4;
        double d3 = 5.0D;
        Vec3 vec31 = vec3.addVector((double)f6 * d3, (double)f5 * d3, (double)f7 * d3);
        return worldIn.rayTraceBlocks(vec3, vec31, useLiquids, !useLiquids, false);
    }

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

    /**
     * returns a list of items with the same ID, but different meta (eg: dye returns 16 items)
     */
    public void getSubItems(Item itemIn, CheatTab tab, List<ItemStack> subItems)
    {
        subItems.add(new ItemStack(itemIn, 1, 0));
    }

    /**
     * gets the tab this item is displayed on
     */
    public CheatTab getTab()
    {
        return this.tabToDisplayOn;
    }

//    public boolean canItemEditBlocks()
//    {
//        return false;
//    }

    /**
     * Return whether this item is repairable in an anvil.
     */
    public boolean getIsRepairable(ItemStack toRepair, ItemStack repair)
    {
        return false;
    }

    public Map<Attribute, Set<AttributeModifier>> getItemAttributeModifiers()
    {
        return Maps.newHashMap();
    }

    public Map<Attribute, Set<AttributeModifier>> getItemInventoryModifiers()
    {
        return Maps.newHashMap();
    }
    
//    public boolean canBeDyed() {
//    	return false;
//    }
    
    public boolean isFragile() {
    	return false;
    }
    
//    public boolean isValidMeta(int meta) {
//    	return true; // meta == 0;
//    }
//    
//    public int getDefaultMeta() {
//    	return 0;
//    }
    
    public final Set<String> getValidTags() {
    	return Sets.newHashSet();
    }

//    private static final Set<String> VALID_TAGS = Sets.newHashSet("Name", "ench", "RepairCost");
    
    protected final boolean validateNbt(NBTTagCompound tag) {
    	return true;
    }
    
//    private final boolean isValidNbt(ItemStack stack) {
//    	if(!stack.hasTagCompound()) {
//    		return true;
//    	}
//    	NBTTagCompound tag = stack.getTagCompound();
//    	if(tag.hasNoTags()) {
//    		return false;
//    	}
//    	Set<String> keys = tag.getKeySet();
//    	int z = keys.size();
//    	boolean validate = false;
//    	if(z > 0) {
//	    	for(String v : VALID_TAGS) {
//	    		if(keys.contains(v)) {
//	    			z--;
//	    			if(z == 0) {
//	    				break;
//	    			}
//	    		}
//	    	}
//    	}
////    	if(adv && z > 0) {
//////        	for(String v : ADV_TAGS) {
////    		if(keys.contains("Unbreakable")) {
////    			z--;
//////    			if(z == 0) {
//////    				break;
//////    			}
////    		}
//////        	}
////    	}
//    	if(z > 0) {
//	    	for(String v : this.getValidTags()) {
//	    		if(keys.contains(v)) {
//	    			validate = true;
//	    			z--;
//	    			if(z == 0) {
//	    				break;
//	    			}
//	    		}
//	    	}
//    	}
//    	if(z > 0) {
//    		return false;
//    	}
////    	if(tag.hasKey("display")) {
////    		if(!tag.hasKey("display", 10)) {
////    			return false;
////    		}
////    		NBTTagCompound display = tag.getCompoundTag("display");
////    		keys = display.getKeySet();
////    		z = keys.size();
//		if(tag.hasKey("Name")) {
//			if(!tag.hasKey("Name", 8)) {
//    			return false;
//    		}
//			if(tag.getString("Name").length() > 64) {
//    			return false;
//    		}
////    			z--;
//		}
////    		if(display.hasKey("Lore")) {
////    			if(!adv) {
////    				display.removeTag("Lore");
////    				if(display.hasNoTags()) {
////    					tag.removeTag("display");
////    					if(tag.hasNoTags()) {
////    						stack.setTagCompound(null);
////    						return true;
////        				}
////    				}
////    			}
////    			else {
////	    			if(!display.hasKey("Lore", 9)) {
////	        			return false;
////	        		}
////	    			NBTTagList lore = display.getTagList("Lore", 8);
////	    			if(lore.hasNoTags()) {
////	        			return false;
////	        		}
////    			}
////    			z--;
////    		}
////    		if(display.hasKey("color")) {
////    			if(!display.hasKey("color", 3)) {
////        			return false;
////        		}
////    			if(!this.canBeDyed()) {
////    				return false;
////    			}
////    			z--;
////    		}
////    		if(z > 0) {
////        		return false;
////        	}
////    	}
//    	if(tag.hasKey("RepairCost")) {
//			if(!tag.hasKey("RepairCost", 3)) {
//    			return false;
//    		}
//			if(tag.getInteger("RepairCost") < 1) {
//    			return false;
//    		}
//		}
//		if(tag.hasKey("ench")) {
//			if(!tag.hasKey("ench", 9)) {
//    			return false;
//    		}
//			NBTTagList ench = tag.getTagList("ench", 10);
//			if(ench.hasNoTags()) {
//    			return false;
//    		}
//			if(ench.tagCount() > Enchantment.getNames().size()) {
//				return false;
//			}
//			Enchantment[] ecn = new Enchantment[ench.tagCount()];
//			for(int e = 0; e < ench.tagCount(); e++) {
//				NBTTagCompound ec = ench.getCompoundTagAt(e);
//				if(ec.getKeySet().size() != 2 || !ec.hasKey("id", 2) || !ec.hasKey("lvl", 2)) {
//					return false;
//				}
//				int id = ec.getShort("id");
//				int lvl = ec.getShort("lvl");
//				Enchantment en = Enchantment.getEnchantmentById(id);
//				if(en == null) {
//					return false;
//				}
////				if(!adv && (lvl < en.getMinLevel() || lvl > en.getMaxLevel())) {
////					return false;
////				}
////				if(!adv && !en.canApply(stack)) {
////					return false;
////				}
//				ecn[e] = en;
//			}
//			for(int e = 0; e < ecn.length; e++) {
//				for(int f = 0; f < ecn.length; f++) {
//					if(f != e && ecn[e] == ecn[f]) {
//						return false;
//					}
//				}
//			}
//		}
////		if(adv) {
////		if(tag.hasKey("Unbreakable")) {
////			if(!tag.hasKey("Unbreakable", 1)) {
////    			return false;
////    		}
////		}
////	    	if(tag.hasKey("HideFlags")) {
////				if(!tag.hasKey("HideFlags", 3)) {
////	    			return false;
////	    		}
////			}
////		}
//    	if(validate) {
//    		if(this.validateNbt(stack.getTagCompound())) {
//	    		if(tag.hasNoTags()) {
//					stack.setTagCompound(null);
//				}
//    		}
//    		else {
//    			return false;
//    		}
//    	}
//		return true;
//    }
    
//    boolean validate(ItemStack stack) {
////    	if(!bypass && this.isSpecialItem()) {
////    		return false;
////    	}
//    	boolean flag = true;
//    	if(this.isDamageable() && (stack.getItemDamage() < 0 || (stack.getItemDamage() > this.getMaxDamage()))) {
//    		stack.setItemDamage(0);
//    		flag = false;
//    	}
//    	if(stack.stackSize > stack.getMaxStackSize()) {
//    		stack.stackSize = stack.getMaxStackSize();
//    		flag = false;
//    	}
//    	else if(stack.stackSize < 1) {
//    		stack.stackSize = 1;
//    		flag = false;
//    	}
//    	if(!this.isValidNbt(stack)) {
//    		stack.setTagCompound(null);
//    		flag = false;
//    	}
//    	return flag;
//    }
    
//    public boolean canBreakBlocks() {
//        return true;
//    }
//    
//    public boolean canUseInAir() {
//        return false;
//    }
//    
//    public boolean ignoresBlocks() {
//        return false;
//    }
    
    public float getRadiation(ItemStack stack) {
    	return 0.0f;
    }
    
    public boolean isMagnetic() {
    	return false;
    }
    
    public boolean isFirstPerson() {
        return true;
    }
    
    public boolean canBeWielded() {
    	return false;
    }
    
    public String getHotbarText(EntityNPC player, ItemStack stack) {
    	return stack.getColoredName();
    }

    public Transforms getTransform() {
    	return Transforms.ITEM;
    }

    public Model getModel(ModelProvider provider, String name, int meta) {
    	return provider.getModel(this.getTransform(), name);
    }
    
    public ItemMeshDefinition getMesher() {
    	return null;
    }
    
    public void getRenderItems(Item itemIn, List<ItemStack> subItems) {
        this.getSubItems(itemIn, null, subItems);
    }
}
