package crazypants.enderio.machine.invpanel;
import java.util.ArrayList;
import java.util.HashMap;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
public abstract class InventoryDatabase<ItemEntry extends ItemEntryBase> {
private static final Item META_EXTRACTOR = new Item();
private static final int SIMPLE_ITEMID_BITS = 12;
private static final int SIMPLE_META_BITS = 4;
private static final int SIMPLE_MAX_ITEMID = 1 << SIMPLE_ITEMID_BITS;
private static final int SIMPLE_MAX_META = 1 << SIMPLE_META_BITS;
private static final int SIMPLE_META_MASK = SIMPLE_MAX_META - 1;
protected static final int COMPLEX_DBINDEX_START = 1 << (SIMPLE_ITEMID_BITS + SIMPLE_META_BITS);
protected final HashMap<Integer, ItemEntry> simpleRegsitry;
protected final HashMap<ItemEntry, ItemEntry> complexRegistry;
protected final ArrayList<ItemEntry> complexItems;
protected int generation;
public InventoryDatabase() {
simpleRegsitry = new HashMap<Integer, ItemEntry>();
complexRegistry = new HashMap<ItemEntry, ItemEntry>();
complexItems = new ArrayList<ItemEntry>();
}
public int getGeneration() {
return generation;
}
public ItemEntry lookupItem(ItemStack stack, ItemEntry hint, boolean create) {
if(stack == null || stack.getItem() == null) {
return null;
}
int itemID = Item.getIdFromItem(stack.getItem());
int meta = META_EXTRACTOR.getDamage(stack);
NBTTagCompound nbt = stack.stackTagCompound;
if(nbt != null && nbt.hasNoTags()) {
nbt = null;
}
if(hint != null && hint.equals(itemID, meta, nbt)) {
return hint;
}
if(nbt == null && itemID < SIMPLE_MAX_ITEMID && meta < SIMPLE_MAX_META) {
return getSimpleItem(itemID, meta, create);
} else {
return getComplexItem(itemID, meta, nbt, create);
}
}
protected abstract ItemEntry createItemEntry(int dbId, int hash, int itemID, int meta, NBTTagCompound nbt);
protected ItemEntry createItemEntry(int dbId, int itemID, int meta, NBTTagCompound nbt) {
int hash = computeComplexHash(itemID, meta, nbt);
return createItemEntry(dbId, hash, itemID, meta, nbt);
}
private ItemEntry getComplexItem(int itemID, int meta, NBTTagCompound nbt, boolean create) {
int hash = computeComplexHash(itemID, meta, nbt);
ItemEntryKey key = new ItemEntryKey(hash, itemID, meta, nbt);
ItemEntry entry = complexRegistry.get(key);
if(entry == null && create) {
if(nbt != null) {
nbt = (NBTTagCompound) nbt.copy();
}
entry = createItemEntry(COMPLEX_DBINDEX_START + complexItems.size(), hash, itemID, meta, nbt);
complexItems.add(entry);
complexRegistry.put(entry, entry);
}
return entry;
}
private static int computeComplexHash(int itemID, int meta, NBTTagCompound nbt) {
int hash = ((itemID * 257) ^ meta) * 17;
if(nbt != null) {
hash ^= nbt.hashCode();
}
return hash;
}
private ItemEntry getSimpleItem(int itemID, int meta, boolean create) {
Integer dbID = (itemID << SIMPLE_META_BITS) | meta;
ItemEntry entry = simpleRegsitry.get(dbID);
if(entry == null && create) {
entry = createItemEntry(dbID, dbID, itemID, meta, null);
simpleRegsitry.put(dbID, entry);
}
return entry;
}
protected ItemEntry getSimpleItem(int dbID) {
int itemID = dbID >> SIMPLE_META_BITS;
int meta = dbID & SIMPLE_META_MASK;
return getSimpleItem(itemID, meta, true);
}
public ItemEntry getItem(int dbID) {
if(dbID < COMPLEX_DBINDEX_START) {
return getSimpleItem(dbID);
}
int dbIndex = dbID - COMPLEX_DBINDEX_START;
if(dbIndex < complexItems.size()) {
return complexItems.get(dbIndex);
}
return null;
}
public ItemEntry getExistingItem(int dbID) {
if(dbID < COMPLEX_DBINDEX_START) {
return simpleRegsitry.get(dbID);
}
return getItem(dbID);
}
static final class ItemEntryKey {
public final int hash;
public final int itemID;
public final int meta;
public final NBTTagCompound nbt;
ItemEntryKey(int hash, int itemID, int meta, NBTTagCompound nbt) {
this.hash = hash;
this.itemID = itemID;
this.meta = meta;
this.nbt = nbt;
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof ItemEntryBase) {
final ItemEntryBase other = (ItemEntryBase) obj;
return other.equals(itemID, meta, nbt);
}
return false;
}
}
}