/* * ExperienceMod - Bukkit server plugin for modifying the experience system in Minecraft. * Copyright (C) 2012 Kristian S. Stangeland * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ package com.comphenix.xp.parser; import java.util.List; import java.util.concurrent.Callable; import org.bukkit.configuration.ConfigurationSection; import com.comphenix.xp.Action; import com.comphenix.xp.messages.Message; import com.comphenix.xp.rewards.ResourceFactory; import com.comphenix.xp.rewards.ResourcesParser; import com.comphenix.xp.rewards.RewardProvider; /** * Represents a parser that will convert item configuration sections into action objects. * * @author Kristian */ public class ActionParser extends ConfigurationParser<Action> { // The current global action ID private static int currentID; private static final String MULTIPLIER_SETTING = "multiplier"; private static final String INHERIT_SETTING = "inherit"; protected StringListParser listParser = new StringListParser(); protected DoubleParser doubleParser = new DoubleParser(); protected RewardProvider provider; protected Callable<Action> previousAction; // Create a message parser that will remove elements for us protected MessagesParser messagesParser = new MessagesParser(true); // The named parameters to supply the parser protected String[] namedParameters; public ActionParser(RewardProvider provider) { this.provider = provider; } public ActionParser(RewardProvider provider, String[] namedParameters) { this.provider = provider; this.namedParameters = namedParameters; } public Action parse(ConfigurationSection input, String key) throws ParsingException { if (input == null) throw ParsingException.fromFormat("Configuration section cannot be null."); Action result = new Action(); String defaultName = provider.getDefaultName(); boolean seenInherit = false; // See if this is a top level reward if (provider.containsService(defaultName)) { ResourcesParser parser = provider.getDefaultService().getResourcesParser(namedParameters); if (parser != null) { try { ResourceFactory factory = parser.parse(input, key); // This is indeed a top level reward if (factory != null) { result.addReward(defaultName, factory); result.setId(currentID++); return result; } } catch (ParsingException e) { // See if it contains multiple rewards if (!input.isConfigurationSection(key)) { // If not, this error should propagate. throw e; } } } } ConfigurationSection values = input.getConfigurationSection(key); // See if this is a configuration section if (values == null) { return null; } // Clone it values = Utility.cloneSection(values); // Retrieve the message result.setMessages(messagesParser.parse(values)); // Next, get sub-rewards for (String sub : values.getKeys(false)) { String enumed = Utility.getEnumName(sub); if (provider.containsService(enumed)) { ResourcesParser parser = provider.getByName(enumed).getResourcesParser(namedParameters); if (parser != null) { List<Message> rewardMessages = null; ResourceFactory factory = parser.parse(values, sub, null); // Might be because we have a message and channel if (factory == null) { Object element = values.get(sub); if (element instanceof ConfigurationSection) { ConfigurationSection rewardSection = Utility.cloneSection((ConfigurationSection) element); // Copy the reward section values.set(sub, rewardSection); rewardMessages = messagesParser.parse(rewardSection); } factory = parseSection(parser, values, sub); } if (factory != null) { result.addReward(sub, factory); result.addMessage(sub, rewardMessages); } else if (rewardMessages != null && rewardMessages.size() > 0) { // Why would you add a message to an empty reward? It doesn't make any sense. throw ParsingException.fromFormat("Cannot send a message from the empty reward %s.", sub); } else { throw ParsingException.fromFormat("Range error at key %s.", sub); } } else { // This is bad throw ParsingException.fromFormat("Parser in %s cannot be NULL.", sub); } } else if (enumed.equalsIgnoreCase(MULTIPLIER_SETTING)) { result.setInheritMultiplier(doubleParser.parse(values, sub)); // Assume inheritance if not otherwise specified if (!seenInherit) { result.setInheritance(true); } } else if (enumed.equalsIgnoreCase(INHERIT_SETTING)) { Object value = values.get(sub); // Handle the inheritance field if (value instanceof Boolean) { result.setInheritance((Boolean) value); seenInherit = true; } else { throw ParsingException.fromFormat("The value %s is not a boolean. Must be TRUE/FALSE:", value); } } else { throw ParsingException.fromFormat("Unrecognized reward %s.", sub); } } // Apply this multiplier to the action itself if (result.getInheritMultiplier() != 1) { result = result.multiply(result.getInheritMultiplier()); } result.setId(currentID++); return result; } private ResourceFactory parseSection(ResourcesParser parser, ConfigurationSection input, String key) throws ParsingException { Object element = input.get(key); ResourceFactory result = null; if (element instanceof ConfigurationSection) { input = (ConfigurationSection) element; for (String sub : input.getKeys(false)) { String enumed = Utility.getEnumName(sub); // Parse the default key if (enumed.equalsIgnoreCase("default")) result = parser.parse(input, sub); else throw ParsingException.fromFormat("Unrecognized element %s in reward %s.", sub, key); } return result; } else { throw ParsingException.fromFormat("%s has an invalid reward.", key); } } /** * Creates a shallow copy of this parser with the given reward provider. * @param provider - new reward provider. * @return Shallow copy of this parser. */ public ActionParser createView(RewardProvider provider) { return new ActionParser(provider); } /** * Creates a shallow copy of this parser with the given named parameters. * @param namedParameters - new named parameters. * @return Shallow copy of this parser. */ public ActionParser createView(String[] namedParameters) { return new ActionParser(provider, namedParameters); } /** * A function that retrieves the previous action, if any, that matches this * action by its query. * @return Previous action. */ public Callable<Action> getPreviousAction() { return previousAction; } /** * Sets a function that retrieves the previous action, if any, that matches * this action by its query. * @param previousAction - the function. */ public void setPreviousAction(Callable<Action> previousAction) { this.previousAction = previousAction; } public String[] getNamedParameters() { return namedParameters; } public static int getCurrentID() { return currentID; } public static void setCurrentID(int id) { currentID = id; } }