package crazypants.enderio.conduit.item.filter;
import crazypants.enderio.conduit.gui.GuiExternalConnection;
import crazypants.enderio.conduit.gui.item.BasicItemFilterGui;
import crazypants.enderio.conduit.gui.item.IItemFilterGui;
import crazypants.enderio.conduit.gui.item.ItemConduitFilterContainer;
import crazypants.enderio.conduit.item.IItemConduit;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.oredict.OreDictionary;
import com.enderio.core.client.gui.widget.GhostSlot;
import com.enderio.core.common.network.NetworkUtil;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import crazypants.enderio.conduit.item.NetworkedInventory;
public class ItemFilter implements IInventory, IItemFilter {
private static final boolean DEFAULT_BLACKLIST = false;
private static final boolean DEFAULT_META = true;
private static final boolean DEFAULT_MBT = true;
private static final boolean DEFAULT_ORE_DICT = false;
private static final boolean DEFAULT_STICKY = false;
boolean isBlacklist = DEFAULT_BLACKLIST;
boolean matchMeta = true;
boolean matchNBT = true;
boolean useOreDict = false;
boolean sticky = false;
FuzzyMode fuzzyMode = FuzzyMode.DISABLED;
ItemStack[] items;
final List<int[]> oreIds;
private boolean isAdvanced;
public void copyFrom(ItemFilter o) {
isBlacklist = o.isBlacklist;
matchMeta = o.matchMeta;
matchNBT = o.matchNBT;
useOreDict = o.useOreDict;
sticky = o.sticky;
fuzzyMode = o.fuzzyMode;
items = o.items;
oreIds.clear();
oreIds.addAll(o.oreIds);
isAdvanced = o.isAdvanced;
}
public ItemFilter() {
this(5, false);
}
public ItemFilter(boolean advanced) {
this(advanced ? 10 : 5, advanced);
}
private ItemFilter(int numItems, boolean isAdvanced) {
this.isAdvanced = isAdvanced;
items = new ItemStack[numItems];
oreIds = new ArrayList<int[]>(numItems);
for(int i=0;i<numItems;i++) {
oreIds.add(null);
}
}
@Override
public boolean doesFilterCaptureStack(NetworkedInventory inv, ItemStack item) {
return isSticky() && itemMatched(item);
}
@Override
public boolean doesItemPassFilter(NetworkedInventory inv, ItemStack item) {
return doesItemPassFilter(item);
}
public boolean doesItemPassFilter(ItemStack item) {
if(!isValid()) {
return true;
}
boolean matched = itemMatched(item);
return isBlacklist ? !matched : matched;
}
private boolean itemMatched(ItemStack item) {
if(item == null) {
return false;
}
boolean doFuzzy = false;
boolean fuzzyValue = false;
if(fuzzyMode != FuzzyMode.DISABLED && item.getItem().isDamageable()) {
doFuzzy = true;
fuzzyValue = fuzzyMode.compare(item);
}
boolean matched = false;
int i = 0;
for (ItemStack it : items) {
if(it != null && Item.getIdFromItem(item.getItem()) == Item.getIdFromItem(it.getItem())) {
matched = true;
boolean fuzzyOk = doFuzzy && fuzzyMode.compare(it) == fuzzyValue;
if(matchMeta && !fuzzyOk && item.getItemDamage() != it.getItemDamage()) {
matched = false;
} else if(matchNBT && !isNBTMatch(item, it)) {
matched = false;
}
}
if(!matched && useOreDict && isOreDicMatch(i, item)) {
matched = true;
}
if(matched) {
break;
}
i++;
}
return matched;
}
private boolean isOreDicMatch(int filterItemIndex, ItemStack item) {
int[] ids1 = getCachedIds(filterItemIndex);
if(ids1 == null || ids1.length == 0) {
return false;
}
int[] ids2 = OreDictionary.getOreIDs(item);
if(ids2 == null || ids2.length == 0) {
return false;
}
for(int id1 : ids1) {
for(int id2 : ids2) {
if(id1 == id2) {
return true;
}
}
}
return false;
}
private boolean isNBTMatch(ItemStack filter, ItemStack item)
{
if (filter.stackTagCompound == null && item.stackTagCompound == null) return true;
if (filter.stackTagCompound == null || item.stackTagCompound == null) return false;
if (!filter.getTagCompound().hasKey("GEN")) return filter.stackTagCompound.equals(item.stackTagCompound);
NBTTagCompound filterTag = (NBTTagCompound) filter.getTagCompound().copy();
NBTTagCompound itemTag = (NBTTagCompound) item.getTagCompound().copy();
filterTag.removeTag("GEN");
itemTag.removeTag("GEN");
return filterTag.equals(itemTag);
}
private int[] getCachedIds(int filterItemIndex) {
int[] res = oreIds.get(filterItemIndex);
if(res == null) {
ItemStack item = items[filterItemIndex];
if(item == null) {
res = new int[0];
} else {
res = OreDictionary.getOreIDs(item);
if(res == null) {
res = new int[0];
}
}
oreIds.set(filterItemIndex, res);
}
return res;
}
@Override
public boolean isValid() {
for (ItemStack item : items) {
if(item != null) {
return true;
}
}
return false;
}
public boolean isBlacklist() {
return isBlacklist;
}
public void setBlacklist(boolean isBlacklist) {
this.isBlacklist = isBlacklist;
}
public boolean isMatchMeta() {
return matchMeta;
}
public void setMatchMeta(boolean matchMeta) {
this.matchMeta = matchMeta;
}
public boolean isMatchNBT() {
return matchNBT;
}
public void setMatchNBT(boolean matchNbt) {
matchNBT = matchNbt;
}
public boolean isUseOreDict() {
return useOreDict;
}
public void setUseOreDict(boolean useOreDict) {
this.useOreDict = useOreDict;
}
@Override
public boolean isSticky() {
return sticky;
}
public void setSticky(boolean sticky) {
this.sticky = sticky;
}
public FuzzyMode getFuzzyMode() {
return fuzzyMode;
}
public void setFuzzyMode(FuzzyMode fuzzyMode) {
this.fuzzyMode = fuzzyMode;
}
@Override
public void writeToNBT(NBTTagCompound nbtRoot) {
nbtRoot.setBoolean("isBlacklist", isBlacklist);
nbtRoot.setBoolean("matchMeta", matchMeta);
nbtRoot.setBoolean("matchNBT", matchNBT);
nbtRoot.setBoolean("useOreDict", useOreDict);
nbtRoot.setBoolean("sticky", sticky);
nbtRoot.setBoolean("isAdvanced", isAdvanced);
nbtRoot.setByte("fuzzyMode", (byte) fuzzyMode.ordinal());
int i = 0;
for (ItemStack item : items) {
NBTTagCompound itemTag = new NBTTagCompound();
if(item != null) {
item.writeToNBT(itemTag);
nbtRoot.setTag("item" + i, itemTag);
}
i++;
}
}
@Override
@SideOnly(Side.CLIENT)
public IItemFilterGui getGui(GuiExternalConnection gui, IItemConduit itemConduit, boolean isInput) {
ItemConduitFilterContainer cont = new ItemConduitFilterContainer(itemConduit, gui.getDir(), isInput);
BasicItemFilterGui basicItemFilterGui = new BasicItemFilterGui(gui, cont, !isInput);
basicItemFilterGui.createFilterSlots();
return basicItemFilterGui;
}
@Override
public void readFromNBT(NBTTagCompound nbtRoot) {
isBlacklist = nbtRoot.getBoolean("isBlacklist");
matchMeta = nbtRoot.getBoolean("matchMeta");
matchNBT = nbtRoot.getBoolean("matchNBT");
useOreDict = nbtRoot.getBoolean("useOreDict");
sticky = nbtRoot.getBoolean("sticky");
isAdvanced = nbtRoot.getBoolean("isAdvanced");
fuzzyMode = FuzzyMode.values()[nbtRoot.getByte("fuzzyMode") & 255];
int numItems = isAdvanced ? 10 : 5;
items = new ItemStack[numItems];
oreIds.clear();
for(int i=0;i<numItems;i++) {
oreIds.add(null);
}
for (int i = 0; i < numItems; i++) {
NBTBase tag = nbtRoot.getTag("item" + i);
if(tag instanceof NBTTagCompound) {
items[i] = ItemStack.loadItemStackFromNBT((NBTTagCompound) tag);
} else {
items[i] = null;
}
}
}
@Override
public void writeToByteBuf(ByteBuf buf) {
NBTTagCompound root = new NBTTagCompound();
writeToNBT(root);
NetworkUtil.writeNBTTagCompound(root, buf);
}
@Override
public void readFromByteBuf(ByteBuf buf) {
NBTTagCompound tag = NetworkUtil.readNBTTagCompound(buf);
readFromNBT(tag);
}
@Override
public int getSizeInventory() {
return items.length;
}
@Override
public ItemStack getStackInSlot(int i) {
if(i < 0 || i >= items.length) {
return null;
}
return items[i];
}
@Override
public ItemStack decrStackSize(int fromSlot, int amount) {
oreIds.set(fromSlot, null);
ItemStack item = items[fromSlot];
items[fromSlot] = null;
if(item == null) {
return null;
}
item.stackSize = 0;
return item;
}
@Override
public ItemStack getStackInSlotOnClosing(int i) {
return null;
}
@Override
public void setInventorySlotContents(int i, ItemStack itemstack) {
if(itemstack != null) {
items[i] = itemstack.copy();
items[i].stackSize = 0;
} else {
items[i] = null;
}
oreIds.set(i, null);
}
@Override
public String getInventoryName() {
return "Item Filter";
}
@Override
public int getInventoryStackLimit() {
return 0;
}
@Override
public boolean hasCustomInventoryName() {
return false;
}
@Override
public void markDirty() {
}
@Override
public boolean isUseableByPlayer(EntityPlayer entityplayer) {
return true;
}
@Override
public void openInventory() {
}
@Override
public void closeInventory() {
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack) {
return true;
}
@Override
public void createGhostSlots(List<GhostSlot> slots, int xOffset, int yOffset, Runnable cb) {
int topY = yOffset;
int leftX = xOffset;
int index = 0;
int numRows = isAdvanced ? 2 : 1;
for (int row = 0; row < numRows; ++row) {
for (int col = 0; col < 5; ++col) {
int x = leftX + col * 18;
int y = topY + row * 20;
slots.add(new ItemFilterGhostSlot(index, x, y, cb));
index++;
}
}
}
@Override
public int getSlotCount() {
return getSizeInventory();
}
public boolean isAdvanced() {
return isAdvanced;
}
public boolean isDefault() {
return !isAdvanced && !isValid() && isBlacklist == DEFAULT_BLACKLIST &&
matchMeta == DEFAULT_META &&
matchNBT == DEFAULT_MBT &&
useOreDict == DEFAULT_ORE_DICT &&
sticky == DEFAULT_STICKY;
}
@Override
public String toString() {
// return "ItemFilter [isBlacklist=" + isBlacklist + ", matchMeta=" + matchMeta + ", matchNBT=" + matchNBT + ", useOreDict=" + useOreDict + ", sticky="
// + sticky + ", items=" + Arrays.toString(items) + ", oreIds=" + Arrays.toString(oreIds) + ", isAdvanced=" + isAdvanced + "]";
return "ItemFilter [isAdvanced=" + isAdvanced + ", items=" + Arrays.toString(items) + "]";
}
class ItemFilterGhostSlot extends GhostSlot {
private final int slot;
private final Runnable cb;
ItemFilterGhostSlot(int slot, int x, int y, Runnable cb) {
this.x = x;
this.y = y;
this.slot = slot;
this.cb = cb;
}
@Override
public void putStack(ItemStack stack) {
if(stack != null) {
stack = stack.copy();
stack.stackSize = 1;
}
items[slot] = stack;
cb.run();
}
@Override
public ItemStack getStack() {
return items[slot];
}
}
}