//*****************************************************************************
/*
** FILE:   xe_EntityDeclParser.java
**
** (c) 1997 Steve Withall.
**
** HISTORY:
**    23Nov97  stevew  Created.
*/
package xe;

//import xg.xg_Dtd;
import xg.xg_EntityDecl;
import xg.xg_ExternalID;
import xg.xg_Node;

import eh.eh_Debug;

import java.io.IOException;

//*****************************************************************************
/**
*  Class xe_EntityDeclParser - parser for an entity declaration within the
*  DTD of an XML document, assuming the beginning ('<!ENTITY') has already
*  been parsed. EntityDecls have the roughly following form:
*
*     <!ENTITY (%) Name "Value" >  - internal
*  or <!ENTITY (%) Name [[SYSTEM "Url" | PUBLIC "Name" "Url"] [NDATA Name]] >
*/
public class xe_EntityDeclParser extends xe_Parser
{
    //*****************************************************************************
    /**
     * Parse the body of an entity declaration.
     *
     * @return  The parsed entity declaration
     */
    public xg_Node parse() throws IOException
    {
        eh_Debug.add(5, "xe_EntityDeclParser.parse: Start parsing EntityDecl");

        // Create new entity declaration object.
        xg_EntityDecl  NewEntityDecl = (xg_EntityDecl)createNode("xg.xg_EntityDecl");
//        xg_EntityDecl  NewEntityDecl
//                         = (xg_EntityDecl)TheParseManager.createEntity(EntityName,
//                                                                       EntityType,
//                                                                       "xg.xg_EntityDecl",
//                                                                       ParentNode);
        // If the next token is '%' then we have a parameter entity.
        xe_Token  CurrentToken = TheParseManager.parseNextToken(true);
        if (CurrentToken.getType() == xe_TokenType.PERCENT_CHAR)
        {
            //TBD
            CurrentToken = TheParseManager.parseNextToken(true);
        }

        // Check the name of this entity declaration.
        EntityName = CurrentToken.getStringValue();
        NewEntityDecl.setName(EntityName);

        // Parse either the value (internal) or external declaration.
        xe_Token  FirstContentToken = TheParseManager.parseNextToken(true);
        switch (FirstContentToken.getType())
        {
            case xe_TokenType.SINGLE_QUOTE_CHAR:
            case xe_TokenType.DOUBLE_QUOTE_CHAR:
                // We have an internal declaration (literal value).
                parseEntityValue(NewEntityDecl, FirstContentToken);
                CurrentToken = TheParseManager.parseNextToken(true);
                break;

            case xe_TokenType.NAME:
                // This indicates an external declaration ("SYSTEM" or "PUBLIC").
                CurrentToken = parseExternalDef(NewEntityDecl, FirstContentToken);
                break;

            default:
                TheParseManager.throwParseException("Illegal value within entity declaration");
                break;
        }

        // The next token has already been parsed; make sure it is the tag end ('>').
        if (CurrentToken.getType() != xe_TokenType.TAG_END_CHAR)
            TheParseManager.throwParseException("Expected tag end ('"
                                                    + xe_TokenType.TAG_END_CHAR
                                                    + "') here");

        eh_Debug.add(7, "xe_EntityDeclParser: End of entity declaration '" + EntityName + "'");
        return NewEntityDecl;
    }

    //*****************************************************************************
    /**
     * This is an internal entity declaration. Parse its value. It should have the
     * rough form:
     *
     *    <!ENTITY (%) Name "Value" >
     *    ==================>
     *
     * @param  InputEntityDecl      The entity declaration currently being parsed
     * @param  InputOpenQuoteToken  The opening quote (either single or double) token
     */
    public void parseEntityValue(xg_EntityDecl  InputEntityDecl,
                                 xe_Token       InputOpenQuoteToken) throws IOException
    {
//        InputEntityDecl.setType(xg_EntityDecl.MIXED_TYPE);

        xe_Token  EntityValueToken = TheParseManager.parseLiteralToken((char)InputOpenQuoteToken.getType());
        //TBD Do something with the value!

        eh_Debug.add(5, "xe_EntityDeclParser.parseEntityValue: Parsed entity value '"
                              + EntityValueToken.getStringValue() + "'");
        return;
    }

    //*****************************************************************************
    /**
     * This is an internal entity declaration. Parse its value, assuming its first
     * token (SYSTEM or PUBLIC) has already been parsed. It should have the form:
     *
     *    SYSTEM "Url"        [NDATA Name]
     * or PUBLIC "Name" "Url" [NDATA Name]
     *    =====>
     *
     * @param  InputEntityDecl  The entity declaration currently being parsed
     * @param  InputStartToken  The first token of the external declaration
     * @return                  The next token after the external declaration
     */
    public xe_Token parseExternalDef(xg_EntityDecl  InputEntityDecl,
                                     xe_Token       InputStartToken) throws IOException
    {
        eh_Debug.add(5, "xe_DtdParser.parseExternalDef:");

        // Parse the ExternalID (the SYSTEM or PUBLIC part).
        xg_ExternalID  NewExternalID = parseExternalID(InputStartToken);

        // Is there an NDATA entry?
        xe_Token CurrentToken = TheParseManager.parseNextToken(true);
        if (    CurrentToken.getType() == xe_TokenType.NAME
             && CurrentToken.getStringValue().compareTo(xe_TokenType.NDATA_STRING) == 0)
        {
            // Parse NDATA Name.
            CurrentToken = TheParseManager.parseNameToken(true);
            //TBD Do something with it!

            // Parse the next token.
            CurrentToken = TheParseManager.parseNextToken(true);
        }

        eh_Debug.add(5, "xe_EntityDeclParser.parseExternalDef: Return");
        return CurrentToken;
    }

    //*****************************************************************************
    /**
     * Parse an external ID. It should have the form:
     *
     *    SYSTEM "Url"
     * or PUBLIC "Name" "Url"
     *
     * @param  InputStartToken  The first token of the external subset
     * @return                  The external ID which has just been parsed
     */
    public xg_ExternalID parseExternalID(xe_Token  InputStartToken) throws IOException
    {
        eh_Debug.add(5, "xe_DtdParser.parseExternalID:");

        // Create a parser for the external ID, and tell it about what it's parsing.
        xe_ExternalIDParser  ExternalIDParser = new xe_ExternalIDParser();
        ExternalIDParser.setParseManager(TheParseManager);
//        NewParser.setEntityType(EntityKeywordDefn.GetType() );
        ExternalIDParser.setEntityName(InputStartToken.getStringValue() );
        ExternalIDParser.setEntityClassName("xg.xg_ExternalID");

        xg_ExternalID  NewExternalID = (xg_ExternalID)ExternalIDParser.parse();

        eh_Debug.add(5, "xe_DtdParser.parseExternalID: Return");
        return NewExternalID;
    }
}

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