package com.raoulvdberge.refinedstorage.apiimpl.util;

import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.block.BlockNode;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.commons.lang3.ArrayUtils;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;

public class Comparer implements IComparer {
    private Map<Integer, Boolean> oredictCache = new HashMap<>();

    @Override
    public boolean isEqual(@Nullable ItemStack left, @Nullable ItemStack right, int flags) {
        EnumActionResult validity = validityCheck(left, right);

        if (validity == EnumActionResult.FAIL || validity == EnumActionResult.SUCCESS) {
            return validity == EnumActionResult.SUCCESS;
        }

        if ((flags & COMPARE_OREDICT) == COMPARE_OREDICT) {
            if (isEqualOredict(left, right)) {
                return true;
            }
        }

        if (left.getItem() != right.getItem()) {
            return false;
        }

        if ((flags & COMPARE_DAMAGE) == COMPARE_DAMAGE && left.getItemDamage() != OreDictionary.WILDCARD_VALUE && right.getItemDamage() != OreDictionary.WILDCARD_VALUE) {
            if (left.getItemDamage() != right.getItemDamage()) {
                return false;
            }
        }

        if ((flags & COMPARE_NBT) == COMPARE_NBT) {
            if ((flags & COMPARE_STRIP_NBT) == COMPARE_STRIP_NBT) {
                left = stripTags(left.copy());
                right = stripTags(right.copy());
            }
            if (!isEqualNBT(left, right)) {
                return false;
            }
        }

        if ((flags & COMPARE_QUANTITY) == COMPARE_QUANTITY) {
            if (left.getCount() != right.getCount()) {
                return false;
            }
        }

        return true;
    }

    @Override
    public boolean isEqual(@Nullable FluidStack left, @Nullable FluidStack right, int flags) {
        if (left == null && right == null) {
            return true;
        }

        if ((left == null && right != null) || (left != null && right == null)) {
            return false;
        }

        if (left.getFluid() != right.getFluid()) {
            return false;
        }

        if ((flags & COMPARE_QUANTITY) == COMPARE_QUANTITY) {
            if (left.amount != right.amount) {
                return false;
            }
        }

        if ((flags & COMPARE_NBT) == COMPARE_NBT) {
            if (left.tag != null && !left.tag.equals(right.tag)) {
                return false;
            }
        }

        return true;
    }

    @Override
    public boolean isEqualNBT(@Nullable ItemStack left, @Nullable ItemStack right) {
        EnumActionResult validity = validityCheck(left, right);

        if (validity == EnumActionResult.FAIL || validity == EnumActionResult.SUCCESS) {
            return validity == EnumActionResult.SUCCESS;
        }

        if (!ItemStack.areItemStackTagsEqual(left, right)) {
            if (left.hasTagCompound() && !right.hasTagCompound() && left.getTagCompound().hasNoTags()) {
                return true;
            } else if (!left.hasTagCompound() && right.hasTagCompound() && right.getTagCompound().hasNoTags()) {
                return true;
            }

            return false;
        }

        return true;
    }

    @Override
    public boolean isEqualOredict(@Nullable ItemStack left, @Nullable ItemStack right) {
        EnumActionResult validity = validityCheck(left, right);

        if (validity == EnumActionResult.FAIL || validity == EnumActionResult.SUCCESS) {
            return validity == EnumActionResult.SUCCESS;
        }

        int code = API.instance().getItemStackHashCode(left);
        code = 31 * code + API.instance().getItemStackHashCode(right);

        if (oredictCache.containsKey(code)) {
            return oredictCache.get(code);
        }

        int[] leftIds = OreDictionary.getOreIDs(left);
        int[] rightIds = OreDictionary.getOreIDs(right);

        for (int i : rightIds) {
            if (ArrayUtils.contains(leftIds, i)) {
                oredictCache.put(code, true);

                return true;
            }
        }

        oredictCache.put(code, false);

        return false;
    }

    private EnumActionResult validityCheck(@Nullable ItemStack left, @Nullable ItemStack right) {
        if (left == null && right == null) {
            return EnumActionResult.SUCCESS;
        }

        if ((left == null && right != null) || (left != null && right == null)) {
            return EnumActionResult.FAIL;
        }

        boolean leftEmpty = left.isEmpty();
        boolean rightEmpty = right.isEmpty();

        if (leftEmpty && rightEmpty) {
            return EnumActionResult.SUCCESS;
        }

        if ((leftEmpty && !rightEmpty) || (!rightEmpty) && rightEmpty) {
            return EnumActionResult.FAIL;
        }

        return EnumActionResult.PASS;
    }

    public static ItemStack stripTags(ItemStack stack) {
        if (stack != null && stack.hasTagCompound()) {
            switch (stack.getItem().getRegistryName().getResourceDomain()) {
                case "mekanism":
                case "mekanismgenerators":
                case "mekanismtools":
                    stack.getTagCompound().removeTag("mekData");
                    break;
                case "enderio":
                    // Soul vials
                    stack.getTagCompound().removeTag("entity");
                    stack.getTagCompound().removeTag("isStub");
                    // Capacitors
                    stack.getTagCompound().removeTag("Energy");
                    // Painted
                    stack.getTagCompound().removeTag("paintSource__null");
                    stack.getTagCompound().removeTag("paintSource");
                    // Sided config
                    stack.getTagCompound().removeTag("faceModes__null");
                    stack.getTagCompound().removeTag("faceModes");
                    // Tank
                    stack.getTagCompound().removeTag("tank");
                    stack.getTagCompound().removeTag("voidMode");
                    stack.getTagCompound().removeTag("inventory");
                    // Name
                    stack.getTagCompound().removeTag("display");
                    stack.getTagCompound().removeTag("eio.abstractMachine");
                    break;
                case "simplyjetpacks":
                    stack.getTagCompound().removeTag("sjData");
                    stack.getTagCompound().removeTag("PackOn");
                    break;
                case "refinedstorage":
                    stack.getTagCompound().removeTag(BlockNode.NBT_REFINED_STORAGE_DATA);
                    break;
                case "immersiveengineering":
                    stack.getTagCompound().removeTag("hammerDmg");
                    stack.getTagCompound().removeTag("cutterDmg");
                    break;
                case "storagedrawers":
                    stack.getTagCompound().removeTag("material");
                    break;
                case "fluxnetworks":
                    stack.getTagCompound().removeTag("dropped");
                    stack.getTagCompound().removeTag("energy");
                    break;
                case "minecraft":
                    stack.getTagCompound().removeTag("RepairCost");
                    break;
            }
        }

        return stack;
    }
}

@@ -5017,27 +5017,25 @@
 y) %7C%7C (!
-righ
+lef
 tEmpty
-)
  && righ
@@ -5033,32 +5033,33 @@
 y && rightEmpty)
+)
  %7B%0A            r

fix flags in validityCheck