package me.desht.scrollingmenusign.util;
import me.desht.dhutils.ExperienceManager;
import me.desht.dhutils.ItemNames;
import me.desht.dhutils.LogUtils;
import me.desht.scrollingmenusign.SMSValidate;
import me.desht.scrollingmenusign.ScrollingMenuSign;
import me.desht.scrollingmenusign.commandlets.CooldownCommandlet;
import me.desht.scrollingmenusign.parser.SubstitutionHandler;
import me.desht.scrollingmenusign.variables.VariablesManager;
import me.desht.scrollingmenusign.views.CommandTrigger;
import me.desht.scrollingmenusign.views.SMSView;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Substitutions {
public static final Pattern userVarSubPat = Pattern.compile("<\\$([A-Za-z0-9_\\.\\*]+)(=.*?)?>");
private static final Pattern viewVarSubPat = Pattern.compile("<\\$v:([A-Za-z0-9_\\.]+)=(.*?)>");
private static final Pattern predefSubPat = Pattern.compile("<([A-Z]+)>");
private static final Map<String, SubstitutionHandler> subs = new HashMap<String, SubstitutionHandler>();
static {
setupBuiltinSubHandlers();
}
/**
* Substitute any user-defined variables (/sms var) in the given string.
*
* @param player the player running the command
* @param command The command string
* @param missing (returned) a set of variable names with no definitions,
* may be null
* @return The substituted command string
*/
public static String userVariableSubs(Player player, String command, Set<String> missing) {
Matcher m = userVarSubPat.matcher(command);
StringBuffer sb = new StringBuffer(command.length());
VariablesManager vm = ScrollingMenuSign.getInstance().getVariablesManager();
String fallback = ScrollingMenuSign.getInstance().getConfigCache().getFallbackUserVarSub();
while (m.find()) {
String repl = vm.get(player, m.group(1));
if (repl == null && m.groupCount() > 1 && m.group(2) != null) {
repl = m.group(2).substring(1);
}
if (repl == null) {
if (missing == null) {
m.appendReplacement(sb, fallback);
} else {
missing.add(m.group(1));
}
} else {
m.appendReplacement(sb, Matcher.quoteReplacement(repl));
}
}
m.appendTail(sb);
return sb.toString();
}
/**
* Substitute any view-specific variables in the given string.
*
* @param view the view
* @param str the input string
* @return the substituted string
*/
public static String viewVariableSubs(SMSView view, String str) {
Matcher m = viewVarSubPat.matcher(str);
StringBuffer sb = new StringBuffer(str.length());
while (m.find()) {
String repl = view != null && view.checkVariable(m.group(1)) ? view.getVariable(m.group(1)) : m.group(2);
m.appendReplacement(sb, Matcher.quoteReplacement(repl));
}
m.appendTail(sb);
return sb.toString();
}
/**
* Perform predefined substitutions on the supplied string.
*
* @param player the player object
* @param str the input string
* @param trigger the command trigger
* @param missing (returned) a set of variable names with no definitions,
* may be null
* @return the substituted string
*/
public static String predefSubs(Player player, String str, CommandTrigger trigger, Set<String> missing) {
Matcher m = predefSubPat.matcher(str);
StringBuffer sb = new StringBuffer(str.length());
while (m.find()) {
String key = m.group(1);
if (subs.containsKey(key)) {
String repl = subs.get(key).sub(player, trigger);
m.appendReplacement(sb, Matcher.quoteReplacement(repl));
} else {
if (missing != null) {
missing.add(key);
}
}
}
m.appendTail(sb);
return sb.toString();
}
public static void addSubstitutionHandler(String sub, SubstitutionHandler handler) {
SMSValidate.isFalse(subs.containsKey(sub), "A handler is already registered for " + sub);
SMSValidate.isTrue(sub.matches("^[A-Z]+$"), "Substitution string must be all uppercase alphabetic");
subs.put(sub, handler);
}
private static void setupBuiltinSubHandlers() {
subs.put("X", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return Integer.toString(player.getLocation().getBlockX());
}
});
subs.put("Y", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return Integer.toString(player.getLocation().getBlockY());
}
});
subs.put("Z", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return Integer.toString(player.getLocation().getBlockZ());
}
});
subs.put("NAME", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return player.getName();
}
});
subs.put("DNAME", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return player.getDisplayName();
}
});
subs.put("UUID", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return player.getUniqueId().toString();
}
});
subs.put("N", subs.get("NAME"));
subs.put("WORLD", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return player.getWorld().getName();
}
});
subs.put("I", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
LogUtils.warning("Command substitution <I> is deprecated and will stop working in a future release.");
return player.getItemInHand() == null ? "0" : Integer.toString(player.getItemInHand().getTypeId());
}
});
subs.put("INAME", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return player.getItemInHand() == null ? "Air" : ItemNames.lookup(player.getItemInHand());
}
});
subs.put("MONEY", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
if (ScrollingMenuSign.economy != null) {
return ScrollingMenuSign.getInstance().isVaultLegacyMode() ?
SMSUtil.formatMoney(ScrollingMenuSign.economy.getBalance(player.getName())) :
SMSUtil.formatMoney(ScrollingMenuSign.economy.getBalance(player));
} else {
return "0.00";
}
}
});
subs.put("VIEW", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return trigger == null ? "" : trigger.getName();
}
});
subs.put("EXP", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
return Integer.toString(new ExperienceManager(player).getCurrentExp());
}
});
subs.put("COOLDOWN", new SubstitutionHandler() {
@Override
public String sub(Player player, CommandTrigger trigger) {
CooldownCommandlet cc = (CooldownCommandlet) ScrollingMenuSign.getInstance().getCommandletManager().getCommandlet("COOLDOWN");
long millis = cc.getLastCooldownTimeRemaining();
int seconds = (int) (millis / 1000) % 60;
if (millis < 60000) return String.format("%ds", seconds);
int minutes = (int) ((millis / (1000 * 60)) % 60);
if (millis < 3600000)
return String.format("%dm %ds", minutes, seconds);
int hours = (int) ((millis / (1000 * 60 * 60)) % 24);
return String.format("%dh %dm %ds", hours, minutes, seconds);
}
});
}
}