package edu.columbia.sip;

import com.objectspace.jgl.Array;
import com.objectspace.jgl.ArrayIterator;

/** Class ProtocolToken models a Protocol by containing a static instance
 * of each of the acceptable tokens in that protocol.  A token is defined as 
 * one of the keywords which can start a line in the protocol and which provides
 * meaning on how to interpret the information in the rest of that line. <p>
 * 
 * Methods are also provided to obtain a token based on its string and to test 
 * whether a given string is a Protocol-correct parameter list for that token.
 *
 * For example, "Content-Type" is a token in the HTTP, and it is represented by
 * HTTPToken.CONTENT_TYPE.  That symbol can be retrieved by calling 
 * HTTPToken.getToken("Content-Type"), and its parameter can be checked by calling
 * HTTPToken.CONTENT_TYPE.isValidParam("application/sdp");  In this case the function
 * would return true, while if it were called with "mjs@cs.columbia.edu" it would
 * return false as that string would not be recognized as a valid parameter list.
 *
 * NOTE that this class does not encapsulate the functionality of what to do with the 
 * information contaned in the values of the tokens and their parameters -- that 
 * functionality is in the SIPConnection class.  It might be a better idea to have
 * that information here as well, but at the time of this design it did not seem 
 * practical.
 *
 * @author Moshe Sambol
 */
public abstract class ProtocolToken {
    // the implementation of this class is very basic, but the interface
    // is designed to hide this.  It seems that the basic design should be sufficient
    // and not hinder performance as there are not expected to be many tokens per
    // protocol, but if in the future another design is implemented the current
    // interface should suffice and not require change.
    
    /** the text of the token */
    private String _text;
    
    /** a list of valid tokens in this protocol */
    private static Array _legalTokens;
    
    /** The constructor is private and empty so that clients cannot create 
     * protocol tokens - one list is maintained for all clients to share.
     */
    private ProtocolToken() {};

    /** This constructor is protected so that clients cannot create tokens; one
     * list of atomic tokens is shared among all clients.  
     *
     * @param s the string which represents the token
     */
    protected ProtocolToken(String s) {
        // if no tokens have yet been created, make an empty array to 
        // hold all the tokens of this protocol
        if (_legalTokens == null) {
            _legalTokens = new Array();
        }
        
        _text = s;
        
        // add this token to the list of those considered legal by the protocol.
        _legalTokens.add(this);
    } // end CTOR(String s)
    
    /** retrieve the text which represents this token 
     *
     * @returns a String of text which represents this token
     */
    public String getText() {
        return _text;
    }
  
    /** allow comparisons with strings 
     * 
     * @param s the string to compare this token to
     *
     * @returns true if the string represents this token, false otherwise
     */
    public boolean equals(String s) {
        return (_text.equals(s));
    }
    
    /** retrieve the text which represents this token
     *
     * @returns a String of text which represents this token
     */
    public String toString() {
        return _text;
    }
    
    /**
    * Class method to check whether or not the given string represents
    * a recognized token in the protocol.
    *
    * @param s the string to match with legal tokens
    *
    * @returns true if there is such a token, otherwise false
    */
    public static boolean isLegalToken(String s) {
        ArrayIterator it = null;
        for (it = new ArrayIterator(_legalTokens, 0); 
             it.hasMoreElements(); it.advance()) {
            if (((ProtocolToken) it.get()).getText().equals(s)) {
                return true;
            }
        }
        return false;
    }
    
    /** class method to retrieve the token which represents the given string.
     * 
     * @param s the string to match with existing tokens
     * 
     * @returns a ProtocolToken representing the string if one exists; otherwise null
     */
    public static ProtocolToken getToken(String s) {
        ArrayIterator it = null;
        for (it = new ArrayIterator(_legalTokens, 0); 
             it.hasMoreElements(); it.advance()) {
            if (((ProtocolToken) it.get()).getText().equals(s)) {
                return ((ProtocolToken) it.get());
            }
        }
        return null;
    }

    
    /**
    * instance method to check whether or not the given string represents
    * a valid parameter list to follow the protocol token.
    *
    * For example, the Content-type token would respond 'true' if asked
    * whether "application/sdp" is a valid parameter, but would respond 
    * 'false' if passed "mjs@cs.columbia.edu."
    */
    public abstract boolean isValidParam(String s);
}