001    package org.bukkit.command;
002    
003    import java.util.ArrayList;
004    import java.util.logging.Level;
005    
006    import org.bukkit.Bukkit;
007    import org.bukkit.entity.Player;
008    import org.bukkit.event.player.PlayerCommandPreprocessEvent;
009    import org.bukkit.event.server.RemoteServerCommandEvent;
010    import org.bukkit.event.server.ServerCommandEvent;
011    
012    public class FormattedCommandAlias extends Command {
013        private final String[] formatStrings;
014    
015        public FormattedCommandAlias(String alias, String[] formatStrings) {
016            super(alias);
017            this.formatStrings = formatStrings;
018        }
019    
020        @Override
021        public boolean execute(CommandSender sender, String commandLabel, String[] args) {
022            boolean result = false;
023            ArrayList<String> commands = new ArrayList<String>();
024            for (String formatString : formatStrings) {
025                try {
026                    commands.add(buildCommand(formatString, args));
027                } catch (Throwable throwable) {
028                    if (throwable instanceof IllegalArgumentException) {
029                        sender.sendMessage(throwable.getMessage());
030                    } else {
031                        sender.sendMessage(org.bukkit.ChatColor.RED + "An internal error occurred while attempting to perform this command");
032                    }
033                    return false;
034                }
035            }
036    
037            for (String command : commands) {
038                result |= Bukkit.dispatchCommand(sender, command);
039            }
040    
041            return result;
042        }
043    
044        private String buildCommand(String formatString, String[] args) {
045            int index = formatString.indexOf("$");
046            while (index != -1) {
047                int start = index;
048    
049                if (index > 0 && formatString.charAt(start - 1) == '\\') {
050                    formatString = formatString.substring(0, start - 1) + formatString.substring(start);
051                    index = formatString.indexOf("$", index);
052                    continue;
053                }
054    
055                boolean required = false;
056                if (formatString.charAt(index + 1) == '$') {
057                    required = true;
058                    // Move index past the second $
059                    index++;
060                }
061    
062                // Move index past the $
063                index++;
064                int argStart = index;
065                while (index < formatString.length() && inRange(((int) formatString.charAt(index)) - 48, 0, 9)) {
066                    // Move index past current digit
067                    index++;
068                }
069    
070                // No numbers found
071                if (argStart == index) {
072                    throw new IllegalArgumentException("Invalid replacement token");
073                }
074    
075                int position = Integer.valueOf(formatString.substring(argStart, index));
076    
077                // Arguments are not 0 indexed
078                if (position == 0) {
079                    throw new IllegalArgumentException("Invalid replacement token");
080                }
081    
082                // Convert position to 0 index
083                position--;
084    
085                boolean rest = false;
086                if (index < formatString.length() && formatString.charAt(index) == '-') {
087                    rest = true;
088                    // Move index past the -
089                    index++;
090                }
091    
092                int end = index;
093    
094                if (required && position >= args.length) {
095                    throw new IllegalArgumentException("Missing required argument " + (position + 1));
096                }
097    
098                StringBuilder replacement = new StringBuilder();
099                if (rest && position < args.length) {
100                    for (int i = position; i < args.length; i++) {
101                        if (i != position) {
102                            replacement.append(' ');
103                        }
104                        replacement.append(args[i]);
105                    }
106                } else if (position < args.length) {
107                    replacement.append(args[position]);
108                }
109    
110                formatString = formatString.substring(0, start) + replacement.toString() + formatString.substring(end);
111                // Move index past the replaced data so we don't process it again
112                index = start + replacement.length();
113    
114                // Move to the next replacement token
115                index = formatString.indexOf("$", index);
116            }
117    
118            return formatString;
119        }
120    
121        private static boolean inRange(int i, int j, int k) {
122            return i >= j && i <= k;
123        }
124    }