/**
  * Returns an MCColor given a colorArray, which supports the following three format types (in this
  * order of priority) array(r: 0, g: 0, b: 0) array(red: 0, green: 0, blue: 0) array(0, 0, 0)
  *
  * @param color
  * @param t
  * @return
  */
 public MCColor color(CArray color, Target t) {
   int red;
   int green;
   int blue;
   if (color.containsKey("r")) {
     red = Static.getInt32(color.get("r"), t);
   } else if (color.containsKey("red")) {
     red = Static.getInt32(color.get("red"), t);
   } else {
     red = Static.getInt32(color.get(0), t);
   }
   if (color.containsKey("g")) {
     green = Static.getInt32(color.get("g"), t);
   } else if (color.containsKey("green")) {
     green = Static.getInt32(color.get("green"), t);
   } else {
     green = Static.getInt32(color.get(1), t);
   }
   if (color.containsKey("b")) {
     blue = Static.getInt32(color.get("b"), t);
   } else if (color.containsKey("blue")) {
     blue = Static.getInt32(color.get("blue"), t);
   } else {
     blue = Static.getInt32(color.get(2), t);
   }
   return StaticLayer.GetConvertor().GetColor(red, green, blue);
 }
 /**
  * Given a Location Object, returns a MCLocation. If the optional world is not specified in the
  * object, the world provided is used instead. Location "objects" are MethodScript arrays that
  * represent a location in game. There are 4 usages:
  *
  * <ul>
  *   <li>(x, y, z)
  *   <li>(x, y, z, world)
  *   <li>(x, y, z, yaw, pitch)
  *   <li>(x, y, z, world, yaw, pitch)
  * </ul>
  *
  * In all cases, the pitch and yaw default to 0, and the world defaults to the specified world.
  * <em>More conveniently: ([world], x, y, z, [yaw, pitch])</em>
  */
 public MCLocation location(Construct c, MCWorld w, Target t) {
   if (!(c instanceof CArray)) {
     throw new ConfigRuntimeException(
         "Expecting an array, received " + c.getCType(), ExceptionType.FormatException, t);
   }
   CArray array = (CArray) c;
   MCWorld world = w;
   double x = 0;
   double y = 0;
   double z = 0;
   float yaw = 0;
   float pitch = 0;
   if (!array.inAssociativeMode()) {
     if (array.size() == 3) {
       // Just the xyz, with default yaw and pitch, and given world
       x = Static.getNumber(array.get(0, t), t);
       y = Static.getNumber(array.get(1, t), t);
       z = Static.getNumber(array.get(2, t), t);
     } else if (array.size() == 4) {
       // x, y, z, world
       x = Static.getNumber(array.get(0, t), t);
       y = Static.getNumber(array.get(1, t), t);
       z = Static.getNumber(array.get(2, t), t);
       world = Static.getServer().getWorld(array.get(3, t).val());
     } else if (array.size() == 5) {
       // x, y, z, yaw, pitch, with given world
       x = Static.getNumber(array.get(0, t), t);
       y = Static.getNumber(array.get(1, t), t);
       z = Static.getNumber(array.get(2, t), t);
       yaw = (float) Static.getNumber(array.get(3, t), t);
       pitch = (float) Static.getNumber(array.get(4, t), t);
     } else if (array.size() == 6) {
       // All have been given
       x = Static.getNumber(array.get(0, t), t);
       y = Static.getNumber(array.get(1, t), t);
       z = Static.getNumber(array.get(2, t), t);
       world = Static.getServer().getWorld(array.get(3, t).val());
       yaw = (float) Static.getNumber(array.get(4, t), t);
       pitch = (float) Static.getNumber(array.get(5, t), t);
     } else {
       throw new ConfigRuntimeException(
           "Expecting a Location array, but the array did not meet the format specifications",
           ExceptionType.FormatException,
           t);
     }
   }
   if (array.containsKey("x")) {
     x = Static.getNumber(array.get("x"), t);
   }
   if (array.containsKey("y")) {
     y = Static.getNumber(array.get("y"), t);
   }
   if (array.containsKey("z")) {
     z = Static.getNumber(array.get("z"), t);
   }
   if (array.containsKey("world")) {
     world = Static.getServer().getWorld(array.get("world").val());
   }
   if (array.containsKey("yaw")) {
     yaw = (float) Static.getDouble(array.get("yaw"), t);
   }
   if (array.containsKey("pitch")) {
     pitch = (float) Static.getDouble(array.get("pitch"), t);
   }
   // If world is still null at this point, it's an error
   if (world == null) {
     throw new ConfigRuntimeException(
         "The specified world doesn't exist, or no world was provided",
         ExceptionType.InvalidWorldException,
         t);
   }
   return StaticLayer.GetLocation(world, x, y, z, yaw, pitch);
 }
 private static MCItemStack EmptyItem() {
   return StaticLayer.GetItemStack(0, 1);
 }
 public MCItemMeta itemMeta(Construct c, int i, Target t) {
   MCItemMeta meta =
       Static.getServer().getItemFactory().getItemMeta(StaticLayer.GetConvertor().getMaterial(i));
   if (c instanceof CNull) {
     return meta;
   }
   CArray ma = null;
   if (c instanceof CArray) {
     ma = (CArray) c;
     try {
       if (ma.containsKey("display")) {
         Construct dni = ma.get("display");
         if (!(dni instanceof CNull)) {
           meta.setDisplayName(dni.val());
         }
       }
       if (ma.containsKey("lore")) {
         Construct li = ma.get("lore");
         if (li instanceof CNull) {
           // do nothing
         } else if (li instanceof CArray) {
           CArray la = (CArray) li;
           List<String> ll = new ArrayList<String>();
           for (int j = 0; j < la.size(); j++) {
             ll.add(la.get(j).val());
           }
           meta.setLore(ll);
         } else {
           throw new Exceptions.FormatException("Lore was expected to be an array.", t);
         }
       }
       if (meta instanceof MCLeatherArmorMeta) {
         if (ma.containsKey("color")) {
           Construct ci = ma.get("color");
           if (ci instanceof CNull) {
             // nothing
           } else if (ci instanceof CArray) {
             ((MCLeatherArmorMeta) meta).setColor(color((CArray) ci, t));
           } else {
             throw new Exceptions.FormatException("Color was expected to be an array.", t);
           }
         }
       }
       if (meta instanceof MCBookMeta) {
         if (ma.containsKey("title")) {
           Construct title = ma.get("title");
           if (!(title instanceof CNull)) {
             ((MCBookMeta) meta).setTitle(title.val());
           }
         }
         if (ma.containsKey("author")) {
           Construct author = ma.get("author");
           if (!(author instanceof CNull)) {
             ((MCBookMeta) meta).setAuthor(author.val());
           }
         }
         if (ma.containsKey("pages")) {
           Construct pages = ma.get("pages");
           if (pages instanceof CNull) {
             // nothing
           } else if (pages instanceof CArray) {
             CArray pa = (CArray) pages;
             List<String> pl = new ArrayList<String>();
             for (int j = 0; j < pa.size(); j++) {
               pl.add(pa.get(j).val());
             }
             ((MCBookMeta) meta).setPages(pl);
           } else {
             throw new Exceptions.FormatException("Pages field was expected to be an array.", t);
           }
         }
       }
       if (meta instanceof MCSkullMeta) {
         if (ma.containsKey("owner")) {
           Construct owner = ma.get("owner");
           if (!(owner instanceof CNull)) {
             ((MCSkullMeta) meta).setOwner(owner.val());
           }
         }
       }
       if (meta instanceof MCEnchantmentStorageMeta) {
         if (ma.containsKey("stored")) {
           Construct stored = ma.get("stored");
           if (stored instanceof CNull) {
             // Still doing nothing
           } else if (stored instanceof CArray) {
             for (String index : ((CArray) stored).keySet()) {
               try {
                 CArray earray = (CArray) ((CArray) stored).get(index);
                 MCEnchantment etype =
                     StaticLayer.GetConvertor().GetEnchantmentByName(earray.get("etype").val());
                 int elevel = Static.getInt32(earray.get("elevel"), t);
                 ((MCEnchantmentStorageMeta) meta).addStoredEnchant(etype, elevel, true);
               } catch (Exception bade) {
                 throw new Exceptions.FormatException(
                     "Could not get enchantment data from index " + index, t);
               }
             }
           } else {
             throw new Exceptions.FormatException(
                 "Stored field was expected to be an array of Enchantment arrays", t);
           }
         }
       }
     } catch (Exception ex) {
       throw new Exceptions.FormatException(
           "Could not get ItemMeta from the given information.", t);
     }
   } else {
     throw new Exceptions.FormatException(
         "An array was expected but recieved " + c + " instead.", t);
   }
   return meta;
 }
  /**
   * 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;
  }