001    package org.bukkit.inventory;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    
007    import org.apache.commons.lang.Validate;
008    
009    import org.bukkit.Material;
010    import org.bukkit.material.MaterialData;
011    
012    /**
013     * Represents a shapeless recipe, where the arrangement of the ingredients on
014     * the crafting grid does not matter.
015     */
016    public class ShapelessRecipe implements Recipe {
017        private ItemStack output;
018        private List<ItemStack> ingredients = new ArrayList<ItemStack>();
019    
020        /**
021         * Create a shapeless recipe to craft the specified ItemStack. The
022         * constructor merely determines the result and type; to set the actual
023         * recipe, you'll need to call the appropriate methods.
024         *
025         * @param result The item you want the recipe to create.
026         * @see ShapelessRecipe#addIngredient(Material)
027         * @see ShapelessRecipe#addIngredient(MaterialData)
028         * @see ShapelessRecipe#addIngredient(Material,int)
029         * @see ShapelessRecipe#addIngredient(int,Material)
030         * @see ShapelessRecipe#addIngredient(int,MaterialData)
031         * @see ShapelessRecipe#addIngredient(int,Material,int)
032         */
033        public ShapelessRecipe(ItemStack result) {
034            this.output = new ItemStack(result);
035        }
036    
037        /**
038         * Adds the specified ingredient.
039         *
040         * @param ingredient The ingredient to add.
041         * @return The changed recipe, so you can chain calls.
042         */
043        public ShapelessRecipe addIngredient(MaterialData ingredient) {
044            return addIngredient(1, ingredient);
045        }
046    
047        /**
048         * Adds the specified ingredient.
049         *
050         * @param ingredient The ingredient to add.
051         * @return The changed recipe, so you can chain calls.
052         */
053        public ShapelessRecipe addIngredient(Material ingredient) {
054            return addIngredient(1, ingredient, 0);
055        }
056    
057        /**
058         * Adds the specified ingredient.
059         *
060         * @param ingredient The ingredient to add.
061         * @param rawdata The data value, or -1 to allow any data value.
062         * @return The changed recipe, so you can chain calls.
063         * @deprecated Magic value
064         */
065        @Deprecated
066        public ShapelessRecipe addIngredient(Material ingredient, int rawdata) {
067            return addIngredient(1, ingredient, rawdata);
068        }
069    
070        /**
071         * Adds multiples of the specified ingredient.
072         *
073         * @param count How many to add (can't be more than 9!)
074         * @param ingredient The ingredient to add.
075         * @return The changed recipe, so you can chain calls.
076         */
077        public ShapelessRecipe addIngredient(int count, MaterialData ingredient) {
078            return addIngredient(count, ingredient.getItemType(), ingredient.getData());
079        }
080    
081        /**
082         * Adds multiples of the specified ingredient.
083         *
084         * @param count How many to add (can't be more than 9!)
085         * @param ingredient The ingredient to add.
086         * @return The changed recipe, so you can chain calls.
087         */
088        public ShapelessRecipe addIngredient(int count, Material ingredient) {
089            return addIngredient(count, ingredient, 0);
090        }
091    
092        /**
093         * Adds multiples of the specified ingredient.
094         *
095         * @param count How many to add (can't be more than 9!)
096         * @param ingredient The ingredient to add.
097         * @param rawdata The data value, or -1 to allow any data value.
098         * @return The changed recipe, so you can chain calls.
099         * @deprecated Magic value
100         */
101        @Deprecated
102        public ShapelessRecipe addIngredient(int count, Material ingredient, int rawdata) {
103            Validate.isTrue(ingredients.size() + count <= 9, "Shapeless recipes cannot have more than 9 ingredients");
104    
105            // -1 is the old wildcard, map to Short.MAX_VALUE as the new one
106            if (rawdata == -1) {
107                rawdata = Short.MAX_VALUE;
108            }
109    
110            while (count-- > 0) {
111                ingredients.add(new ItemStack(ingredient, 1, (short) rawdata));
112            }
113            return this;
114        }
115    
116        /**
117         * Removes an ingredient from the list. If the ingredient occurs multiple
118         * times, only one instance of it is removed. Only removes exact matches,
119         * with a data value of 0.
120         *
121         * @param ingredient The ingredient to remove
122         * @return The changed recipe.
123         */
124        public ShapelessRecipe removeIngredient(Material ingredient) {
125            return removeIngredient(ingredient, 0);
126        }
127    
128        /**
129         * Removes an ingredient from the list. If the ingredient occurs multiple
130         * times, only one instance of it is removed. If the data value is -1,
131         * only ingredients with a -1 data value will be removed.
132         *
133         * @param ingredient The ingredient to remove
134         * @return The changed recipe.
135         */
136        public ShapelessRecipe removeIngredient(MaterialData ingredient) {
137            return removeIngredient(ingredient.getItemType(), ingredient.getData());
138        }
139    
140        /**
141         * Removes multiple instances of an ingredient from the list. If there are
142         * less instances then specified, all will be removed. Only removes exact
143         * matches, with a data value of 0.
144         *
145         * @param count The number of copies to remove.
146         * @param ingredient The ingredient to remove
147         * @return The changed recipe.
148         */
149        public ShapelessRecipe removeIngredient(int count, Material ingredient) {
150            return removeIngredient(count, ingredient, 0);
151        }
152    
153        /**
154         * Removes multiple instances of an ingredient from the list. If there are
155         * less instances then specified, all will be removed. If the data value
156         * is -1, only ingredients with a -1 data value will be removed.
157         *
158         * @param count The number of copies to remove.
159         * @param ingredient The ingredient to remove.
160         * @return The changed recipe.
161         */
162        public ShapelessRecipe removeIngredient(int count, MaterialData ingredient) {
163            return removeIngredient(count, ingredient.getItemType(), ingredient.getData());
164        }
165    
166        /**
167         * Removes an ingredient from the list. If the ingredient occurs multiple
168         * times, only one instance of it is removed. If the data value is -1,
169         * only ingredients with a -1 data value will be removed.
170         *
171         * @param ingredient The ingredient to remove
172         * @param rawdata The data value;
173         * @return The changed recipe.
174         * @deprecated Magic value
175         */
176        @Deprecated
177        public ShapelessRecipe removeIngredient(Material ingredient, int rawdata) {
178            return removeIngredient(1, ingredient, rawdata);
179        }
180    
181        /**
182         * Removes multiple instances of an ingredient from the list. If there are
183         * less instances then specified, all will be removed. If the data value
184         * is -1, only ingredients with a -1 data value will be removed.
185         *
186         * @param count The number of copies to remove.
187         * @param ingredient The ingredient to remove.
188         * @param rawdata The data value.
189         * @return The changed recipe.
190         * @deprecated Magic value
191         */
192        @Deprecated
193        public ShapelessRecipe removeIngredient(int count, Material ingredient, int rawdata) {
194            Iterator<ItemStack> iterator = ingredients.iterator();
195            while (count > 0 && iterator.hasNext()) {
196                ItemStack stack = iterator.next();
197                if (stack.getType() == ingredient && stack.getDurability() == rawdata) {
198                    iterator.remove();
199                    count--;
200                }
201            }
202            return this;
203        }
204    
205        /**
206         * Get the result of this recipe.
207         *
208         * @return The result stack.
209         */
210        public ItemStack getResult() {
211            return output.clone();
212        }
213    
214        /**
215         * Get the list of ingredients used for this recipe.
216         *
217         * @return The input list
218         */
219        public List<ItemStack> getIngredientList() {
220            ArrayList<ItemStack> result = new ArrayList<ItemStack>(ingredients.size());
221            for (ItemStack ingredient : ingredients) {
222                result.add(ingredient.clone());
223            }
224            return result;
225        }
226    }