package com.bergerkiller.bukkit.common.inventory; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import com.bergerkiller.bukkit.common.utils.ItemUtil; import com.bergerkiller.bukkit.common.utils.LogicUtil; import com.bergerkiller.bukkit.common.utils.MaterialUtil; import com.bergerkiller.bukkit.common.utils.ParseUtil; import com.bergerkiller.bukkit.common.utils.StringUtil; /** * Can be used to match items against, and to provide amounts. * Material AIR is designated for invalid (or failed-to-parse) Item Parsers. */ public class ItemParser { public static final char STACK_MULTIPLIER = '^'; public static final char[] MULTIPLIER_SIGNS = {'x', 'X', '*', ' ', '@', STACK_MULTIPLIER}; /** * Constructs a new Item Parser for any data and infinite amount * * @param type to match, null for any type */ public ItemParser(Material type) { this(type, -1); } /** * Constructs a new Item Parser for any data * * @param type to match, null for any type * @param amount to use, -1 for infinite */ public ItemParser(Material type, int amount) { this(type, amount, -1); } /** * Constructs a new Item Parser * * @param type to match, null for any type * @param amount to use, -1 for infinite * @param data to match, -1 for any data */ public ItemParser(Material type, int amount, int data) { this.amount = amount; this.data = data; this.type = type; } private ItemParser() { this.data = -1; this.type = null; this.amount = 1; } private int data; private Material type; private int amount; /** * Supported formats: typedata: [type]:[data] [typeid]:[data] [typeid] * * Amount/name relationship: [amount]x[typedata] [amount]*[typedata] * [amount] [typedata] [amount]@[typedata] [typedata] */ public static ItemParser parse(String fullname) { fullname = fullname.trim(); int index = StringUtil.firstIndexOf(fullname, MULTIPLIER_SIGNS); if (index == -1) { return parse(fullname, null); } else { ItemParser parser = parse(fullname.substring(index + 1), fullname.substring(0, index)); if (fullname.charAt(index) == STACK_MULTIPLIER) { parser = parser.multiplyAmount(parser.getMaxStackSize()); } return parser; } } public static ItemParser parse(String name, String amount) { int index = name.indexOf(':'); if (index == -1) { return parse(name, null, amount); } else { return parse(name.substring(0, index), name.substring(index + 1), amount); } } public static ItemParser parse(String name, String dataname, String amount) { ItemParser parser = new ItemParser(); // parse amount parser.amount = ParseUtil.parseInt(amount, -1); // parse material from name if (LogicUtil.nullOrEmpty(name)) { parser.type = null; } else { parser.type = ParseUtil.parseMaterial(name, Material.AIR); } // parse material data from name if needed if (parser.hasType() && !LogicUtil.nullOrEmpty(dataname)) { parser.data = ParseUtil.parseMaterialData(dataname, parser.type, -1); } return parser; } public boolean match(ItemStack stack) { if (stack == null) { return false; } return this.match(MaterialUtil.getTypeId(stack), MaterialUtil.getRawData(stack)); } public boolean match(Material type, int data) { if (type == null) { return false; } return this.match(MaterialUtil.getTypeId(type), data); } public boolean match(int typeid, int data) { if (this.hasType() && typeid != this.getTypeId()) { return false; } if (!this.hasData() || data == this.getData()) { return true; } // Take in account certain items/blocks with bit fields if (this.getType() == Material.LEAVES) { return (data & 0x3) == this.getData(); } else { return false; } } /** * Checks whether an amount is being used * * @return True if there is an amount, False if not */ public boolean hasAmount() { return this.amount >= 0; } /** * Checks whether data is being used * * @return True if there is data, False if not */ public boolean hasData() { return this.data >= 0; } /** * Checks whether a type is being used * * @return True if there is a type, False if not */ public boolean hasType() { return this.type != null; } /** * Gets the data to match against, -1 for any data * * @return Matched data */ public int getData() { return this.data; } /** * Gets the amount, -1 for infinite amount * * @return Amount */ public int getAmount() { return this.amount; } /** * Gets the type to match against, null for any item * * @return Matched type */ public Material getType() { return this.type; } /** * Gets the type Id to match against, -1 for any item * * @return Matched type Id */ public int getTypeId() { return this.type == null ? -1 : MaterialUtil.getTypeId(this.type); } public ItemStack getItemStack() { return this.getItemStack(this.amount); } public ItemStack getItemStack(int amount) { return new ItemStack(this.type, this.amount, (short) this.data); } public int getMaxStackSize() { return ItemUtil.getMaxSize(this.getTypeId(), 64); } /** * Creates a new ItemParser with the type and amount of this parser, but with a new data * * @param data for the new parser (-1 for no data) * @return new ItemParser with the new data */ public ItemParser setData(int data) { return new ItemParser(this.type, this.amount, data); } /** * Creates a new ItemParser with the type and data of this parser, but with a new amount * * @param amount for the new parser, -1 for infinite * @return new ItemParser with the new amount */ public ItemParser setAmount(int amount) { return new ItemParser(this.type, amount, this.data); } /** * Multiplies the amount of this item parser with the amount specified<br> * If this parser has no amount, an amount of 1 is assumed, * resulting in a new item parser with the specified amount * * @param amount to multiply with * @return new Item Parser with the multiplied amount */ public ItemParser multiplyAmount(int amount) { if (this.hasAmount()) { amount *= this.getAmount(); } return this.setAmount(amount); } @Override public String toString() { StringBuilder rval = new StringBuilder(); if (this.hasAmount()) { rval.append(this.amount).append(" of "); } if (this.hasType()) { rval.append(this.type.toString().toLowerCase()); if (this.hasData()) { rval.append(':').append(this.data); } } else { rval.append("any type"); } return rval.toString(); } }