summaryrefslogtreecommitdiffstats
path: root/EssentialsUpdate/src/f00f/net/irc/martyr/commands/AbstractInCommand.java
blob: 97f3052416cca7a5179ccf3432206bd849061f28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package f00f.net.irc.martyr.commands;

import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

import f00f.net.irc.martyr.CommandRegister;
import f00f.net.irc.martyr.InCommand;
import f00f.net.irc.martyr.State;
import f00f.net.irc.martyr.clientstate.ClientState;

/**
 * Defines a generic command.  Most commands will simply have to
 * override the getIrcIdentifier method and implement the parse and
 * render methods using convenience methods.
 */
public abstract class AbstractInCommand implements InCommand
{

    protected Map<String,String> attributes = new HashMap<String,String>();

    protected AbstractInCommand()
    {
    }

    protected AbstractInCommand( String[] attributeNames )
    {
        for (String attributeName : attributeNames) {
            attributes.put(attributeName, null);
        }
    }

    public String getAttribute( String key )
    {
        return attributes.get( key );
    }

    public Iterator getAttributeKeys()
    {
        return Collections.unmodifiableSet( attributes.keySet() ).iterator();
    }

    protected void setAttribute( String key, String value )
    {
        attributes.put( key, value );
    }

    private String sourceString;

    /**
     * Some commands, when received by the server, can only occur in one
     * state.  Thus, when this command is received, the protocol should
     * assume that it is that state.  A command can use the 'unknown'
     * state to indicate it can be received in any state (for example,
     * ping).  Most commands will occur in the REGISTERED state, so for a
     * few exeptions, commands can leave this alone.
     */
    public State getState()
    {
        return State.REGISTERED;
    }

    /**
     * Every command should know how to register itself (or not) with the
     * command parsing engine.  If a command is available under mutiple
     * identifiers, then this method can be overridden and the addCommand
     * method can be called multiple times.
     */
    public void selfRegister( CommandRegister commandRegister )
    {
        commandRegister.addCommand( getIrcIdentifier(), this );
    }

    /**
     * Parses a string and produces a formed command object, if it can.
     * Should return null if it cannot form the command object.
     */
    public abstract InCommand parse( String prefix, String identifier, String params );

    /**
     * By default, commands do not update the client state.
     */
    public boolean updateClientState( ClientState state )
    {
        return false;
    }

    /**
     * Utility method to make parsing easy.  Provides parameter n, where
     * n=0 is the first parameter.  Parses out the : and considers
     * anything after a : to be one string, the final parameter.
     *
     * If the index doesn't exist, returns null.  Should it throw
     * IndexOutOfBoundsException?  No, some commands may have optional
     * fields.
     *
     * @param params String with parameters in it
     * @param num Position number of parameter to be requested
     * @return Parameter specified by id in params string
     */
    public String getParameter( String params, int num )
    {
        int colonIndex = params.indexOf( " :" );
        colonIndex++; // Skip the space, we just needed it to be sure it's really a "rest of line" colon
        String textParam = null;
        String spaceParams;

        if( colonIndex < 0 )
        {
            spaceParams = params;
        }
        else if( colonIndex == 0 )
        {
            if( num == 0 )
                return params.substring( 1, params.length() );
            else
                return null;
                // throw exception?
        }
        else
        {
            // colon index > 0, so we have at least one parameter before
            // the final parameter.
            spaceParams = params.substring( 0, colonIndex ).trim();
            textParam = params.substring( colonIndex + 1, params.length() );
        }

        StringTokenizer tokens = new StringTokenizer( spaceParams, " " );

        while( tokens.hasMoreTokens() && num > 0 )
        {
            // strip off tokensi
            --num;
            tokens.nextToken();
        }

        if( num == 0 && tokens.hasMoreTokens() )
            return tokens.nextToken();
        if( num == 0 && !tokens.hasMoreTokens() )
            return textParam;


        return null;
        // throw exception?
    }

    public int getIntParameter( String params, int paramnum, int defaultNum )
    {
        try
        {
            return Integer.parseInt( getParameter( params, paramnum ) );
        }
        catch( NumberFormatException nfe )
        {
            return defaultNum;
        }

    }

    public void setSourceString( String source )
    {
        this.sourceString = source;
    }

    public String getSourceString()
    {
        return sourceString;
    }

}