//*****************************************************************************
/*
** FILE:   xe_XmlDeclParser.java
**
** (c) 1998 Steve Withall.
**
** HISTORY:
**    18Apr98  stevew  Created.
*/
package xe;

import xg.xg_Attribute;
import xg.xg_Node;
import xg.xg_XmlDecl;

import xa.xa_Keyword;
import xa.xa_StandaloneChoiceList;

import eh.eh_Debug;

import java.io.IOException;

//*****************************************************************************
/** Standard parser for an XML declaration, assuming the beginning ('<?xml')
 *  has already been parsed. An XML declaration takes the following form:
 *
 *    <?xml version = "1.0" [encoding = "Name"] [standalone = "yes|no"] ?>
 */
public class xe_XmlDeclParser extends xe_Parser
{
    static final xa_StandaloneChoiceList StandaloneChoiceList = new xa_StandaloneChoiceList();

    //*****************************************************************************
    /** Parse an XML declaration, putting the result in a newly-created XML
     *  declaration object.
     *
     *  @return  The parsed XML declaration
     */
    public xg_Node parse() throws IOException
    {
        eh_Debug.add(5, "xe_XmlDeclParser.parse: Start parsing XML declaration '" + EntityName + "'");

        // Create new XML declaration object.
        xg_XmlDecl  NewXmlDecl = (xg_XmlDecl)createNode("xg.xg_XmlDecl");
//        xg_XmlDecl  NewXmlDecl = (xg_XmlDecl)TheParseManager.createEntity(EntityName,
//                                                                          EntityType,
//                                                                          "xg.xg_XmlDecl",
//                                                                          ParentNode);

        // Retrieve the attribute name/value pairs.
        parseAttributes(NewXmlDecl);

        TheParseManager.fireEndNodeEvent(NewXmlDecl);
        eh_Debug.add(7, "xe_XmlDeclParser: Completed parsing XML declaration '" + EntityName + "'");
        return NewXmlDecl;
    }

    //*****************************************************************************
    /** Parse the XML declaration, assuming its starting '<?xml' has already been
     *  parsed. It takes the form:
     *
     *    <?xml version = "1.0" [encoding = "Name"] [standalone = "yes|no"] ?>
     *
     * @param  InputNewXmlDecl  The XML declaration currently being parsed
     */
    public void parseAttributes(xg_XmlDecl  InputNewXmlDecl) throws IOException
    {
        eh_Debug.add(5, "xe_DocumentParser.parseAttributes: Parse the XML declaration");

        // Parse 'version = "1.0"'.
        xe_Token  NameToken
                     = TheParseManager.parseNameTokenExpected(xa_Keyword.VERSION_STRING, true);
        xe_Token  EqualsToken = TheParseManager.parseNextTokenExpected(xe_TokenType.EQUALS_CHAR, true);
        xe_Token  ValueToken  = TheParseManager.parseLiteralToken(true);
        InputNewXmlDecl.setVersion(createAttribute(NameToken, EqualsToken, ValueToken) );

        // Parse encoding declaration 'encoding = "Name"' (optional).
        NameToken = TheParseManager.parseNextToken(true);
        if (    NameToken.getType() == xe_TokenType.NAME
             && NameToken.getStringValue().compareTo(xa_Keyword.ENCODING_STRING) == 0)
        {
            EqualsToken = TheParseManager.parseNextTokenExpected(xe_TokenType.EQUALS_CHAR, true);
            ValueToken  = TheParseManager.parseLiteralToken(true);
            InputNewXmlDecl.setEncoding(createAttribute(NameToken, EqualsToken, ValueToken) );

            // Parse the token after the encoding declaration.
            NameToken = TheParseManager.parseNextToken(true);
        }

        // Parse standalone declaration: 'standalone = "yes|no"' (optional).
        if (    NameToken.getType() == xe_TokenType.NAME
             && NameToken.getStringValue().compareTo(StandaloneChoiceList.getName() ) == 0)
        {
            EqualsToken = TheParseManager.parseNextTokenExpected(xe_TokenType.EQUALS_CHAR, true);

            ValueToken = TheParseManager.parseLiteralToken(true);
            String  StandaloneValue = ValueToken.getStringValue();
            if (!StandaloneChoiceList.hasChoice(StandaloneValue) )
                TheParseManager.throwParseException("Expected 'standalone' value to be 'yes' or 'no', but found '"
                                                        + StandaloneValue + "' instead");
            InputNewXmlDecl.setStandalone(createAttribute(NameToken, EqualsToken, ValueToken) );

            // Parse the token after the encoding declaration.
            NameToken = TheParseManager.parseNextToken(true);
            if (NameToken.getType() != xe_TokenType.PI_END)
                TheParseManager.throwParseException("Expected end of XML declaration, but found '"
                                                        + NameToken + "'");
        }

        if (NameToken.getType() != xe_TokenType.PI_END)
            TheParseManager.throwParseException("Unexpected value '"
                                                    + NameToken
                                                    + "' in XML declaration");

        // Store whitespace preceding the end.
        InputNewXmlDecl.setWhitespacePrecedingEnd(NameToken.getPrecedingWhitespace() );
        return;
    }

    //*****************************************************************************
    /** 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();
        NewAttribute.setPrecedingWhitespace(InputNameToken.getPrecedingWhitespace() );
        NewAttribute.setName(InputNameToken.getStringValue() );
        NewAttribute.setWhitespaceBeforeEquals(InputEqualsToken.getPrecedingWhitespace() );
        NewAttribute.setWhitespaceAfterEquals(InputValueToken.getPrecedingWhitespace() );
        NewAttribute.setValue(InputValueToken.getStringValue() );
        return NewAttribute;
    }
}

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