//*****************************************************************************
/*
** FILE:   xe_XmlEngine.java
**
** (c) 1997, 1998 Steve Withall.
**
** HISTORY:
**    05Oct97  stevew  Created.
**    06Apr98  stevew  Added xe_ParseListener.
**    03Jul98  stevew  Removed code now inherited from new base class xm_XmlEngine.
*/
package xe;

import xm.xm_NodeTypeRegistry;
import xm.xm_ParseException;
import xm.xm_ParseListener;
import xm.xm_XmlEngine;

import xg.xg_Document;
import xg.xg_Node;

import eh.eh_Debug;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

//*****************************************************************************
/** Engine for processing an XML source.
 *
 *  Given the name of an XML file, initiate the parsing of it, and return a tree
 *  of xg_Node-derived classes representing it. The root xg_Node will currently
 *  always be an xg_Document, but xg_Node is used so that in future we may be
 *  able to parse partial documents.
 */
public class xe_XmlEngine extends xm_XmlEngine
{
    /** The manager of the parse process: recording state and performing all the
     *  low-level parsing. */
    xe_ParseManager  TheParseManager = new xe_ParseManager();

    //*****************************************************************************
    /** Constructor.
     */
    public xe_XmlEngine()
    {
        super();
        xe_TokenType.ensureInitialised();
    }

    //*****************************************************************************
    /** Parse the source supplied by the InputSourceReader.
     *
     *  @param      InputSourceReader  The reader from which to read the XML source
     *  @param      OutputDocument     Document into which to place the parse results
     *  @return                        The xg_Node representing the parse results
     *  @exception  xm_ParseException  The XML source contains an error
     *  @exception  IOException        An error occurred reading from InputSourceReader
     */
    public xg_Node parseSource(Reader       InputSourceReader,
                               xg_Document  OutputDocument) throws xm_ParseException,
                                                                   IOException
    {
        long               StartTime          = System.currentTimeMillis();
        xe_DocumentParser  MainDocumentParser = new xe_DocumentParser();
        MainDocumentParser.setParseManager(TheParseManager);

        TheParseManager.setSource(InputSourceReader);

        try
        {
            if (OutputDocument == null)
                MainDocumentParser.parse();
            else
                MainDocumentParser.parse(OutputDocument);
        }
        catch (xm_ParseException InputException)
        {
            eh_Debug.add(2, "Error in XML source.");
            StatusMessage = InputException.getMessage();
            eh_Debug.add(2, "  " + StatusMessage);
            eh_Debug.add(2, "  Exception = " + InputException.getMessage2() );
            eh_Debug.add(3, "Parse unsuccessful after parsing "
                                       + getParseStatsText(StartTime));
            throw(InputException);
        }
        catch (IOException InputException)
        {
            StatusMessage = new String("Unexpected error parsing XML source: " + InputException);
            eh_Debug.add(2, "Unexpected error parsing XML source.");
            eh_Debug.add(2, "  Exception = " + InputException.toString());
            InputException.printStackTrace();
            eh_Debug.add(3, "Parse unsuccessful after parsing "
                                       + getParseStatsText(StartTime));
            throw(InputException);
        }

        StatusMessage = new String("Successfully parsed " + getParseStatsText(StartTime));
        eh_Debug.add(3, StatusMessage);

        return MainDocumentParser.getCurrentDocument();
    }

    //*****************************************************************************
    /** Prepare and return a string describing how much was parsed, and how fast.
     *
     *  This method is private because it uses the current time as the time at which
     *  the parse is deemed to have completed - so if called from outside later,
     *  a misleading result will be given.
     *
     *  @param  InputParseStartTime  The system time at which the parse started
     *  @return                      A string description of the parse statistics
     */
    protected String getParseStatsText(long  InputParseStartTime)
    {
        long    ParseTimeMillis = System.currentTimeMillis() - InputParseStartTime;
        float   ParseTime       = ((float)ParseTimeMillis) / 1000;
        float   ParseRate       = TheParseManager.getTotalCharCount() / ParseTime;
        String  ParseStatsText  = new String(TheParseManager.getTotalCharCount()
                                             + " characters/" + TheParseManager.getLineCount()
                                             + " lines in " + ParseTime
                                             + " seconds (" + ParseRate
                                             + " characters per second)");
        return ParseStatsText;
    }

    //*****************************************************************************
    /** Set the parse listener which is to be informed of parse events.
     */
    public void setParseListener(xm_ParseListener  InputParseListener)
    {
        TheParseManager.setParseListener(InputParseListener);
    }
    //*****************************************************************************
    /** Set the flag to control whether to validate the document.
     *
     *  @param  InputValidateFlag  true means validate; false means do not.
     */
    public void setValidateFlag(boolean  InputValidateFlag)
    {
        super.setValidateFlag(InputValidateFlag);
        TheParseManager.setValidateFlag(InputValidateFlag);
    }

    //*****************************************************************************
    /** Set the flag to control whether to verify the document.
     *
     *  @param  InputVerifyFlag  true means verify; false means do not.
     */
    public void setVerifyFlag(boolean  InputVerifyFlag)
    {
        super.setValidateFlag(InputVerifyFlag);
        TheParseManager.setVerifyFlag(InputVerifyFlag);
    }

    //*****************************************************************************
    /** Specify whether we check the semantics of the source.
     *
     *  @param InputStopIfVerifyErrorFlag  True means we check semantics
     */
    public void setStopIfVerifyErrorFlag(boolean  InputStopIfVerifyErrorFlag)
    {
        super.setStopIfVerifyErrorFlag(InputStopIfVerifyErrorFlag);
        TheParseManager.setStopIfVerifyErrorFlag(InputStopIfVerifyErrorFlag);
    }
}

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

