diff --git a/src/main/java/net/knarcraft/paidsigns/PaidSigns.java b/src/main/java/net/knarcraft/paidsigns/PaidSigns.java index 4616d5b..0e90225 100644 --- a/src/main/java/net/knarcraft/paidsigns/PaidSigns.java +++ b/src/main/java/net/knarcraft/paidsigns/PaidSigns.java @@ -4,6 +4,8 @@ import net.knarcraft.paidsigns.command.AddCommand; import net.knarcraft.paidsigns.command.AddConditionCommand; import net.knarcraft.paidsigns.command.AddConditionTabCompleter; import net.knarcraft.paidsigns.command.AddTabCompleter; +import net.knarcraft.paidsigns.command.EditCommand; +import net.knarcraft.paidsigns.command.EditTabCompleter; import net.knarcraft.paidsigns.command.ListCommand; import net.knarcraft.paidsigns.command.ListTabCompleter; import net.knarcraft.paidsigns.command.ReloadTabCommand; @@ -154,7 +156,9 @@ public final class PaidSigns extends JavaPlugin { registerCommand("addPaidSign", new AddCommand(), new AddTabCompleter()); registerCommand("listPaidSigns", new ListCommand(), new ListTabCompleter()); registerCommand("addPaidSignCondition", new AddConditionCommand(), new AddConditionTabCompleter()); - registerCommand("removePaidSignCondition", new RemoveConditionCommand(), new RemoveConditionTabCompleter()); + registerCommand("removePaidSignCondition", new RemoveConditionCommand(), + new RemoveConditionTabCompleter()); + registerCommand("editPaidSign", new EditCommand(), new EditTabCompleter()); TabExecutor removeTabExecutor = new RemoveTabCommand(); registerCommand("removePaidSign", removeTabExecutor, removeTabExecutor); diff --git a/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java b/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java index f42febc..3a52319 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/AddConditionCommand.java @@ -11,8 +11,6 @@ import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.io.IOException; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; /** * A representation of the command for adding a new match condition for a sign @@ -43,7 +41,7 @@ public class AddConditionCommand extends TokenizedCommand { boolean executeRegEx = false; if (argumentSize > 3) { executeRegEx = Boolean.parseBoolean(arguments.get(3)); - if (executeRegEx && !testRegEx(sender, stringToMatch)) { + if (executeRegEx && isRegExInvalid(sender, stringToMatch)) { return false; } } @@ -58,24 +56,6 @@ public class AddConditionCommand extends TokenizedCommand { return addCondition(name, lineNumber, stringToMatch, executeRegEx, ignoreCase, ignoreColor, sender); } - /** - * Tests whether the given regular expression is valid - * - * @param sender

The command sender to notify if the regular expression is invalid

- * @param regularExpression

The regular expression to test

- * @return

True if the regular expression is valid

- */ - private boolean testRegEx(CommandSender sender, String regularExpression) { - try { - Pattern.compile(regularExpression); - return true; - } catch (PatternSyntaxException exception) { - sender.sendMessage(StringFormatter.getTranslatedErrorMessage( - TranslatableMessage.ERROR_INVALID_REGULAR_EXPRESSION)); - return false; - } - } - /** * Uses the given input to add a paid sign condition * diff --git a/src/main/java/net/knarcraft/paidsigns/command/EditCommand.java b/src/main/java/net/knarcraft/paidsigns/command/EditCommand.java index f5197d3..7897681 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/EditCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/EditCommand.java @@ -1,15 +1,176 @@ package net.knarcraft.paidsigns.command; +import net.knarcraft.paidsigns.PaidSigns; +import net.knarcraft.paidsigns.container.PaidSign; +import net.knarcraft.paidsigns.container.PaidSignCondition; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; +import net.knarcraft.paidsigns.manager.PaidSignManager; +import net.knarcraft.paidsigns.property.OptionState; +import net.knarcraft.paidsigns.property.PaidSignConditionProperty; +import net.knarcraft.paidsigns.property.PaidSignProperty; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; +import java.io.IOException; + +/** + * A representation of the command for editing a new paid sign + */ public class EditCommand extends TokenizedCommand { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - return false; + if (argumentSize < 3) { + return false; + } + + PaidSign sign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0)); + if (sign == null) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_PAID_SIGN_NOT_FOUND)); + return false; + } + + try { + try { + //First, assume a condition is changed + return parseGivenConditionLine(sign, sender); + } catch (NumberFormatException exception) { + //Fall back to assume a sign is changed + return parseGivenProperty(sign, sender); + } + } catch (IOException e) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED)); + return false; + } + } + + /** + * Parses the given condition line and the rest of the input + * + * @param sign

The paid sign the user is trying to edit

+ * @param sender

The command sender to notify of any errors

+ * @return

True if the command was executed successfully

+ * @throws NumberFormatException

If the given argument is not a number

+ */ + private boolean parseGivenConditionLine(@NotNull PaidSign sign, + @NotNull CommandSender sender) throws NumberFormatException { + short signLine = (short) (Short.parseShort(arguments.get(1)) - 1); + if (signLine < 0 || signLine > 3 || sign.getConditions().get(signLine) == null) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_NO_SUCH_CONDITION)); + return false; + } + if (argumentSize < 4) { + return false; + } + + PaidSignConditionProperty conditionProperty = PaidSignConditionProperty.getFromString(arguments.get(2)); + if (conditionProperty == null) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage( + TranslatableMessage.ERROR_PROPERTY_NOT_RECOGNIZED)); + return false; + } + String value = arguments.get(3); + return updateConditionProperty(sender, sign, signLine, conditionProperty, value); + } + + /** + * Parses the given paid sign property and the rest of the input + * + * @param sign

The paid sign the user is trying to edit

+ * @param sender

The command sender to notify of any errors

+ * @return

True if the command was executed successfully

+ * @throws IOException

If unable to remove or save the sign

+ */ + private boolean parseGivenProperty(@NotNull PaidSign sign, + @NotNull CommandSender sender) throws IOException { + PaidSignProperty property = PaidSignProperty.getFromString(arguments.get(1)); + if (property == null) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage( + TranslatableMessage.ERROR_PROPERTY_NOT_RECOGNIZED)); + return false; + } + String value = arguments.get(2); + try { + updateProperty(sender, sign, property, value); + return true; + } catch (NumberFormatException exception) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_INVALID_NUMBER)); + return false; + } + } + + /** + * Updates a property for a paid sign + * + * @param sender

The command sender to notify of any errors or success

+ * @param sign

The sign to be updated

+ * @param property

The property to update

+ * @param newValue

The new value of the property

+ * @throws IOException

If unable to remove or save the sign

+ */ + private void updateProperty(CommandSender sender, PaidSign sign, PaidSignProperty property, + String newValue) throws IOException { + String signName = property == PaidSignProperty.NAME ? newValue : sign.getName(); + OptionState ignoreCase = property == PaidSignProperty.IGNORE_CASE ? OptionState.fromString(newValue) : + OptionState.getFromBoolean(sign.getIgnoreCase()); + OptionState ignoreColor = property == PaidSignProperty.IGNORE_COLOR ? OptionState.fromString(newValue) : + OptionState.getFromBoolean(sign.getIgnoreColor()); + boolean matchAnyCondition = property == PaidSignProperty.MATCH_ANY_CONDITION ? Boolean.parseBoolean(newValue) : + sign.matchAnyCondition(); + double cost = property == PaidSignProperty.COST ? Double.parseDouble(newValue) : sign.getCost(); + String permission = property == PaidSignProperty.PERMISSION ? newValue : sign.getPermission(); + + PaidSignManager manager = PaidSigns.getInstance().getSignManager(); + PaidSign updatedSign = new PaidSign(signName, cost, permission, ignoreCase, ignoreColor, matchAnyCondition); + manager.removePaidSign(sign.getName()); + manager.addPaidSign(updatedSign); + + sender.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.SUCCESS_UPDATED_PAID_SIGN)); + } + + /** + * Updates a property of a condition of a paid sign + * + * @param sender

The command sender to notify of any errors or success

+ * @param sign

The sign the condition belongs to

+ * @param conditionIndex

The line index that identifies the sign condition

+ * @param property

The condition property to update

+ * @param newValue

The new value of the property

+ * @return

True if the property was successfully changed

+ */ + private boolean updateConditionProperty(CommandSender sender, PaidSign sign, short conditionIndex, + PaidSignConditionProperty property, String newValue) { + PaidSignCondition condition = sign.getConditions().get(conditionIndex); + String stringToMatch = property == PaidSignConditionProperty.STRING_TO_MATCH ? newValue : + condition.getStringToMatch(); + boolean executeRegEx = property == PaidSignConditionProperty.EXECUTE_REG_EX ? Boolean.parseBoolean(newValue) : + condition.executeRegex(); + boolean ignoreCase = property == PaidSignConditionProperty.IGNORE_CASE ? Boolean.parseBoolean(newValue) : + condition.ignoreCase(); + boolean ignoreColor = property == PaidSignConditionProperty.IGNORE_COLOR ? Boolean.parseBoolean(newValue) : + condition.ignoreColor(); + + //Make sure to test the regular expression in case anything changed + if (executeRegEx && isRegExInvalid(sender, stringToMatch)) { + return false; + } + + sign.addCondition(conditionIndex, stringToMatch, executeRegEx, OptionState.getFromBoolean(ignoreCase), + OptionState.getFromBoolean(ignoreColor)); + + try { + PaidSigns.getInstance().getSignManager().saveSigns(); + } catch (IOException e) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.ERROR_EXCEPTION_OCCURRED)); + return false; + } + + sender.sendMessage(StringFormatter.getTranslatedInfoMessage( + TranslatableMessage.SUCCESS_UPDATED_PAID_SIGN_CONDITION)); + return true; } } diff --git a/src/main/java/net/knarcraft/paidsigns/command/EditTabCompleter.java b/src/main/java/net/knarcraft/paidsigns/command/EditTabCompleter.java index 682f068..b59533b 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/EditTabCompleter.java +++ b/src/main/java/net/knarcraft/paidsigns/command/EditTabCompleter.java @@ -15,6 +15,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * The tab completer for the edit paid sign command + */ public class EditTabCompleter extends TokenizedTabCompleter { private static Map> propertyExampleValues; @@ -70,7 +73,7 @@ public class EditTabCompleter extends TokenizedTabCompleter { * @return

The tab complete options to give to users

*/ private List tabCompleteSignLine(@NotNull PaidSign sign) { - short signLine = Short.parseShort(arguments.get(2)); + short signLine = (short) (Short.parseShort(arguments.get(2)) - 1); //Refuse to autocomplete if invalid input is given if (signLine < 0 || signLine > 3 || sign.getConditions().get(signLine) == null) { return new ArrayList<>(); diff --git a/src/main/java/net/knarcraft/paidsigns/command/TokenizedCommand.java b/src/main/java/net/knarcraft/paidsigns/command/TokenizedCommand.java index 107b00b..a76ac78 100644 --- a/src/main/java/net/knarcraft/paidsigns/command/TokenizedCommand.java +++ b/src/main/java/net/knarcraft/paidsigns/command/TokenizedCommand.java @@ -1,5 +1,7 @@ package net.knarcraft.paidsigns.command; +import net.knarcraft.paidsigns.formatting.StringFormatter; +import net.knarcraft.paidsigns.formatting.TranslatableMessage; import net.knarcraft.paidsigns.utility.Tokenizer; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -7,6 +9,8 @@ import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; /** * A command executor with tokenized arguments @@ -23,4 +27,22 @@ public class TokenizedCommand implements CommandExecutor { return true; } + /** + * Tests whether the given regular expression is valid + * + * @param sender

The command sender to notify if the regular expression is invalid

+ * @param regularExpression

The regular expression to test

+ * @return

True if the regular expression is invalid

+ */ + protected boolean isRegExInvalid(CommandSender sender, String regularExpression) { + try { + Pattern.compile(regularExpression); + return false; + } catch (PatternSyntaxException exception) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage( + TranslatableMessage.ERROR_INVALID_REGULAR_EXPRESSION)); + return true; + } + } + } diff --git a/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java b/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java index b0219d5..0be698b 100644 --- a/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java +++ b/src/main/java/net/knarcraft/paidsigns/formatting/TranslatableMessage.java @@ -20,6 +20,16 @@ public enum TranslatableMessage { */ SUCCESS_ADDED_PAID_SIGN_CONDITION, + /** + * The message to display when a paid sign is successfully updated + */ + SUCCESS_UPDATED_PAID_SIGN, + + /** + * The message to display when a paid sign condition is successfully updated + */ + SUCCESS_UPDATED_PAID_SIGN_CONDITION, + /** * The message to display when a paid sign has been successfully removed */ @@ -120,4 +130,9 @@ public enum TranslatableMessage { */ ERROR_INVALID_REGULAR_EXPRESSION, + /** + * The error to display if an invalid property is given to the edit command + */ + ERROR_PROPERTY_NOT_RECOGNIZED, + } diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml index 28dbac3..03d8867 100644 --- a/src/main/resources/strings.yml +++ b/src/main/resources/strings.yml @@ -2,6 +2,8 @@ en: PREFIX: "[PaidSigns]" SUCCESS_ADDED_PAID_SIGN: "&bSuccessfully added new paid sign" SUCCESS_ADDED_PAID_SIGN_CONDITION: "&bSuccessfully added new paid sign condition" + SUCCESS_UPDATED_PAID_SIGN: "&bSuccessfully updated the paid sign property" + SUCCESS_UPDATED_PAID_SIGN_CONDITION: "&bSuccessfully updated the paid sign condition property" SUCCESS_REMOVED_PAID_SIGN: "&bSuccessfully removed paid sign" SUCCESS_REMOVED_CONDITION: "&bSuccessfully removed paid sign condition" SUCCESS_RELOADED: "&bSuccessfully reloaded configuration" @@ -21,4 +23,5 @@ en: ERROR_PAID_SIGN_NOT_FOUND: "&bNo such paid sign exists" ERROR_NO_SUCH_CONDITION: "&bThe paid sign you specified has no condition for line {line}" ERROR_CANNOT_AFFORD: "&bYou cannot afford to create this sign" - ERROR_INVALID_REGULAR_EXPRESSION: "&bThe provided regular expression is invalid" \ No newline at end of file + ERROR_INVALID_REGULAR_EXPRESSION: "&bThe provided regular expression is invalid" + ERROR_PROPERTY_NOT_RECOGNIZED: "&bThe property you tried to change was not recognized" \ No newline at end of file