001    /**
002     * Jetrix TetriNET Server
003     * Copyright (C) 2001-2003  Emmanuel Bourg
004     *
005     * This program is free software; you can redistribute it and/or
006     * modify it under the terms of the GNU General Public License
007     * as published by the Free Software Foundation; either version 2
008     * of the License, or (at your option) any later version.
009     *
010     * This program is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program; if not, write to the Free Software
017     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018     */
019    
020    package net.jetrix.commands;
021    
022    import java.util.*;
023    
024    import net.jetrix.*;
025    import net.jetrix.messages.channel.CommandMessage;
026    import net.jetrix.messages.channel.PlineMessage;
027    
028    /**
029     * CommandManager
030     *
031     * @author Emmanuel Bourg
032     * @version $Revision: 798 $, $Date: 2009-02-18 16:24:28 +0100 (Wed, 18 Feb 2009) $
033     */
034    public class CommandManager
035    {
036        private static CommandManager instance = new CommandManager();
037    
038        /** aliases->commands Map */
039        private Map<String, Command> commands;
040    
041        /** Set of commands sorted alphabetically by the main alias */
042        private Map<String, Command> commandSet;
043    
044        private CommandManager()
045        {
046            commands = new TreeMap<String, Command>();
047            commandSet = new TreeMap<String, Command>();
048        }
049    
050        public static CommandManager getInstance()
051        {
052            return instance;
053        }
054    
055        /**
056         * Register a new command.
057         */
058        public void addCommand(Command command)
059        {
060            for (String alias : command.getAliases())
061            {
062                addCommandAlias(command, alias);
063            }
064    
065            if (command.getAliases().length > 0)
066            {
067                commandSet.put(command.getAliases()[0], command);
068            }
069        }
070    
071        /**
072         * Register a new alias for a command.
073         */
074        public void addCommandAlias(Command command, String alias)
075        {
076            commands.put(alias.toLowerCase(), command);
077        }
078    
079        /**
080         * Remove a command.
081         */
082        public void removeCommand(Command command)
083        {
084            Iterator<String> aliases = commands.keySet().iterator();
085            while (aliases.hasNext())
086            {
087                if (commands.get(aliases.next()).getClass().equals(command.getClass()))
088                {
089                    aliases.remove();
090                }
091            }
092    
093            Iterator<Command> cmds = commandSet.values().iterator();
094            while (cmds.hasNext())
095            {
096                if (cmds.next().getClass().equals(command.getClass()))
097                {
098                    cmds.remove();
099                }
100            }
101        }
102    
103        /**
104         * Return the command matching the specified alias. The alias is not
105         * case sensitive. If no command matches the exact alias specified,
106         * it will return the first command starting with the alias.
107         */
108        public Command getCommand(String alias)
109        {
110            alias = alias.toLowerCase();
111            Command command = commands.get(alias);
112    
113            if (command == null)
114            {
115                Iterator<String> aliases = commands.keySet().iterator();
116                while (command == null && aliases.hasNext())
117                {
118                    String name = aliases.next();
119                    if (name.startsWith(alias))
120                    {
121                        command = commands.get(name);
122                    }
123                }
124            }
125    
126            return command;
127        }
128    
129        /**
130         * Return all commands available to clients with the lowest
131         * access level.
132         */
133        public Iterator<Command> getCommands()
134        {
135            return getCommands(AccessLevel.PLAYER);
136        }
137    
138        /**
139         * Return all commands available to clients with the specified
140         * access level.
141         */
142        public Iterator<Command> getCommands(final int accessLevel)
143        {
144            List<Command> commands = new ArrayList<Command>();
145    
146            for (Command command : commandSet.values())
147            {
148                if (command.getAccessLevel() <= accessLevel)
149                {
150                    commands.add(command);
151                }
152            }
153    
154            return commands.iterator();
155        }
156    
157        /**
158         * Execute the command specified in the message. This method checks if
159         * the client has the access level required to use the command.
160         */
161        public void execute(CommandMessage m)
162        {
163            execute(m, getCommand(m.getCommand()));
164        }
165    
166        /**
167         * Execute an unregistered command.
168         */
169        public void execute(CommandMessage m, Command command)
170        {
171            Client client = (Client) m.getSource();
172            if (command == null)
173            {
174                PlineMessage response = new PlineMessage();
175                response.setKey("command.invalid");
176                client.send(response);
177            }
178            else
179            {
180                // check the access level
181                if (client.getUser().getAccessLevel() >= command.getAccessLevel())
182                {
183                    // check the number of parameters
184                    if (command instanceof ParameterCommand && m.getParameterCount() < ((ParameterCommand) command).getParameterCount())
185                    {
186                        // not enough parameters
187                        PlineMessage response = new PlineMessage();
188                        response.setText(colorizeUsage(command.getUsage(client.getUser().getLocale())));
189                        client.send(response);
190                        return;
191                    }
192    
193                    // execute the command
194                    try
195                    {
196                        command.execute(m);
197                    }
198                    catch (Exception e)
199                    {
200                        e.printStackTrace();
201                    }
202                }
203                else
204                {
205                    // denying access
206                    PlineMessage response = new PlineMessage();
207                    response.setKey("command.denied");
208                    client.send(response);
209                }
210            }
211        }
212    
213        /**
214         * Clear all commands.
215         */
216        public void clear()
217        {
218            commands.clear();
219            commandSet.clear();
220        }
221    
222        /**
223         * Return a colorized usage string of the specified command.
224         */
225        String colorizeUsage(String usage)
226        {
227            usage = usage.trim();
228            int i = usage.indexOf(" ");
229    
230            StringBuilder colorized = new StringBuilder();
231            colorized.append("<red>");
232    
233            if (i > -1)
234            {
235                colorized.append(usage.substring(0, i));
236                colorized.append(" <blue>");
237                colorized.append(usage.substring(i + 1));
238            }
239            else
240            {
241                colorized.append(usage);
242            }
243    
244            return colorized.toString();
245        }
246    
247    }