// Path: src/main/java/me/desht/scrollingmenusign/util/SMSUtil.java
// public class SMSUtil {
//     public static String escape(String s) {
//         return StringEscapeUtils.escapeHtml(MiscUtil.unParseColourSpec(s));
//     }
// 
//     public static String unEscape(String s) {
//         return MiscUtil.parseColourSpec(StringEscapeUtils.unescapeHtml(s));
//     }
// 
//     /**
//      * Given a string specification, try to get an ItemStack.
//      * <p>
//      * The spec. is of the form "material-name[:data-byte][,amount][,glow]" where
//      * material-name is a valid Bukkit material name as understoood by
//      * {@link Material#matchMaterial(String)}, data-byte is a numeric byte value,
//      * amount is an optional item quantity, and "glow" if present indicates that
//      * the item should glow if possible.
//      * <p>
//      * No item metadata is considered by this method.
//      *
//      * @param spec the specification
//      * @return the return ItemStack
//      * @throws SMSException if the specification is invalid
//      */
//     public static ItemStack parseMaterialSpec(String spec) {
//         if (spec == null || spec.isEmpty()) {
//             return null;
//         }
// 
//         String[] fields = spec.split(",");
//         MaterialData mat = parseMatAndData(fields[0]);
// 
//         int amount = 1;
//         boolean glowing = false;
//         for (int i = 1; i < fields.length; i++) {
//             if (StringUtils.isNumeric(fields[i])) {
//                 amount = Integer.parseInt(fields[i]);
//             } else if (fields[i].equalsIgnoreCase("glow")) {
//                 glowing = true;
//             }
//         }
//         ItemStack stack = mat.toItemStack(amount);
//         if (glowing && ScrollingMenuSign.getInstance().isProtocolLibEnabled()) {
//             ItemGlow.setGlowing(stack, true);
//         }
//         return stack;
//     }
// 
//     private static MaterialData parseMatAndData(String matData) {
//         String[] fields = matData.split("[:()]");
//         Material mat = Material.matchMaterial(fields[0]);
//         if (mat == null) {
//             throw new SMSException("Unknown material " + fields[0]);
//         }
//         MaterialData res = new MaterialData(mat);
//         if (fields.length > 1) {
//             if (StringUtils.isNumeric(fields[1])) {
//                 res.setData(Byte.parseByte(fields[1]));
//             } else {
//                 switch (mat) {
//                     case INK_SACK:
//                         Dye dye = new Dye();
//                         dye.setColor(DyeColor.valueOf(fields[1].toUpperCase()));
//                         res = dye;
//                         break;
//                     case WOOL:
//                     case CARPET:
//                     case STAINED_GLASS:
//                     case STAINED_GLASS_PANE:
//                     case STAINED_CLAY:
//                         // maybe one day these will all implement Colorable...
//                         DyeColor dc2 = DyeColor.valueOf(fields[1].toUpperCase());
//                         res.setData(dc2.getWoolData());
//                         break;
//                     case SAPLING:
//                     case WOOD:
//                         TreeSpecies ts = TreeSpecies.valueOf(fields[1].toUpperCase());
//                         res.setData(ts.getData());
//                         break;
//                 }
//             }
//         }
//         return res;
//     }
// 
//     /**
//      * Given an ItemStack, freeze it into a parseable form.
//      * <p>
//      * The returned String is guaranteed to parseable by {@link #parseMaterialSpec(String)}
//      * <p>
//      * No item metadata is frozen.
//      *
//      * @param stack the ItemStack to freeze
//      * @return a String representing the ItemStack
//      */
//     public static String freezeMaterialSpec(ItemStack stack) {
//         MaterialData m = stack.getData();
//         StringBuilder sb = new StringBuilder(m.getItemType().toString());
//         if (stack.getDurability() != 0) {
//             sb.append(":").append(stack.getDurability());
//         }
//         if (stack.getAmount() > 1) {
//             sb.append(",").append(Integer.toString(stack.getAmount()));
//         }
//         if (ScrollingMenuSign.getInstance().isProtocolLibEnabled() && ItemGlow.hasGlow(stack)) {
//             sb.append(",").append("glow");
//         }
//         return sb.toString();
//     }
// 
//     public static String formatMoney(double amount) {
//         try {
//             return ScrollingMenuSign.economy.format(amount);
//         } catch (Exception e) {
//             LogUtils.warning("Caught exception from " + ScrollingMenuSign.economy.getName() + " while trying to format quantity " + amount + ":");
//             e.printStackTrace();
//             LogUtils.warning("ScrollingMenuSign will continue but you should verify your economy plugin configuration.");
//         }
//         return new DecimalFormat("#0.00").format(amount) + " ";
//     }
// }


import me.desht.scrollingmenusign.util.SMSUtil;
import org.bukkit.configuration.Configuration;
import org.bukkit.inventory.ItemStack;
import java.util.regex.Matcher;
package me.desht.scrollingmenusign;



/**
 * Cache some config values which are accessed very frequently, to reduce
 * lookup/parsing overheads.
 */
public class ConfigCache {
    private String prefixSelected;
    private String prefixNotSelected;
    private boolean physicsProtected;
    private boolean breakProtected;
    private String submenuBackLabel;
    private ItemStack submenuBackIcon;
    private String submenuTitlePrefix;
    private ItemStack defaultInventoryViewIcon;
    private String fallbackUserVarSub;

    public void processConfig(Configuration conf) {
        setPrefixSelected(conf.getString("sms.item_prefix.selected"));
        setPrefixNotSelected(conf.getString("sms.item_prefix.not_selected"));
        setPhysicsProtected(conf.getBoolean("sms.no_physics"));
        setBreakProtected(conf.getBoolean("sms.no_destroy_signs"));
        setSubmenuBackLabel(conf.getString("sms.submenus.back_item.label"));
        setSubmenuBackIcon(conf.getString("sms.submenus.back_item.material"));
        setSubmenuTitlePrefix(conf.getString("sms.submenus.title_prefix"));
        setDefaultInventoryViewIcon(conf.getString("sms.inv_view.default_icon"));
        setFallbackUserVarSub(conf.getString("sms.user_variables.fallback_sub"));
    }

    public String getPrefixSelected() {
        return prefixSelected;
    }

    public void setPrefixSelected(String prefixSelected) {
// Path: src/main/java/me/desht/scrollingmenusign/util/SMSUtil.java
// public class SMSUtil {
//     public static String escape(String s) {
//         return StringEscapeUtils.escapeHtml(MiscUtil.unParseColourSpec(s));
//     }
// 
//     public static String unEscape(String s) {
//         return MiscUtil.parseColourSpec(StringEscapeUtils.unescapeHtml(s));
//     }
// 
//     /**
//      * Given a string specification, try to get an ItemStack.
//      * <p>
//      * The spec. is of the form "material-name[:data-byte][,amount][,glow]" where
//      * material-name is a valid Bukkit material name as understoood by
//      * {@link Material#matchMaterial(String)}, data-byte is a numeric byte value,
//      * amount is an optional item quantity, and "glow" if present indicates that
//      * the item should glow if possible.
//      * <p>
//      * No item metadata is considered by this method.
//      *
//      * @param spec the specification
//      * @return the return ItemStack
//      * @throws SMSException if the specification is invalid
//      */
//     public static ItemStack parseMaterialSpec(String spec) {
//         if (spec == null || spec.isEmpty()) {
//             return null;
//         }
// 
//         String[] fields = spec.split(",");
//         MaterialData mat = parseMatAndData(fields[0]);
// 
//         int amount = 1;
//         boolean glowing = false;
//         for (int i = 1; i < fields.length; i++) {
//             if (StringUtils.isNumeric(fields[i])) {
//                 amount = Integer.parseInt(fields[i]);
//             } else if (fields[i].equalsIgnoreCase("glow")) {
//                 glowing = true;
//             }
//         }
//         ItemStack stack = mat.toItemStack(amount);
//         if (glowing && ScrollingMenuSign.getInstance().isProtocolLibEnabled()) {
//             ItemGlow.setGlowing(stack, true);
//         }
//         return stack;
//     }
// 
//     private static MaterialData parseMatAndData(String matData) {
//         String[] fields = matData.split("[:()]");
//         Material mat = Material.matchMaterial(fields[0]);
//         if (mat == null) {
//             throw new SMSException("Unknown material " + fields[0]);
//         }
//         MaterialData res = new MaterialData(mat);
//         if (fields.length > 1) {
//             if (StringUtils.isNumeric(fields[1])) {
//                 res.setData(Byte.parseByte(fields[1]));
//             } else {
//                 switch (mat) {
//                     case INK_SACK:
//                         Dye dye = new Dye();
//                         dye.setColor(DyeColor.valueOf(fields[1].toUpperCase()));
//                         res = dye;
//                         break;
//                     case WOOL:
//                     case CARPET:
//                     case STAINED_GLASS:
//                     case STAINED_GLASS_PANE:
//                     case STAINED_CLAY:
//                         // maybe one day these will all implement Colorable...
//                         DyeColor dc2 = DyeColor.valueOf(fields[1].toUpperCase());
//                         res.setData(dc2.getWoolData());
//                         break;
//                     case SAPLING:
//                     case WOOD:
//                         TreeSpecies ts = TreeSpecies.valueOf(fields[1].toUpperCase());
//                         res.setData(ts.getData());
//                         break;
//                 }
//             }
//         }
//         return res;
//     }
// 
//     /**
//      * Given an ItemStack, freeze it into a parseable form.
//      * <p>
//      * The returned String is guaranteed to parseable by {@link #parseMaterialSpec(String)}
//      * <p>
//      * No item metadata is frozen.
//      *
//      * @param stack the ItemStack to freeze
//      * @return a String representing the ItemStack
//      */
//     public static String freezeMaterialSpec(ItemStack stack) {
//         MaterialData m = stack.getData();
//         StringBuilder sb = new StringBuilder(m.getItemType().toString());
//         if (stack.getDurability() != 0) {
//             sb.append(":").append(stack.getDurability());
//         }
//         if (stack.getAmount() > 1) {
//             sb.append(",").append(Integer.toString(stack.getAmount()));
//         }
//         if (ScrollingMenuSign.getInstance().isProtocolLibEnabled() && ItemGlow.hasGlow(stack)) {
//             sb.append(",").append("glow");
//         }
//         return sb.toString();
//     }
// 
//     public static String formatMoney(double amount) {
//         try {
//             return ScrollingMenuSign.economy.format(amount);
//         } catch (Exception e) {
//             LogUtils.warning("Caught exception from " + ScrollingMenuSign.economy.getName() + " while trying to format quantity " + amount + ":");
//             e.printStackTrace();
//             LogUtils.warning("ScrollingMenuSign will continue but you should verify your economy plugin configuration.");
//         }
//         return new DecimalFormat("#0.00").format(amount) + " ";
//     }
// }


// Path: src/main/java/me/desht/scrollingmenusign/ConfigCache.java
import me.desht.scrollingmenusign.util.SMSUtil;
import org.bukkit.configuration.Configuration;
import org.bukkit.inventory.ItemStack;
import java.util.regex.Matcher;

package me.desht.scrollingmenusign;



/**
 * Cache some config values which are accessed very frequently, to reduce
 * lookup/parsing overheads.
 */
public class ConfigCache {
    private String prefixSelected;
    private String prefixNotSelected;
    private boolean physicsProtected;
    private boolean breakProtected;
    private String submenuBackLabel;
    private ItemStack submenuBackIcon;
    private String submenuTitlePrefix;
    private ItemStack defaultInventoryViewIcon;
    private String fallbackUserVarSub;

    public void processConfig(Configuration conf) {
        setPrefixSelected(conf.getString("sms.item_prefix.selected"));
        setPrefixNotSelected(conf.getString("sms.item_prefix.not_selected"));
        setPhysicsProtected(conf.getBoolean("sms.no_physics"));
        setBreakProtected(conf.getBoolean("sms.no_destroy_signs"));
        setSubmenuBackLabel(conf.getString("sms.submenus.back_item.label"));
        setSubmenuBackIcon(conf.getString("sms.submenus.back_item.material"));
        setSubmenuTitlePrefix(conf.getString("sms.submenus.title_prefix"));
        setDefaultInventoryViewIcon(conf.getString("sms.inv_view.default_icon"));
        setFallbackUserVarSub(conf.getString("sms.user_variables.fallback_sub"));
    }

    public String getPrefixSelected() {
        return prefixSelected;
    }

    public void setPrefixSelected(String prefixSelected) {
        this.prefixSelected = SMSUtil.unEscape(prefixSelected.replace("%", "%%"));