//*****************************************************************************
/*
** FILE:   xe_TokenType.java
**
** (c) 1997, 1998 Steve Withall.
**
** HISTORY:
**    18Oct97  stevew  Created.
**    08Jun98  stevew  Renamed from xe_Keyword.
*/
package xe;

import xa.xa_Keyword;
import xa.xa_NodeTypeChoiceList;

//import eh.eh_Debug;  //TEMP
import java.util.Hashtable;

//*****************************************************************************
/**
*  <p>Class xe_TokenType - A utility class which knows about all the standard
*  XML keywords, and provides a range of manipulation methods for them.</p>
*
*  <p>It is expected that this class will normally be used statically: that
*  instances will typically not be created. (They are not much use if
*  instantiated anyway: they have no data attributes.)</p>
*/
public class xe_TokenType extends xa_Keyword
{
    /** Constants for the standard XML keywords. (See also the constants
     *  defined in the base class xa_Keyword.) */
//    public final static int FIXED                = 128;  /** #FIXED */
//    public final static int IMPLIED              = 129;  /** #IMPLIED */
//    public final static int PCDATA_DECL          = 130;  /** #PCDATA */
//    public final static int REQUIRED             = 131;  /** #REQUIRED */
    public final static int PE_REFERENCE         = 132;  /** %name */
    public final static int ENTITY_REFERENCE     = 133;  /** &name */
    public final static int CHAR_REFERENCE_DEC   = 134;  /** &#number */
    public final static int CHAR_REFERENCE_HEX   = 135;  /** &#xnumber */
    public final static int COMMENT_END          = 136;  /** --> */
    public final static int EMPTY_TAG_END        = 137;  /** /> */
    public final static int COMMENT_START        = 138;  /** <!-- */
    public final static int CDATA_START          = 139;  /** <![CDATA[ */
    public final static int ATTLIST_DECL_START   = 140;  /** <!ATTLIST */
    public final static int DOCTYPE_START        = 141;  /** <!DOCTYPE */
    public final static int ELEMENT_DECL_START   = 142;  /** <!ELEMENT */
    public final static int ENTITY_DECL_START    = 143;  /** <!ENTITY */
    public final static int NOTATION_DECL_START  = 144;  /** <!NOTATION */
    public final static int END_TAG_START        = 145;  /** </name */
    public final static int PI_START             = 146;  /** <? */
    public final static int XML_DECL_START       = 147;  /** <?xml */
    public final static int NAMESPACE_DECL_START = 148;  /** <?xml:namespace */
    public final static int ELEMENT_START        = 149;  /** <name */
    public final static int PI_END               = 150;  /** ?> */
    public final static int CDATA_END            = 151;  /** ]]> */
//    public final static int ANY                  = 152;  /** ANY */
//    public final static int EMPTY                = 153;  /** EMPTY */
//    public final static int ID                   = 154;  /** ID */
//    public final static int IGNORE               = 158;  /** IGNORE */
//    public final static int INCLUDE              = 159;  /** INCLUDE */

    // Token types which do not have clearly-defined values.
    public final static int LITERAL             = 167;  /** A literal string */
    public final static int NAME                = 168;  /** Name */
    public final static int NUMBER              = 169;  /** Numeric value */
    public final static int PCDATA              = 170;  /** Text */

    // Special values.
    public final static int END_OF_SOURCE       = 199;  /** End of source */
    public final static int UNKNOWN             =  -1;  /** Unknown keyword type */

    /** If a keyword can have further characters added to form another keyword
     *  ('more'), one of these values are used to specify what sorts of
     *  characters may follow. */
    public final static int NO_MORE      = 0;  /** No more may follow */
    public final static int MORE_SPECIAL = 1;  /** Special characters follow */
    public final static int MORE_NAME    = 2;  /** A name follows */
    public final static int MORE_NUMBER  = 3;  /** A number follows */
    public final static int MORE_ANY     = 4;  /** Anything may follow */

    // Data attributes.
    /** Hashtable used to find a token type definition given an integer type. */
    private static Hashtable  TypeHashtable  = null;

    /** Hashtable used to find a token type definition given a string value. */
    private static Hashtable  ValueHashtable = null;

    //*****************************************************************************
    /**
     * Convert to a string the token whose type is InputTokenType.
     *
     * @return  String value or null
     */
    static public String toString(int  InputTokenType)
    {
        if (TypeHashtable == null)
            initialise();

        String  FoundString = null;
        if (InputTokenType == UNKNOWN)
            FoundString = "unknown type";
        else
        {
            xe_TokenTypeDefn  FoundDefn = getDefn(InputTokenType);
            if (FoundDefn == null)
                FoundString = "Type " + InputTokenType;
            else
                FoundString = FoundDefn.getTypeString();
        }
        return FoundString;
    }

    //*****************************************************************************
    /**
     * Convert to a type the token type whose string value is InputTokenValue.
     *
     * @param   Keyword string
     * @return  Keyword type
     */
    static public int convertToType(String  InputTokenValue)
    {
        xe_TokenTypeDefn  FoundDefn    = getDefn(InputTokenValue);
        int               FoundTypeInt = UNKNOWN;
        if (FoundDefn != null)
            FoundTypeInt = FoundDefn.getType();
//        eh_Debug.add(9, "xe_TokenType.convertToType: Keyword '" + InputTokenValue
//                              + "' has type " + FoundTypeInt);
        return FoundTypeInt;
    }

    //*****************************************************************************
    /**
     * Get the token type definition of the token whose type is InputTokenValue.
     *
     * @param   InputTokenType  Token type
     * @return  Token type definition
     */
    static public xe_TokenTypeDefn getDefn(int  InputTokenType)
    {
        if (TypeHashtable == null)
            initialise();

        return (xe_TokenTypeDefn)TypeHashtable.get(new Integer(InputTokenType) );
    }

    //*****************************************************************************
    /**
     * Get the token type definition of the token whose string value is
     * InputTokenValue.
     *
     * @param   InputTokenValue Token value string
     * @return  Token type definition
     */
    static public xe_TokenTypeDefn getDefn(String  InputTokenValue)
    {
        if (ValueHashtable == null)
            initialise();

        return (xe_TokenTypeDefn)ValueHashtable.get(InputTokenValue);
    }

    //*****************************************************************************
    /**
     * Ensure the hashtables of the token types are initialised with their definitions
     * (ie. if they aren't, then initialise them).
     */
    static public void ensureInitialised()
    {
        if (TypeHashtable == null)
            initialise();
    }

    //*****************************************************************************
    /**
     * Initialise the hashtables of the token types with their definitions.
     */
    static public void initialise()
    {
//        eh_Debug.add(7, "xe_TokenType.initialise:");
        TypeHashtable  = new Hashtable();
        ValueHashtable = new Hashtable();

        //       Name          Type                 Description           Valid?  More?
        //              Node type
        register("\"",         DOUBLE_QUOTE_CHAR,   "DOUBLE_QUOTE_CHAR",  true,  NO_MORE, 0);
        register("#",          HASH_CHAR,           "HASH_CHAR",          true,  MORE_NAME, 0);
//        register("#FIXED",     FIXED,               "FIXED",              true,  NO_MORE, 0);
//        register("#IMPLIED",   IMPLIED,             "IMPLIED",            true,  NO_MORE, 0);
//        register("#PCDATA",    PCDATA_DECL,         "PCDATA_DECL",        true,  NO_MORE, 0);
//        register("#REQUIRED",  REQUIRED,            "REQUIRED",           true,  NO_MORE, 0);
        register("%",          PERCENT_CHAR,        "PERCENT_CHAR",       true,  MORE_NAME, 0);
        register("&",          AMPERSAND_CHAR,      "AMPERSAND_CHAR",     true,  MORE_ANY, 0);
        register("&#",         UNKNOWN,             "UNKNOWN",            false, MORE_NUMBER, 0);
        register("\'",         SINGLE_QUOTE_CHAR,   "SINGLE_QUOTE_CHAR",  true,  NO_MORE, 0);
        register("(",          OPEN_PAREN_CHAR,     "OPEN_PAREN_CHAR",    true,  NO_MORE, 0);
        register(")",          CLOSE_PAREN_CHAR,    "CLOSE_PAREN_CHAR",   true,  NO_MORE, 0);
        register("*",          STAR_CHAR,           "STAR_CHAR",          true,  NO_MORE, 0);
        register("+",          PLUS_CHAR,           "PLUS_CHAR",          true,  NO_MORE, 0);
        register(",",          COMMA_CHAR,          "COMMA_CHAR",         true,  NO_MORE, 0);
        register("-",          DASH_CHAR,           "DASH_CHAR",          true,  MORE_SPECIAL, 0);
        register("--",         UNKNOWN,             "UNKNOWN",            false, MORE_SPECIAL, 0);
        register("-->",        COMMENT_END,         "COMMENT_END",        true,  NO_MORE, 0);
        register("/",          SLASH_CHAR,          "SLASH_CHAR",         true,  MORE_SPECIAL, 0);
        register("/>",         EMPTY_TAG_END,       "EMPTY_TAG_END",      true,  NO_MORE, 0);
        register("|",          OR_CHAR,             "OR_CHAR",            true,  MORE_SPECIAL, 0);
        register("<",          TAG_START_CHAR,      "TAG_START_CHAR",     true,  MORE_SPECIAL, 0);
        register("<!",         UNKNOWN,             "UNKNOWN",            false, MORE_ANY, 0);
        register("<!-",        UNKNOWN,             "UNKNOWN",            false, MORE_SPECIAL, 0);
        register("<!--",       COMMENT_START,       "COMMENT_START",      true,  NO_MORE,
                        xa_NodeTypeChoiceList.COMMENT_TYPE);
        register("<![",        UNKNOWN,             "UNKNOWN",            false, MORE_NAME, 0);
        register("<![CDATA",   UNKNOWN,             "UNKNOWN",            true,  MORE_SPECIAL, 0);
        register("<![CDATA[",  CDATA_START,         "CDATA_START",        true,  NO_MORE,
                        xa_NodeTypeChoiceList.CDATA_TYPE);
        register("<!ATTLIST",  ATTLIST_DECL_START,  "ATTLIST_DECL_START", true,  NO_MORE,
                        xa_NodeTypeChoiceList.ATTLIST_DECL_TYPE);
        register("<!DOCTYPE",  DOCTYPE_START,       "DOCTYPE_START",      true,  NO_MORE,
                        xa_NodeTypeChoiceList.DOCTYPE_DECL_TYPE);
        register("<!ELEMENT",  ELEMENT_DECL_START,  "ELEMENT_DECL_START", true,  NO_MORE,
                        xa_NodeTypeChoiceList.ELEMENT_DECL_TYPE);
        register("<!ENTITY",   ENTITY_DECL_START,   "ENTITY_DECL_START",  true,  NO_MORE,
                        xa_NodeTypeChoiceList.ENTITY_DECL_TYPE);
        register("<!NOTATION", NOTATION_DECL_START, "NOTATION_START",     true,  NO_MORE,
                        xa_NodeTypeChoiceList.NOTATION_DECL_TYPE);
        register("</",         END_TAG_START,       "END_TAG_START",      false, NO_MORE, 0);
        register("<?",         PI_START,            "PI_START",           true,  MORE_NAME,
                        xa_NodeTypeChoiceList.PI_TYPE);
        register("<?" + XML_STRING,
                               XML_DECL_START,      "XML_DECL_START",     true,  NO_MORE,
                        xa_NodeTypeChoiceList.XML_DECL_TYPE);
        register("<?xml:namespace",
                               NAMESPACE_DECL_START, "NAMESPACE_DECL_START", true,  NO_MORE,
                        xa_NodeTypeChoiceList.NAMESPACE_DECL_TYPE);
        register("=",          EQUALS_CHAR,         "EQUALS_CHAR",        true,  NO_MORE, 0);
        register(">",          TAG_END_CHAR,        "TAG_END_CHAR",       true,  NO_MORE, 0);
        register("?",          QUESTION_MARK_CHAR,  "QUESTION_MARK_CHAR", true,  MORE_SPECIAL, 0);
        register("?>",         PI_END,              "PI_END",             true,  NO_MORE, 0);
        register("[",          OPEN_BRACKET_CHAR,   "OPEN_BRACKET_CHAR",  true,  NO_MORE, 0);
        register("]",          CLOSE_BRACKET_CHAR,  "CLOSE_BRACKET_CHAR", true,  MORE_SPECIAL, 0);
        register("]]",         UNKNOWN,             "UNKNOWN",            true,  MORE_SPECIAL, 0);
        register("]]>",        CDATA_END,           "CDATA_END",          true,  NO_MORE, 0);
//        register("ANY",        ANY,                 "ANY",                true,  NO_MORE, 0);
//        register("EMPTY",      EMPTY,               "EMPTY",              true,  NO_MORE, 0);
//        register("IGNORE",     IGNORE,              "IGNORE",             true,  NO_MORE, 0);
//        register("INCLUDE",    INCLUDE,             "INCLUDE",            true,  NO_MORE, 0);

        // Keywords with null names are artificial. They are never actually parsed,
        // but they are accessed via the keyword type (int) in order to retrieve
        // their definition (for a string representation of them, if nothing else).
        register(null,         ELEMENT_START,      "ELEMENT_START",      true,  NO_MORE,
                        xa_NodeTypeChoiceList.ELEMENT_TYPE);
        register(null,         NAME,               "NAME",               true,  NO_MORE, 0);
        register(null,         END_OF_SOURCE,      "END_OF_SOURCE",      false, NO_MORE, 0);
        register(null,         UNKNOWN,            "UNKNOWN",            false, NO_MORE, 0);
    }

    //*****************************************************************************
    /**
     * Register a token type.
     *
     * @param  InputTokenValue       The string value of this token
     * @param  InputTokenType        Type of this token
     * @param  InputTokenTypeString  String representation of token type
     * @param  InputValidTokenFlag   If we parsed this value, could it be
     *                                considered a valid token?
     * @param  InputMoreControl      Are there other token types which begin with this
     *                                string value? The allowed values are: NO_MORE,
     *                                MORE_SPECIAL, MORE_NAME, MORE_NUMBER, MORE_ANY.
     * @param  InputNodeType         Type of the node for which this is the opening
     *                                token (or 0 if it is not the beginning of a
     *                                node)
     */
    static protected void register(String   InputTokenValue,
                                   int      InputTokenType,
                                   String   InputTokenTypeString,
                                   boolean  InputValidTokenFlag,
                                   int      InputMoreControl,
                                   int      InputNodeType)
    {
//        eh_Debug.add(7, "xe_TokenType.Register: " + InputTokenValue);  //TEMP
        xe_TokenTypeDefn  NewDefn = new xe_TokenTypeDefn(InputTokenValue,
                                                         InputTokenType,
                                                         InputTokenTypeString,
                                                         InputNodeType,
                                                         InputValidTokenFlag,
                                                         InputMoreControl);
        Integer  TokenTypeObject = new Integer(InputTokenType);

        if (InputTokenType != UNKNOWN)
            TypeHashtable.put(TokenTypeObject, NewDefn);

        if (InputTokenValue != null)
            ValueHashtable.put(InputTokenValue, NewDefn);
    }
}

//*****************************************************************************
