@Override
  public boolean matches(
      ArrayList<ItemStack> input, ItemStack in, World world, EntityPlayer player) {
    if (in == null || !(in.getItem() instanceof ItemEtherealFamiliar))
      return false; // We call it "FamiliarAugment" Recipe for a reason..
    if (getRecipeInput() == null || !(getRecipeInput().getItem() instanceof ItemEtherealFamiliar))
      return false; // A bit late but still working..

    if ((this.research.length() > 0)
        && (!ThaumcraftApiHelper.isResearchComplete(
            player.getCommandSenderName(), this.research))) {
      return false;
    }

    FamiliarAugment.FamiliarAugmentList list = ItemEtherealFamiliar.getAugments(in);

    int level;
    if (list.contains(toAdd)) {
      level = list.getLevel(toAdd);
    } else {
      level = 0;
    }
    if (requiredPreviousLevel > level) return false; // Requires higher level to do this infusion.

    if (!toAdd.checkConditions(list, level + 1)) {
      return false; // Preconditions not met.
    }

    // Normal infusionrecipe stuff...

    ItemStack inCopy;
    ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
    for (ItemStack is : input) {
      ii.add(is.copy());
    }
    for (ItemStack comp : getComponents()) {
      boolean b = false;
      for (int a = 0; a < ii.size(); a++) {
        inCopy = ii.get(a).copy();
        if (comp.getItemDamage() == 32767) {
          inCopy.setItemDamage(32767);
        }
        if (areItemStacksEqual(inCopy, comp, true)) {
          ii.remove(a);
          b = true;
          break;
        }
      }
      if (!b) {
        return false;
      }
    }
    return true;
  }
  /**
   * Used to check if a recipe matches current crafting inventory
   *
   * @param player
   */
  public boolean matches(
      ArrayList<ItemStack> input, ItemStack central, World world, EntityPlayer player) {
    if (research.length() > 0
        && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) {
      return false;
    }

    if (!enchantment.canApply(central) || !central.getItem().isItemTool(central)) {
      return false;
    }

    Map map1 = EnchantmentHelper.getEnchantments(central);
    Iterator iterator = map1.keySet().iterator();
    while (iterator.hasNext()) {
      int j1 = ((Integer) iterator.next()).intValue();
      Enchantment ench = Enchantment.enchantmentsList[j1];
      if (j1 == enchantment.effectId
          && EnchantmentHelper.getEnchantmentLevel(j1, central) >= ench.getMaxLevel()) return false;
      if (enchantment.effectId != ench.effectId
          && (!enchantment.canApplyTogether(ench) || !ench.canApplyTogether(enchantment))) {
        return false;
      }
    }

    ItemStack i2 = null;

    ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
    for (ItemStack is : input) {
      ii.add(is.copy());
    }

    for (ItemStack comp : components) {
      boolean b = false;
      for (int a = 0; a < ii.size(); a++) {
        i2 = ii.get(a).copy();
        if (comp.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
          i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
        }
        if (areItemStacksEqual(i2, comp, true)) {
          ii.remove(a);
          b = true;
          break;
        }
      }
      if (!b) return false;
    }
    //		System.out.println(ii.size());
    return ii.size() == 0 ? true : false;
  }
  /** Used to check if a recipe matches current crafting inventory */
  public boolean matches(IInventory par1InventoryCrafting, EntityPlayer player) {
    if (key.length() > 0 && !ThaumcraftApiHelper.isResearchComplete(player.username, key)) {
      return false;
    }
    for (int var2 = 0; var2 <= 3 - this.recipeWidth; ++var2) {
      for (int var3 = 0; var3 <= 3 - this.recipeHeight; ++var3) {
        if (this.checkMatch(par1InventoryCrafting, var2, var3, true)) {
          return true;
        }

        if (this.checkMatch(par1InventoryCrafting, var2, var3, false)) {
          return true;
        }
      }
    }

    return false;
  }
  /**
   * Used to check if a recipe matches current crafting inventory
   *
   * @param player
   */
  public boolean matches(
      ArrayList<ItemStack> input, ItemStack central, World world, EntityPlayer player) {
    if (recipeInput == null) return false;

    if (research.length() > 0
        && !ThaumcraftApiHelper.isResearchComplete(player.username, research)) {
      return false;
    }

    ItemStack i2 = central.copy();
    if (recipeInput.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
      i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
    }

    if (!areItemStacksEqual(i2, recipeInput, true)) return false;

    ArrayList<ItemStack> ii = new ArrayList<ItemStack>();
    for (ItemStack is : input) {
      ii.add(is.copy());
    }

    for (ItemStack comp : components) {
      boolean b = false;
      for (int a = 0; a < ii.size(); a++) {
        i2 = ii.get(a).copy();
        if (comp.getItemDamage() == OreDictionary.WILDCARD_VALUE) {
          i2.setItemDamage(OreDictionary.WILDCARD_VALUE);
        }
        if (areItemStacksEqual(i2, comp, true)) {
          ii.remove(a);
          b = true;
          break;
        }
      }
      if (!b) return false;
    }
    //		System.out.println(ii.size());
    return ii.size() == 0 ? true : false;
  }