/**
   * An Item Object consists of data about a particular item stack. Information included is: type,
   * data, qty, and an array of enchantment objects (labeled enchants): etype (enchantment type) and
   * elevel (enchantment level). For backwards compatibility, this information is also listed in
   * numerical slots as well as associative slots. If the MCItemStack is null, or the underlying
   * item is nonexistant (or air) CNull is returned.
   *
   * @param is
   * @return
   */
  public Construct item(MCItemStack is, Target t) {
    if (is == null || is.getAmount() == 0) {
      return new CNull(t);
    }
    int type = is.getTypeId();

    int data;
    if (type < 256) {
      // Use the data
      data = (is.getData() != null ? is.getData().getData() : 0);
    } else {
      // Use the durability
      data = is.getDurability();
    }
    int qty = is.getAmount();
    CArray enchants = new CArray(t);
    for (Map.Entry<MCEnchantment, Integer> entry : is.getEnchantments().entrySet()) {
      CArray enchObj = CArray.GetAssociativeArray(t);
      enchObj.set("etype", new CString(entry.getKey().getName(), t), t);
      enchObj.set("elevel", new CInt(entry.getValue(), t), t);
      enchants.push(enchObj);
    }
    Construct meta = itemMeta(is, t);
    CArray ret = CArray.GetAssociativeArray(t);
    ret.set("type", Integer.toString(type));
    ret.set("data", Integer.toString(data));
    ret.set("qty", Integer.toString(qty));
    ret.set("enchants", enchants, t);
    ret.set("meta", meta, t);
    return ret;
  }
 public Construct itemMeta(MCItemStack is, Target t) {
   Construct ret, display, lore, color, title, author, pages, owner, stored;
   if (!is.hasItemMeta()) {
     ret = new CNull(t);
   } else {
     ret = CArray.GetAssociativeArray(t);
     MCItemMeta meta = is.getItemMeta();
     if (meta.hasDisplayName()) {
       display = new CString(meta.getDisplayName(), t);
     } else {
       display = new CNull(t);
     }
     if (meta.hasLore()) {
       lore = new CArray(t);
       for (String l : meta.getLore()) {
         ((CArray) lore).push(new CString(l, t));
       }
     } else {
       lore = new CNull(t);
     }
     ((CArray) ret).set("display", display, t);
     ((CArray) ret).set("lore", lore, t);
     if (meta instanceof MCLeatherArmorMeta) {
       color = color(((MCLeatherArmorMeta) meta).getColor(), t);
       ((CArray) ret).set("color", color, t);
     }
     if (meta instanceof MCBookMeta) {
       if (((MCBookMeta) meta).hasTitle()) {
         title = new CString(((MCBookMeta) meta).getTitle(), t);
       } else {
         title = new CNull(t);
       }
       if (((MCBookMeta) meta).hasAuthor()) {
         author = new CString(((MCBookMeta) meta).getAuthor(), t);
       } else {
         author = new CNull(t);
       }
       if (((MCBookMeta) meta).hasPages()) {
         pages = new CArray(t);
         for (String p : ((MCBookMeta) meta).getPages()) {
           ((CArray) pages).push(new CString(p, t));
         }
       } else {
         pages = new CNull(t);
       }
       ((CArray) ret).set("title", title, t);
       ((CArray) ret).set("author", author, t);
       ((CArray) ret).set("pages", pages, t);
     }
     if (meta instanceof MCSkullMeta) {
       if (((MCSkullMeta) meta).hasOwner()) {
         owner = new CString(((MCSkullMeta) meta).getOwner(), t);
       } else {
         owner = new CNull(t);
       }
       ((CArray) ret).set("owner", owner, t);
     }
     if (meta instanceof MCEnchantmentStorageMeta) {
       if (((MCEnchantmentStorageMeta) meta).hasStoredEnchants()) {
         stored = new CArray(t);
         for (Map.Entry<MCEnchantment, Integer> entry :
             ((MCEnchantmentStorageMeta) meta).getStoredEnchants().entrySet()) {
           CArray eObj = CArray.GetAssociativeArray(t);
           eObj.set("etype", new CString(entry.getKey().getName(), t), t);
           eObj.set("elevel", new CInt(entry.getValue(), t), t);
           ((CArray) stored).push(eObj);
         }
       } else {
         stored = new CNull(t);
       }
       ((CArray) ret).set("stored", stored, t);
     }
   }
   return ret;
 }
  /**
   * Gets an MCItemStack from a given item "object". Supports both the old and new formats currently
   *
   * @param i
   * @param line_num
   * @param f
   * @return
   */
  public MCItemStack item(Construct i, Target t) {
    if (i instanceof CNull) {
      return EmptyItem();
    }
    if (!(i instanceof CArray)) {
      throw new ConfigRuntimeException("Expected an array!", ExceptionType.FormatException, t);
    }
    CArray item = (CArray) i;
    int type = 0;
    int data = 0;
    int qty = 1;
    Map<MCEnchantment, Integer> enchants = new HashMap<MCEnchantment, Integer>();
    MCItemMeta meta = null;

    if (item.containsKey("type")) {
      try {
        if (item.get("type").val().contains(":")) {
          // We're using the combo addressing method
          String[] split = item.get("type").val().split(":");
          item.set("type", split[0]);
          item.set("data", split[1]);
        }
        type = Integer.parseInt(item.get("type").val());
      } catch (NumberFormatException e) {
        throw new ConfigRuntimeException(
            "Could not get item information from given information ("
                + item.get("type").val()
                + ")",
            ExceptionType.FormatException,
            t,
            e);
      }
    } else {
      throw new ConfigRuntimeException(
          "Could not find item type!", ExceptionType.FormatException, t);
    }
    if (item.containsKey("data")) {
      try {
        data = Integer.parseInt(item.get("data").val());
      } catch (NumberFormatException e) {
        throw new ConfigRuntimeException(
            "Could not get item data from given information (" + item.get("data").val() + ")",
            ExceptionType.FormatException,
            t,
            e);
      }
    }
    if (item.containsKey("qty")) {
      // This is the qty
      String sqty = "notanumber";
      if (item.containsKey("qty")) {
        sqty = item.get("qty").val();
      }
      try {
        qty = Integer.parseInt(sqty);
      } catch (NumberFormatException e) {
        throw new ConfigRuntimeException(
            "Could not get qty from given information (" + sqty + ")",
            ExceptionType.FormatException,
            t,
            e);
      }
    }

    if (item.containsKey("enchants")) {
      CArray enchantArray = null;
      try {
        if (item.containsKey("enchants")) {
          enchantArray = (CArray) item.get("enchants");
        }
        if (enchantArray == null) {
          throw new NullPointerException();
        }
      } catch (Exception e) {
        throw new ConfigRuntimeException(
            "Could not get enchantment data from given information.",
            ExceptionType.FormatException,
            t,
            e);
      }

      for (String index : enchantArray.keySet()) {
        try {
          CArray enchantment = (CArray) enchantArray.get(index);
          String setype = null;
          String selevel = null;
          if (enchantment.containsKey("etype")) {
            setype = enchantment.get("etype").val();
          }

          if (enchantment.containsKey("elevel")) {
            selevel = enchantment.get("elevel").val();
          }
          if (setype == null || selevel == null) {
            throw new ConfigRuntimeException(
                "Could not get enchantment data from given information.",
                ExceptionType.FormatException,
                t);
          }
          int elevel = 0;
          try {
            elevel = Integer.parseInt(selevel);
          } catch (NumberFormatException e) {
            throw new ConfigRuntimeException(
                "Could not get enchantment data from given information.",
                ExceptionType.FormatException,
                t);
          }
          MCEnchantment etype = StaticLayer.GetEnchantmentByName(setype);
          enchants.put(etype, elevel);
        } catch (ClassCastException e) {
          throw new ConfigRuntimeException(
              "Could not get enchantment data from given information.",
              ExceptionType.FormatException,
              t,
              e);
        }
      }
    }
    if (item.containsKey("meta")) {
      meta = itemMeta(item.get("meta"), type, t);
    }
    MCItemStack ret = StaticLayer.GetItemStack(type, qty);
    ret.setData(data);
    ret.setDurability((short) data);
    if (meta != null) {
      ret.setItemMeta(meta);
    }
    for (Map.Entry<MCEnchantment, Integer> entry : enchants.entrySet()) {
      ret.addUnsafeEnchantment(entry.getKey(), entry.getValue());
    }

    // Giving them air crashes the client, so just clear the inventory slot
    if (ret.getTypeId() == 0) {
      ret = EmptyItem();
    }
    return ret;
  }