//*****************************************************************************
/*
** FILE:   xe_NamespaceDeclParser.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    31May98  stevew  Created.
*/
package xe;

import xg.xg_Attribute;
import xg.xg_NamespaceDecl;
import xg.xg_Node;

import xa.xa_Keyword;

import eh.eh_Debug;

import java.io.IOException;

//*****************************************************************************
/** Standard parser for a namespace declaration, assuming the beginning
 *  ('<?xml:namespace') has already been parsed. A namespace declaration takes
 *  the following form:
*
*     <?xml:namespace ns = "(Literal)" [src = "(Literal)"] prefix = "(Name)" ?>
*
*   (although the attributes can appear in any order).
*/
public class xe_NamespaceDeclParser extends xe_Parser
{
    //*****************************************************************************
    /** Parse a namespace declaration, putting the result in a newly-created
     *  namespace declaration object.
     *
     *  @return  The parsed namespace declaration
     */
    public xg_Node parse() throws IOException
    {
        eh_Debug.add(5, "xe_NamespaceDeclParser.parse: Start parsing namespace declaration '"
                               + EntityName + "'");

        // Create new namespace declaration object.
        xg_NamespaceDecl  NewNamespaceDecl = (xg_NamespaceDecl)createNode("xg.xg_NamespaceDecl");
//        xg_NamespaceDecl  NewNamespaceDecl
//                           = (xg_NamespaceDecl)TheParseManager.createEntity(EntityName,
//                                                                            EntityType,
//                                                                            "xg.xg_NamespaceDecl",
//                                                                            ParentNode);

        parseAttributes(NewNamespaceDecl);  // Retrieve the attribute name/value pairs
        checkAttributes(NewNamespaceDecl);  // Check the mandatory attributes are present

        TheParseManager.fireEndNodeEvent(NewNamespaceDecl);
        eh_Debug.add(7, "xe_NamespaceDeclParser: Completed parsing Namespace declaration '"
                              + EntityName + "'");
        return NewNamespaceDecl;
    }

    //*****************************************************************************
    /** Parse the attributes of a namespace declaration. Keep looking for
     *  'Name = "Value"' attributes until we encounter '?>'.
     *
     *  @param  InputNamespaceDecl  The namespace declaration currently being parsed
     */
    public void parseAttributes(xg_NamespaceDecl  InputNamespaceDecl) throws IOException
    {
        eh_Debug.add(6, "xe_NamespaceDeclParser.parseAttributes:");

        xe_Token      CurrentToken       = null;
        String        NewAttName         = null;
        xg_Attribute  NewAttribute       = null;
        boolean       MoreAttributesFlag = true;
        boolean       AttAddedFlag       = true;
        while (MoreAttributesFlag)
        {
            CurrentToken = TheParseManager.parseNextToken(true);
            if (CurrentToken.getType() == xe_TokenType.END_OF_SOURCE)
                TheParseManager.throwParseException("Unexpected end of source");
            else if (CurrentToken.getType() == xe_TokenType.PI_END)
            {
                // '?>' means end of namespace declaration.
                MoreAttributesFlag = false;
            }
            else
            {
                // We have the beginning of a new attribute. Parse the rest of it.
                NewAttribute = parseAttribute(CurrentToken);
                NewAttName   = NewAttribute.getName();

                // Only 'ns', 'src' and 'prefix' attributes are allowed.
                if (    !NewAttName.equals(xg_NamespaceDecl.NAMESPACE_NAME_STRING)
                     && !NewAttName.equals(xg_NamespaceDecl.NAMESPACE_PREFIX_STRING)
                     && !NewAttName.equals(xg_NamespaceDecl.NAMESPACE_SOURCE_STRING) )
                    TheParseManager.throwParseException("Attribute '" + NewAttName
                                                           + "' not allowed in namespace declaration");

                // Add this attribute to the new namespace declaration.
                AttAddedFlag = InputNamespaceDecl.addAttribute(NewAttribute);
                if (!AttAddedFlag)
                    TheParseManager.throwParseException("Attribute '" + NewAttName
                                                           + "' declared twice in namespace");
            }
        }
    }

    //*****************************************************************************
    /** Check that the mandatory attributes ('ns' and 'prefix') are present.
     *
     *  @param      InputNamespaceDecl  The namespace declaration currently being
     *                                   parsed
     *  @exception  IOException         An essential attribute is missing
     */
    public void checkAttributes(xg_NamespaceDecl  InputNamespaceDecl) throws IOException
    {
        eh_Debug.add(7, "xe_NamespaceDeclParser.checkAttributes:");

        // Is there an 'ns' attribute?
        xg_Attribute  NamespaceNameAtt
                       = InputNamespaceDecl.getAttribute(xg_NamespaceDecl.NAMESPACE_NAME_STRING);
        if (NamespaceNameAtt == null)
        {
            TheParseManager.throwParseException("Attribute '"
                                                   + xg_NamespaceDecl.NAMESPACE_NAME_STRING
                                                   + "' missing from namespace declaration");
        }

        // Is there a 'prefix' attribute?
        xg_Attribute  PrefixNameAtt
                       = InputNamespaceDecl.getAttribute(xg_NamespaceDecl.NAMESPACE_PREFIX_STRING);
        if (PrefixNameAtt == null)
        {
            TheParseManager.throwParseException("Attribute '"
                                                   + xg_NamespaceDecl.NAMESPACE_PREFIX_STRING
                                                   + "' missing from namespace declaration");
        }
    }

    //*****************************************************************************
    /** Create an attribute based on three parsed tokens, which represent the name,
     *  equals and value parts.
     *
     *  @param  InputNameToken    Token for the name of the attribute
     *  @param  InputEqualsToken  Token for the '=' of the attribute
     *  @param  InputValueToken   Token for the value of the attribute
     */
    public xg_Attribute createAttribute(xe_Token  InputNameToken,
                                        xe_Token  InputEqualsToken,
                                        xe_Token  InputValueToken)
    {
        xg_Attribute  NewAttribute = new xg_Attribute(InputNameToken.getValue(),
                                                      InputEqualsToken.getValue(),
                                                      InputValueToken.getValue() );
        return NewAttribute;
    }
}

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