//*****************************************************************************
/*
** FILE:   xm_NodeTypeRegistry.java
**
** (c) 1997, 1998 Steve Withall.
**
** HISTORY:
**    08Jun98  stevew  Created, based on xe_Keyword.
**    03Jul98  stevew  Moved from xe to xm.
**    24Jul98  stevew  Added ViewClassName.
*/
package xm;

import xa.xa_NodeTypeChoiceList;

import eh.eh_Debug;

import java.util.Enumeration;
import java.util.Hashtable;

//*****************************************************************************
/** A registry of all known node, parser, customizer and view classes. It can
 *  be consulted to find the classes suitable for a particular type of node.
 *  The main xg, xe and xc classes for the standard XML types are automatically
 *  registered by calling the initialise() method. Non-standard types can be
 *  registered by calling the register() method.</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 xm_NodeTypeRegistry
//public class xm_NodeTypeRegistry extends xa_Keyword
{
    // Special values.
    /** Unknown keyword type */
    public final static int UNKNOWN         =  -1;

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

    /** Hashtable used to find a node definition given a string value. */
    private static Hashtable  NameHashtable = null;

    /** Default for the name of the class used to parse nodes of this type, if
     *  it is not explicitly given. This attribute is implemented purely for the
     *  convenience of callers: so they do not have to repeatedly pass the same
     *  values when registering a number of elements. */
    private static String     DefaultParserClassName     = null;

    /** Default for the name of the class used for customizing (on-screen editing
     *  of) nodes of this type. Implemented for the same reason as
     *  DefaultParserClassName. */
    private static String     DefaultCustomizerClassName = null;

    /** Default for the name of the class used for displaying nodes of this type.
     *  Implemented for the same reason as DefaultParserClassName. */
    private static String     DefaultViewClassName = null;

    //*****************************************************************************
    /** Convert to a string the node type definition whose type is InputNodeType.
     *
     *  @param   InputNodeType  The type of node for which we want a string
     *                           representation
     *  @return  String value or null
     */
    static public String toString(int  InputNodeType)
    {
        if (TypeHashtable == null)
            initialise();

        String  FoundString = null;
        xm_NodeTypeDefn  FoundDefn = getDefn(InputNodeType);
        if (FoundDefn == null)
            FoundString = "Type " + InputNodeType;
        else
            FoundString = FoundDefn.getTypeString();
        return FoundString;
    }

    //*****************************************************************************
    /** Convert to a type the node type whose name is InputKeywordValue.
     *
     *  @param   InputNodeTypeName  Node type name
     *  @return  Node type (or -1 if this is an unknown type)
     */
    static public int convertToType(String  InputNodeTypeName)
    {
        xm_NodeTypeDefn  FoundDefn    = getDefn(InputNodeTypeName);
        int              FoundTypeInt = UNKNOWN;
        if (FoundDefn != null)
            FoundTypeInt = FoundDefn.getType();
//        eh_Debug.add(9, "xm_NodeTypeRegistry.convertToType: Keyword '"
//                              + InputNodeTypeName + "' has type " + FoundTypeInt);
        return FoundTypeInt;
    }

    //*****************************************************************************
    /** Set the default name of the class used to parse nodes.
     *
     *  @param  InputDefaultParserClassName  Default name of parser class
     */
    static public void setDefaultParserClassName(String  InputDefaultParserClassName)
    {
        DefaultParserClassName = InputDefaultParserClassName;
    }

    //*****************************************************************************
    /** Set the default name of the class used to customize nodes.
     *
     *  @param  InputDefaultCustomizerClassName   Default name of customizer class
     */
    static public void setDefaultCustomizerClassName(String  InputDefaultCustomizerClassName)
    {
        DefaultCustomizerClassName = InputDefaultCustomizerClassName;
    }

    //*****************************************************************************
    /** Set the default name of the class used to display nodes.
     *
     *  @param  InputDefaultViewClassName  Default name of view class
     */
    static public void setDefaultViewClassName(String  InputDefaultViewClassName)
    {
        DefaultViewClassName = InputDefaultViewClassName;
    }

    //*****************************************************************************
    /** Get the node type definition of the node whose name is InputNodeTypeName. If
     *  this does not exist, try finding a definition for the InputNodeType.
     *
     *  @param   InputNodeName  Node type name
     *  @param   InputNodeType  Node type code
     *  @return  Node type definition
     */
    static public xm_NodeTypeDefn getDefn(String  InputNodeName,
                                          int     InputNodeType)
    {
        xm_NodeTypeDefn  RequestedNodeDefn = getDefn(InputNodeName);
        if (RequestedNodeDefn == null)
            // No entry for this node name - so get one for this node type.
            RequestedNodeDefn = getDefn(InputNodeType);

        return RequestedNodeDefn;
    }

    //*****************************************************************************
    /** Get the node type definition of the node whose name is InputNodeTypeName.
     *
     *  @param   InputNodeName  Node type name
     *  @return  Node type definition
     */
    static public xm_NodeTypeDefn getDefn(String  InputNodeTypeName)
    {
        if (NameHashtable == null)
            initialise();

        xm_NodeTypeDefn  FoundDefn = null;
        if (InputNodeTypeName != null)
            FoundDefn = (xm_NodeTypeDefn)NameHashtable.get(InputNodeTypeName);

        return FoundDefn;
    }

    //*****************************************************************************
    /** Get the node type definition of the node whose type is InputNodeTypeName.
     *
     *  @param   InputNodeType Node type code
     *  @return  Node type definition
     */
    static public xm_NodeTypeDefn getDefn(int  InputNodeType)
    {
        if (TypeHashtable == null)
            initialise();

        return (xm_NodeTypeDefn)TypeHashtable.get(new Integer(InputNodeType) );
    }

    //*****************************************************************************
    /** Get the Hashtable of standard XML node types.
     *
     *  @return  Hashtable of standard types
     */
    static Hashtable getTypeHashtable()
    {
        return TypeHashtable;
    }

    //*****************************************************************************
    /** Get the Hashtable of special XML element names registered.
     *
     *  @return  Hashtable of special named types
     */
    static Hashtable getNameHashtable()
    {
        return NameHashtable;
    }

    //*****************************************************************************
    /** Get the default name of the class used to parse nodes.
     *
     *  @return  Default name of parser class
     */
    static public String getDefaultParserClassName()
    {
        return DefaultParserClassName;
    }

    //*****************************************************************************
    /** Get the default name of the class used to customize nodes.
     *
     *  @return  Default name of customizer class
     */
    static public String getDefaultCustomizerClassName()
    {
        return DefaultCustomizerClassName;
    }

    //*****************************************************************************
    /** Get the default name of the class used to display nodes.
     *
     *  @return   Default name of view class
     */
    static public String getDefaultViewClassName()
    {
        return DefaultViewClassName;
    }

    //*****************************************************************************
    /** Ensure the hashtables of the keywords 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 keywords with their definitions.
     */
    static public void initialise()
    {
//        eh_Debug.add(7, "xm_NodeTypeRegistry.initialise:");
        TypeHashtable = new Hashtable();
        NameHashtable = new Hashtable();

        //       Type
        //       Description
        //       Object class
        //       Parser class
        //       Customizer class
        //       View class
        register(xa_NodeTypeChoiceList.DOCUMENT_TYPE,
                 xa_NodeTypeChoiceList.DOCUMENT_STRING,
                 "xg.xg_Document",
                 "xe.xe_DocumentParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewY");
        register(xa_NodeTypeChoiceList.ELEMENT_TYPE,
                 xa_NodeTypeChoiceList.ELEMENT_STRING,
                 "xg.xg_Element",
                 "xe.xe_ElementParser",
                 "xc.xc_ElementCustomizer",
                 "xv.xv_BoxViewX");
        // xa_NodeTypeChoiceList.ATTRIBUTE_TYPE not registered. (This is defined
        // in the DOM, but is not parsed as a separate type by xe.)
        register(xa_NodeTypeChoiceList.PI_TYPE,
                 xa_NodeTypeChoiceList.PI_STRING,
                 "xg.xg_PI",
                 "xe.xe_PIParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_LabelView");
        register(xa_NodeTypeChoiceList.COMMENT_TYPE,
                 xa_NodeTypeChoiceList.COMMENT_STRING,
                 "xg.xg_Comment",
                 "xe.xe_CommentParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_LabelView");
        register(xa_NodeTypeChoiceList.TEXT_TYPE,
                 xa_NodeTypeChoiceList.TEXT_STRING,
                 "xg.xg_Text",
                 null,
                 "xc.xc_NodeCustomizer",
                 "xv.xv_LabelView");
//                 "com.sun.java.swing.text.LabelView");
        register(xa_NodeTypeChoiceList.CDATA_TYPE,
                 xa_NodeTypeChoiceList.CDATA_STRING,
                 "xg.xg_Cdata",
                 "xe.xe_CdataParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_LabelView");
        register(xa_NodeTypeChoiceList.XML_DECL_TYPE,
                 xa_NodeTypeChoiceList.XML_DECL_STRING,
                 "xg.xg_XmlDecl",
                 "xe.xe_XmlDeclParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
        register(xa_NodeTypeChoiceList.NAMESPACE_DECL_TYPE,
                 xa_NodeTypeChoiceList.NAMESPACE_DECL_STRING,
                 "xg.xg_NamespaceDecl",
                 "xe.xe_NamespaceDeclParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
        register(xa_NodeTypeChoiceList.DOCTYPE_DECL_TYPE,
                 xa_NodeTypeChoiceList.DOCTYPE_DECL_STRING,
                 "xg.xg_Dtd",
                 "xe.xe_DtdParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
        register(xa_NodeTypeChoiceList.ATTLIST_DECL_TYPE,
                 xa_NodeTypeChoiceList.ATTLIST_DECL_STRING,
                 "xg.xg_AttListDecl",
                 "xe.xe_AttListDeclParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
        register(xa_NodeTypeChoiceList.ENTITY_DECL_TYPE,
                 xa_NodeTypeChoiceList.ENTITY_DECL_STRING,
                 "xg.xg_EntityDecl",
                 "xe.xe_EntityDeclParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
        register(xa_NodeTypeChoiceList.ELEMENT_DECL_TYPE,
                 xa_NodeTypeChoiceList.ELEMENT_DECL_STRING,
                 "xg.xg_ElementDecl",
                 "xe.xe_ElementDeclParser",
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
        register(xa_NodeTypeChoiceList.NOTATION_DECL_TYPE,
                 xa_NodeTypeChoiceList.NOTATION_DECL_STRING,
                 "xg.xg_NotationDecl",
                 null,
                 "xc.xc_NodeCustomizer",
                 "xv.xv_BoxViewX");
    }

    //*****************************************************************************
    /** Register a node name. This is a convenience function, intended to be used
     *  when registering special types of nodes, to save having to specify the
     *  values commonly used for such nodes.
     *
     *  @param  InputNodeName            The string value of this keyword - also
     *                                    used for type of this keyword
     *  @param  InputNodeTypeString      String representation of keyword type
     *  @param  InputEntityClassName     Name of the class used to represent
     *                                    entities of this type
     *  @return The node type definition registered
     */
    static public xm_NodeTypeDefn register(String   InputNodeName,
                                           String   InputEntityClassName)
    {
        return(register(InputNodeName,
                        xm_NodeTypeRegistry.UNKNOWN,
                        InputNodeName,
                        InputEntityClassName,
                        DefaultParserClassName,
                        DefaultCustomizerClassName,
                        DefaultViewClassName) );
    }

    //*****************************************************************************
    /** Register a node name. This is a convenience function, intended to be used
     *  when registering special types of nodes, to save having to specify the
     *  values commonly used for such nodes.
     *
     *  @param  InputNodeName            The string value of this keyword - also used
     *                                    for type of this keyword
     *  @param  InputNodeTypeString      Description of node type
     *  @param  InputEntityClassName     Name of the class used to represent entities
     *                                    of this type
     *  @return The node type definition registered
     */
    static public xm_NodeTypeDefn register(String   InputNodeName,
                                           String   InputNodeTypeString,
                                           String   InputEntityClassName)
    {
        return(register(InputNodeName,
                        xm_NodeTypeRegistry.UNKNOWN,
                        InputNodeTypeString,
                        InputEntityClassName,
                        DefaultParserClassName,
                        DefaultCustomizerClassName,
                        DefaultViewClassName) );
    }

    //*****************************************************************************
    /** Register a node name. This is a convenience function, intended to be used
     *  when registering special types of nodes, to save having to specify the values
     *  commonly used for such nodes.
     *
     *  @param  InputNodeName            The string value of this keyword - also used
     *                                    for type of this keyword
     *  @param  InputNodeTypeString      String representation of keyword type
     *  @param  InputEntityClassName     Name of the class used to represent entities
     *                                    of this type
     *  @param  InputParserClassName     Name of the class used to parse entities of
     *                                    this type
     *  @param  InputCustomizerClassName Name of the class used to customize entities
     *                                    of this type
     *  @param  InputViewClassName       Name of the class used to display entities of
     *                                    this type
     *  @return The node type definition registered
     */
    static public xm_NodeTypeDefn register(String   InputNodeName,
                                           String   InputEntityClassName,
                                           String   InputParserClassName,
                                           String   InputCustomizerClassName,
                                           String   InputViewClassName)
    {
        return(register(InputNodeName,
                        xm_NodeTypeRegistry.UNKNOWN,
                        InputNodeName,
                        InputEntityClassName,
                        InputParserClassName,
                        InputCustomizerClassName,
                        InputViewClassName) );
    }

    //*****************************************************************************
    /** Register a node type - without a node name.
     *
     *  @param  InputNodeType            Type of this node
     *  @param  InputNodeTypeString      String representation of node type
     *  @param  InputEntityClassName     Name of the class used to represent nodes
     *                                    of this type
     *  @param  InputParserClassName     Name of the class used to parse nodes of
     *                                    this type
     *  @param  InputCustomizerClassName Name of the class used to customize nodes
     *                                    of this type
     *  @param  InputViewClassName       Name of the class used to display entities of
     *                                    this type
     *  @return The node type definition registered
     */
    static protected xm_NodeTypeDefn register(int      InputNodeType,
                                              String   InputNodeTypeString,
                                              String   InputEntityClassName,
                                              String   InputParserClassName,
                                              String   InputCustomizerClassName,
                                              String   InputViewClassName)
    {
        return(register(null,
                        InputNodeType,
                        InputNodeTypeString,
                        InputEntityClassName,
                        InputParserClassName,
                        InputCustomizerClassName,
                        InputViewClassName) );
    }

    //*****************************************************************************
    /** Register a node type.
     *
     *  @param  InputNodeName            The name of this node type
     *  @param  InputNodeType            Type of this node
     *  @param  InputNodeTypeString      String representation of node type
     *  @param  InputEntityClassName     Name of the class used to represent nodes
     *                                    of this type
     *  @param  InputParserClassName     Name of the class used to parse nodes of
     *                                    this type
     *  @param  InputCustomizerClassName Name of the class used to customize nodes
     *                                    of this type
     *  @param  InputViewClassName       Name of the class used to display entities
     *                                    of this type
     *  @return The node type definition registered
     */
    static public xm_NodeTypeDefn register(String   InputNodeName,
                                           int      InputNodeType,
                                           String   InputNodeTypeString,
                                           String   InputEntityClassName,
                                           String   InputParserClassName,
                                           String   InputCustomizerClassName,
                                           String   InputViewClassName)
    {
//        eh_Debug.add(7, "xm_NodeTypeRegistry.Register: " + InputNodeName);
        xm_NodeTypeDefn  NewDefn = new xm_NodeTypeDefn(InputNodeName,
                                                       InputNodeType,
                                                       InputNodeTypeString,
                                                       InputEntityClassName,
                                                       InputParserClassName,
                                                       InputCustomizerClassName,
                                                       InputViewClassName);
        Integer  KeywordTypeObject = new Integer(InputNodeType);

        if (InputNodeType != UNKNOWN)
            TypeHashtable.put(KeywordTypeObject, NewDefn);

        if (InputNodeName != null)
            NameHashtable.put(InputNodeName, NewDefn);

        return NewDefn;
    }

    //*****************************************************************************
    /** Output a list of all registered node types to debug.
     */
    static public void listToDebug()
    {
        // List the standard types.
        eh_Debug.add(1, "The standard XML node types currently registered are:");
        listHashtableToDebug(TypeHashtable);

        // List the non-standard types.
        eh_Debug.add(1, "The non-standard XML node types currently registered are:");
        listHashtableToDebug(NameHashtable);
    }

    //*****************************************************************************
    /** Output a list of all the registered node types in the given hash table to
     *  debug.
     *
     *  @param  InputHashtable  The hash table whose entries are to be listed
     */
    static protected void listHashtableToDebug(Hashtable  InputHashtable)
    {
        eh_Debug.incrementIndentLevel();
        eh_Debug.add(1, "Name, Type, Description, Node class, Parser class, Customizer class, View class");

        xm_NodeTypeDefn  CurrentDefn         = null;
        Enumeration      RegistryEnumeration = InputHashtable.elements();

        while (RegistryEnumeration.hasMoreElements() )
        {
            CurrentDefn = (xm_NodeTypeDefn)RegistryEnumeration.nextElement();
            CurrentDefn.listToDebug();
        }

        eh_Debug.decrementIndentLevel();
    }
}

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