package org.squiddev.plethora.integration.vanilla.meta;

import com.google.common.collect.Maps;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.output.NullOutputStream;
import org.squiddev.plethora.api.meta.BasicMetaProvider;
import org.squiddev.plethora.api.meta.IMetaProvider;
import org.squiddev.plethora.utils.DebugLogger;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

/**
 * Adds basic properties for item stacks.
 */
@IMetaProvider.Inject(ItemStack.class)
public class MetaItemBasic extends BasicMetaProvider<ItemStack> {
	@Nonnull
	@Override
	public Map<Object, Object> getMeta(@Nonnull ItemStack stack) {
		HashMap<Object, Object> data = getBasicProperties(stack);

		String display = stack.getDisplayName();
		data.put("displayName", display == null || display.length() == 0 ? stack.getUnlocalizedName() : display);
		data.put("rawName", stack.getUnlocalizedName());

		data.put("maxCount", stack.getMaxStackSize());
		data.put("maxDamage", stack.getMaxDamage());

		if (stack.getItem().showDurabilityBar(stack)) {
			data.put("durability", stack.getItem().getDurabilityForDisplay(stack));
		}

		// tabToDisplayOn
		CreativeTabs tab = ObfuscationReflectionHelper.getPrivateValue(Item.class, stack.getItem(), "field_77701_a");
		if (tab != null) {
			// tabLabel
			data.put("creativeTab", ObfuscationReflectionHelper.getPrivateValue(CreativeTabs.class, tab, "field_78034_o"));
		}

		return data;
	}

	@Nonnull
	public static HashMap<Object, Object> getBasicProperties(@Nonnull ItemStack stack) {
		HashMap<Object, Object> data = Maps.newHashMap();

		data.put("name", stack.getItem().getRegistryName());
		data.put("damage", stack.getItemDamage());
		data.put("count", stack.stackSize);
		data.put("nbtHash", getNBTHash(stack));

		return data;
	}

	@Nullable
	private static String getNBTHash(@Nonnull ItemStack stack) {
		if (!stack.hasTagCompound() || stack.getTagCompound().hasNoTags()) return null;

		NBTTagCompound tag = stack.getTagCompound();
		try {
			MessageDigest digest = MessageDigest.getInstance("MD5");
			OutputStream dump = new NullOutputStream();
			DigestOutputStream hasher = new DigestOutputStream(dump, digest);
			DataOutput output = new DataOutputStream(hasher);
			CompressedStreamTools.write(tag, output);
			byte[] hash = digest.digest();
			return new String(Hex.encodeHex(hash));
		} catch (NoSuchAlgorithmException e) {
			DebugLogger.error("Cannot hash NBT", e);
			return null;
		} catch (IOException e) {
			DebugLogger.error("Cannot hash NBT", e);
			return null;
		}
	}
}

package org.squiddev.plethora.integration.vanilla.meta;

import com.google.common.collect.Maps;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.output.NullOutputStream;
import org.squiddev.plethora.api.meta.BasicMetaProvider;
import org.squiddev.plethora.api.meta.IMetaProvider;
import org.squiddev.plethora.utils.DebugLogger;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

/**
 * Adds basic properties for item stacks.
 */
@IMetaProvider.Inject(ItemStack.class)
public class MetaItemBasic extends BasicMetaProvider<ItemStack> {
	@Nonnull
	@Override
	public Map<Object, Object> getMeta(@Nonnull ItemStack stack) {
		HashMap<Object, Object> data = getBasicProperties(stack);

		String display = stack.getDisplayName();
		data.put("displayName", display == null || display.length() == 0 ? stack.getUnlocalizedName() : display);
		data.put("rawName", stack.getUnlocalizedName());

		data.put("maxCount", stack.getMaxStackSize());
		data.put("maxDamage", stack.getMaxDamage());

		if (stack.getItem().showDurabilityBar(stack)) {
			data.put("durability", stack.getItem().getDurabilityForDisplay(stack));
		}

		return data;
	}

	@Nonnull
	public static HashMap<Object, Object> getBasicProperties(@Nonnull ItemStack stack) {
		HashMap<Object, Object> data = Maps.newHashMap();

		data.put("name", stack.getItem().getRegistryName());
		data.put("damage", stack.getItemDamage());
		data.put("count", stack.stackSize);
		data.put("nbtHash", getNBTHash(stack));

		return data;
	}

	@Nullable
	private static String getNBTHash(@Nonnull ItemStack stack) {
		if (!stack.hasTagCompound() || stack.getTagCompound().hasNoTags()) return null;

		NBTTagCompound tag = stack.getTagCompound();
		try {
			MessageDigest digest = MessageDigest.getInstance("MD5");
			OutputStream dump = new NullOutputStream();
			DigestOutputStream hasher = new DigestOutputStream(dump, digest);
			DataOutput output = new DataOutputStream(hasher);
			CompressedStreamTools.write(tag, output);
			byte[] hash = digest.digest();
			return new String(Hex.encodeHex(hash));
		} catch (NoSuchAlgorithmException e) {
			DebugLogger.error("Cannot hash NBT", e);
			return null;
		} catch (IOException e) {
			DebugLogger.error("Cannot hash NBT", e);
			return null;
		}
	}
}

Revert "Add creative tab to item metadata"