package net.knarcraft.blacksmith.util; import net.knarcraft.blacksmith.container.ActionCost; import net.knarcraft.blacksmith.formatting.Translatable; import net.knarcraft.blacksmith.property.CostModifyAction; import net.knarcraft.blacksmith.property.CostType; import net.knarcraft.knarlib.formatting.FormatBuilder; import net.knarcraft.knarlib.util.TabCompletionHelper; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** * A helper class for setting action costs */ public final class CostHelper { private CostHelper() { } /** * Parses a simple double cost * * @param commandSender

The command sender to notify of any problems

* @param costString

The string to parse into a cost

* @return

The parsed cost, or null if not a valid number

*/ @Nullable public static Double parseSimpleCost(@NotNull CommandSender commandSender, @NotNull String costString) throws IllegalArgumentException { try { double cost = Double.parseDouble(costString); if (cost < 0) { throw new NumberFormatException(); } return cost; } catch (NumberFormatException exception) { new FormatBuilder(Translatable.DOUBLE_COST_REQUIRED).error(commandSender); return null; } } /** * Shows tab-completion actions for altering a cost * * @param arguments

The arguments given by the user

* @return

The available tab-complete options

*/ public static @Nullable List tabCompleteCost(@NotNull String[] arguments) { if (arguments.length == 1) { return List.of("simple", "advanced"); } else if (arguments.length == 2) { if (arguments[0].equalsIgnoreCase("simple")) { return List.of(); } else { return TabCompletionHelper.filterMatchingStartsWith(TabCompletionHelper.getEnumList(CostModifyAction.class), arguments[1]); } } else if (arguments.length == 3) { if (arguments[0].equalsIgnoreCase("simple")) { return List.of(); } else { return TabCompletionHelper.filterMatchingStartsWith(TabCompletionHelper.getEnumList(CostType.class), arguments[2]); } } else if (arguments.length == 4) { CostType costType = CostType.parse(arguments[2]); if (costType == null) { return null; } return switch (costType) { case PERMISSION -> TabCompletionHelper.tabCompletePermission(arguments[3]); case ECONOMY -> List.of("0.5", "1", "10"); case EXP -> List.of("1, 5, 10"); case ITEM -> List.of(); }; } return List.of(); } /** * Modifies the cost of an action * * @param costAction

The action to perform on the cost

* @param costTypeName

The name of the cost to modify, or null if clearing costs

* @param costValue

The value of the new cost, or null if clearing costs

* @param oldCost

The previous cost of the action

* @param player

The player attempting to alter the action cost

* @return

The modified action cost, or null if something went wrong

*/ @Nullable public static ActionCost modifyActionCost(@NotNull String costAction, @Nullable String costTypeName, @Nullable String costValue, @NotNull ActionCost oldCost, @NotNull Player player) { CostType costType; if (costTypeName != null) { costType = CostType.parse(costTypeName); } else { costType = null; } CostModifyAction action = CostModifyAction.fromString(costAction); if (action == null) { return null; } if (action != CostModifyAction.CLEAR && (costType == null || costValue == null)) { player.sendMessage("Invalid cost type or value specified!"); return null; } return switch (action) { case CLEAR -> clearActionCost(costType, oldCost); case ADD -> addActionCost(costType, costValue, oldCost, player); case SET -> setActionCost(costType, costValue, player); }; } /** * Sets the cost to the specified value * * @param costType

The type of cost to set

* @param costValue

The value of the new cost

* @param player

The player to alert if the cost cannot be properly set

* @return

The new action cost

*/ public static ActionCost setActionCost(@NotNull CostType costType, @NotNull String costValue, @NotNull Player player) { return parseCost(costType, costValue, new ActionCost(), player); } /** * Modifies a value for the specified action cost * * @param costType

The type of cost to modify

* @param costValue

The new value of the cost

* @param oldCost

The cost to modify

* @param player

The player to alert if the cost cannot be properly set

* @return

The new action cost

*/ public static ActionCost addActionCost(@NotNull CostType costType, @NotNull String costValue, @NotNull ActionCost oldCost, @NotNull Player player) { return parseCost(costType, costValue, oldCost, player); } /** * Clears an action cost * * @param costType

The type of action cost to clear, or null if clearing all action costs

* @param oldCost

The old cost to modify, or null if clearing all action costs

* @return

The modified cost

*/ public static ActionCost clearActionCost(@Nullable CostType costType, @Nullable ActionCost oldCost) { // Clears one or all fields of a cost if (costType == null || oldCost == null) { return new ActionCost(); } else { return switch (costType) { case EXP -> oldCost.changeExpCost(0); case ITEM -> oldCost.changeItemCost(null); case ECONOMY -> oldCost.changeMonetaryCost(0); case PERMISSION -> oldCost.changePermissionCost(Set.of()); }; } } /** * Parses an advanced action cost * * @param costType

The type of cost to parse

* @param value

The value to parse

* @param oldCost

The old cost to modify

* @param player

The player changing the value

* @return

The new action cost, or null if the process failed.

*/ @Nullable private static ActionCost parseCost(@NotNull CostType costType, @NotNull String value, @NotNull ActionCost oldCost, @NotNull Player player) { switch (costType) { case ECONOMY: double economyCost = Double.parseDouble(value); if (economyCost < 0) { new FormatBuilder("Cost cannot be negative!").error(player); return null; } return oldCost.changeMonetaryCost(economyCost); case ITEM: ItemStack itemCost = player.getInventory().getItemInMainHand(); if (itemCost.getType().isAir()) { new FormatBuilder("You have no item in your main hand").error(player); return null; } return oldCost.changeItemCost(itemCost); case PERMISSION: Set permissionSet = new HashSet<>(Arrays.asList(value.split(","))); return oldCost.changePermissionCost(permissionSet); case EXP: int expCost = Integer.parseInt(value); if (expCost < 0) { new FormatBuilder("Exp cost cannot be negative!").error(player); return null; } return oldCost.changeExpCost(expCost); default: return null; } } }