content: package thebetweenlands.common.item.tools;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  
  import javax.annotation.Nullable;
  
  import net.minecraft.client.gui.GuiScreen;
  import net.minecraft.client.resources.I18n;
  import net.minecraft.client.util.ITooltipFlag;
  import net.minecraft.entity.player.EntityPlayer;
  import net.minecraft.init.SoundEvents;
  import net.minecraft.item.Item;
  import net.minecraft.item.ItemStack;
  import net.minecraft.nbt.NBTTagCompound;
  import net.minecraft.nbt.NBTTagList;
  import net.minecraft.util.EnumActionResult;
  import net.minecraft.util.EnumFacing;
  import net.minecraft.util.EnumHand;
  import net.minecraft.util.EnumParticleTypes;
  import net.minecraft.util.ResourceLocation;
  import net.minecraft.util.SoundCategory;
  import net.minecraft.util.StringUtils;
  import net.minecraft.util.math.BlockPos;
  import net.minecraft.world.World;
  import net.minecraftforge.fml.client.FMLClientHandler;
  import net.minecraftforge.fml.relauncher.Side;
  import net.minecraftforge.fml.relauncher.SideOnly;
  import thebetweenlands.api.aspect.Aspect;
  import thebetweenlands.api.aspect.DiscoveryContainer;
  import thebetweenlands.api.aspect.IAspectType;
  import thebetweenlands.api.aspect.ItemAspectContainer;
  import thebetweenlands.client.tab.BLCreativeTabs;
  import thebetweenlands.common.TheBetweenlands;
  import thebetweenlands.common.herblore.aspect.AspectManager;
  import thebetweenlands.common.herblore.elixir.ElixirRecipe;
  import thebetweenlands.common.herblore.elixir.ElixirRecipes;
  import thebetweenlands.common.item.ITintedItem;
  import thebetweenlands.common.registries.ItemRegistry;
  
  public class ItemBucketInfusion extends Item implements ITintedItem, ItemRegistry.IMultipleItemModelDefinition {
  
  	public ItemBucketInfusion() {
  		this.setCreativeTab(BLCreativeTabs.GEARS);
  		this.setMaxStackSize(1);
  		this.setHasSubtypes(true);
  		this.setMaxDamage(0);
  	}
  
  	@Override
  	@SideOnly(Side.CLIENT)
  	public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> list, ITooltipFlag flagIn) {
  		if (hasTag(stack)) {
  			if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("infused") && stack.getTagCompound().hasKey("ingredients") && stack.getTagCompound().hasKey("infusionTime")) {
  				int infusionTime = stack.getTagCompound().getInteger("infusionTime");
  				list.add(I18n.format("tooltip.bl.infusion.time", StringUtils.ticksToElapsedTime(infusionTime), infusionTime));
  				list.add(I18n.format("tooltip.bl.infusion.ingredients"));
  				// The properties will be retrieved in the Alembic's TE logic
  				NBTTagList nbtList = (NBTTagList) stack.getTagCompound().getTag("ingredients");
  				Map<ItemStack, Integer> stackMap = new LinkedHashMap<ItemStack, Integer>();
  				for (int i = 0; i < nbtList.tagCount(); i++) {
  					ItemStack ingredient = new ItemStack(nbtList.getCompoundTagAt(i));
  					boolean contained = false;
  					for (Map.Entry<ItemStack, Integer> stackCount : stackMap.entrySet()) {
  						if (ItemStack.areItemStacksEqual(stackCount.getKey(), ingredient)) {
  							stackMap.put(stackCount.getKey(), stackCount.getValue() + 1);
  							contained = true;
  						}
  					}
  					if (!contained) {
  						stackMap.put(ingredient, 1);
  					}
  				}
  				for (Map.Entry<ItemStack, Integer> stackCount : stackMap.entrySet()) {
  					ItemStack ingredient = stackCount.getKey();
  					int count = stackCount.getValue();
  					if (!ingredient.isEmpty()) {
  						list.add((count > 1 ? (count + "x ") : "") + ingredient.getDisplayName());
  						ItemAspectContainer container = ItemAspectContainer.fromItem(ingredient, AspectManager.get(TheBetweenlands.proxy.getClientWorld()));
  						List<Aspect> ingredientAspects = container.getAspects(DiscoveryContainer.getMergedDiscoveryContainer(FMLClientHandler.instance().getClientPlayerEntity()));
  						if (ingredientAspects.size() >= 1) {
  							if (GuiScreen.isShiftKeyDown()) {
  								for (Aspect aspect : ingredientAspects) {
  									list.add("  - " + aspect.type.getName() + " (" + Aspect.ASPECT_AMOUNT_FORMAT.format(aspect.getDisplayAmount() * count) + ")");
  								}
  							}
  						}
  					}
  				}
  			} else {
  				list.add(I18n.format("tooltip.bl.infusion.empty"));
  			}
  		}
  	}
  
  	@Override
  	public EnumActionResult onItemUseFirst(EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ, EnumHand hand) {
  		if(player.isSneaking()) {
  			pos = pos.offset(side);
  			world.playSound(player, pos, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 1.0F, itemRand.nextFloat() * 0.4F + 0.8F);
  			for(int i = 0; i < 50; i++) {
  				world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, pos.getX() + world.rand.nextFloat(), pos.getY() + world.rand.nextFloat(), pos.getZ() + world.rand.nextFloat(), 0, 0, 0);
  			}
  			player.setHeldItem(hand, getEmptyBucket(player.getHeldItem(hand)));
  			return EnumActionResult.SUCCESS;
  		}
  		return super.onItemUseFirst(player, world, pos, side, hitX, hitY, hitZ, hand);
  	}
  
  	@Override
  	public void onCreated(ItemStack stack, World world, EntityPlayer player) {
  		stack.setTagCompound(new NBTTagCompound());
  	}
  
  	private boolean hasTag(ItemStack stack) {
  		if (!stack.hasTagCompound()) {
  			stack.setTagCompound(new NBTTagCompound());
  			return false;
  		}
  		return true;
  	}
  
  	public ElixirRecipe getInfusionElixirRecipe(ItemStack stack) {
  		return ElixirRecipes.getFromAspects(this.getInfusingAspects(stack));
  	}
  
  	public List<IAspectType> getInfusingAspects(ItemStack stack) {
  		List<IAspectType> infusingAspects = new ArrayList<IAspectType>();
  		if (hasTag(stack)) {
  			if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("infused") && stack.getTagCompound().hasKey("ingredients") && stack.getTagCompound().hasKey("infusionTime")) {
  				NBTTagList nbtList = (NBTTagList) stack.getTagCompound().getTag("ingredients");
  				for (int i = 0; i < nbtList.tagCount(); i++) {
  					ItemStack ingredient = new ItemStack(nbtList.getCompoundTagAt(i));
  					ItemAspectContainer container = ItemAspectContainer.fromItem(ingredient, AspectManager.get(TheBetweenlands.proxy.getClientWorld()));
  					for (Aspect aspect : container.getAspects()) {
  						infusingAspects.add(aspect.type);
  					}
  					//infusingAspects.addAll(AspectManager.get(TheBetweenlands.proxy.getClientWorld()).getDiscoveredAspectTypes(AspectManager.getAspectItem(ingredient), null));
  				}
  			}
  		}
  		return infusingAspects;
  	}
  
  	public int getInfusionTime(ItemStack stack) {
  		if (hasTag(stack)) {
  			if (stack.getTagCompound() != null && stack.getTagCompound().hasKey("infused") && stack.getTagCompound().hasKey("ingredients") && stack.getTagCompound().hasKey("infusionTime")) {
  				return stack.getTagCompound().getInteger("infusionTime");
  			}
  		}
  		return 0;
  	}
  
  	@Override
  	public int getColorMultiplier(ItemStack stack, int tintIndex) {
  		if(tintIndex == 1) {
  			ElixirRecipe recipe = this.getInfusionElixirRecipe(stack);
  			int infusionTime = this.getInfusionTime(stack);
  			//Infusion liquid
  			if(recipe != null) {
  				if(infusionTime > recipe.idealInfusionTime + recipe.infusionTimeVariation) {
  					float[] failedColor = recipe.getRGBA(recipe.infusionFailedColor);
  					return this.getColorFromRGBA(failedColor[0], failedColor[1], failedColor[2], failedColor[3]);
  				} else if(infusionTime > recipe.idealInfusionTime - recipe.infusionTimeVariation
  						&& infusionTime < recipe.idealInfusionTime + recipe.infusionTimeVariation) {
  					float[] finishedColor = recipe.getRGBA(recipe.infusionFinishedColor);
  					return this.getColorFromRGBA(finishedColor[0], finishedColor[1], finishedColor[2], finishedColor[3]);
  				} else {
  					float startR = 0.2F;
  					float startG = 0.6F;
  					float startB = 0.4F;
  					float startA = 0.9F;
  					float[] targetColor = recipe.getRGBA(recipe.infusionGradient);
  					int targetTime = recipe.idealInfusionTime - recipe.infusionTimeVariation;
  					float infusingPercentage = (float)infusionTime / (float)targetTime;
  					float interpR = startR + (targetColor[0] - startR) * infusingPercentage;
  					float interpG = startG + (targetColor[1] - startG) * infusingPercentage;
  					float interpB = startB + (targetColor[2] - startB) * infusingPercentage;
  					float interpA = startA + (targetColor[3] - startA) * infusingPercentage;
  					return this.getColorFromRGBA(interpR, interpG, interpB, interpA);
  				}
  			} else {
  				return this.getColorFromRGBA(0.8F, 0.0F, 0.8F, 1.0F);
  			}
  		}
  		return 0xFFFFFFFF;
  	}
  
  	private int getColorFromRGBA(float r, float g, float b, float a) {
  		return ((int) (a * 255.0F) << 24) | ((int) (r * 255.0F) << 16) | ((int) (g * 255.0F) << 8) | ((int) (b * 255.0F));
  	}
  
  	@Override
  	public String getTranslationKey(ItemStack stack) {
  		try {
  			switch (stack.getItemDamage()) {
  			case 0:
  				return "item.thebetweenlands.bl_bucket_infusion.weedwood";
  			case 1:
  				return "item.thebetweenlands.bl_bucket_infusion.syrmorite";
  			}
  		} catch (Exception e) {
  		}
  		return "item.thebetweenlands.unknown";
  	}
  
  	@Override
  	public Map<Integer, ResourceLocation> getModels() {
  		Map<Integer, ResourceLocation> models = new HashMap<>();
  		models.put(0, new ResourceLocation(getRegistryName().toString() + "_weedwood"));
  		models.put(1, new ResourceLocation(getRegistryName().toString() + "_syrmorite"));
  		return models;
  	}
  
  	@Override
  	public ItemStack getContainerItem(ItemStack itemStack) {
  		return getEmptyBucket(itemStack);
  	}
  	
  	public static ItemStack getEmptyBucket(ItemStack stack) {
  		return ItemRegistry.BL_BUCKET.getEmpty(new ItemStack(ItemRegistry.BL_BUCKET, 1, stack.getMetadata()));
  	}
  }
  