//-*-C++-*-
/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2000-2001 by Andreas Zehender
    email                : zehender@kde.org
**************************************************************************

**************************************************************************
*                                                                        *
*  This program is free software; you can redistribute it and/or modify  *
*  it under the terms of the GNU General Public License as published by  *
*  the Free Software Foundation; either version 2 of the License, or     *
*  (at your option) any later version.                                   *
*                                                                        *
**************************************************************************/


#ifndef PMPARSER_H
#define PMPARSER_H

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <kurl.h>
#include <qcstring.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qvaluelist.h>

#include "pmobject.h"
#include "pmsymboltable.h"
#include "pmvalue.h"

class QTextStream;
class QIODevice;

class PMScanner;
class PMPart;
class PMSymbolTable;

enum PMPMessage { PMMClockDefault = 1, PMMClockDeltaDefault = 2,
                  PMMSpecialRawComment = 4 };

/**
 * Base class for kpovmodeler parsers.
 */
class PMParser
{
public:
   /** Parser that parses the device */
   PMParser( PMPart* part, QIODevice* device );
   /** Parser that parses the byte array */
   PMParser( PMPart* part, const QByteArray& array );
   /** Deletes the parser */
   virtual ~PMParser( );

   /**
    * Quickly scans the top level objects. Appends all top level object
    * types to the list.
    */
   virtual void quickParse( QValueList<PMObjectType>& /*list*/ ) { };
   /** Returns true, if the parser can quickly scan the top level objects. */
   virtual bool canQuickParse( ) const { return false; }

   /**
    * Parses the device.
    *
    * Appends all parsed objects to the list.
    *
    * parent is the object where the parsed objects will be inserted as
    * children behind the object after. These parameters are used to check
    * the consistency of declares and links.
    *
    * Set parent and after to 0 if and only if a document is parsed/opened.
    */
   void parse( PMObjectList* list, PMObject* parent,
               PMObject* after );
   
   /** Returns the messages of the parser */
   QStringList messages( ) const { return m_messages; }
   /** Returns true if there were errors during parsing */
   bool errors( ) const { return m_errors > 0; }
   /** Returns true if there were warnings during parsing */
   bool warnings( ) const { return m_warnings > 0; }
   /** Returns true, if a fatal error occurred or no object could be
    * successfully parsed and it doesn't make sense to continue */
   bool fatal( ) const { return m_bFatalError; }
   /** Returns a bitwise combination of @ref PMErrorFlags constants */
   int errorFlags( ) const;

   /** returns the maximum number of errors */
   static unsigned maxErrors( ) { return s_maxErrors; }
   /** sets the maximum number of errors to m */
   static void setMaxErrors( unsigned m ) { s_maxErrors = m; }
   /** returns the maximum number of warnings */
   static unsigned maxWarnings( ) { return s_maxWarnings; }
   /** sets the maximum number of warnings to m */
   static void setMaxWarnings( unsigned m ) { s_maxWarnings = m; }

   /** Adds an error to the message string */
   void printError( const QString& msg );
   /** Adds the error "'<str>' expected, found <token> instead" to the message string */
   void printExpected( const QString& str, const char* token );
   /** Adds the error "'<c>' expected" to the message string */
   void printExpected( const char c, const char* token );
   /** Adds the error "Unexpected token '<str>', found <token> instead" to the message string */
   void printUnexpected( const QString& str );
   /** Adds a warning to the message string */
   void printWarning( const QString& msg );
   /** Adds an info to the message string */
   void printInfo( const QString& msg );
   /** Adds the message to the message string. Type is "error", "warning",
    * "info" or "scanner error" */
   void printMessage( const QString& type, const QString& msg );
   /** Prints a messages that should only reported once */
   void printMessage( const PMPMessage messageNum );

   /** Sets the fatal error flag */
   void setFatalError( ) { m_bFatalError = true; }
   
   /** Sets the current line number */
   void setCurrentLine( int lineNumber ) { m_lineNum = lineNumber; }

   /** Returns the declare object with id, if it exists and is declared at
    * the current parse position, otherwise 0 */
   PMDeclare* checkLink( const QString& id );
   /** Checks the id of the declare. If there is already a declare with
    * the same id, the id of the object is renamed.
    *
    * Inserts the object into the symbol table.*/
   void checkID( PMDeclare* obj );
   /** Checks the id of the value declare (constant, vector or color).
    * If there is already a declare with
    * the same id, the id of the value is renamed.
    *
    * Inserts the object into the symbol table.*/
   void checkID( const QString& id, const PMValue& v );
   /** Returns the symbol with id id or 0 if the id is undeclared */
   PMSymbol* getSymbol( const QString& id ) const;
   /** Tries to insert obj as child of parent. If parent is 0, the object
    * will be inserted in the list of top level objects.
    *
    * Returns true if the object could be inserted. */
   bool insertChild( PMObject* obj, PMObject* parent );

protected:
   /**
    * Top level parse function.
    *
    * Overwrite this function in a specific parser.
    */
   virtual void topParse( ) = 0;
   
protected:
   /** Pointer to the part */
   PMPart* m_pPart;
   /** parent object where the parsed top level objects
    * will be inserted _later_ (not from the parser) as children */
   const PMObject* m_pTopParent;
   const PMObject* m_pAfter;
   /** The list where the parsed objects are stored */
   PMObjectList* m_pResultList;
   /** The QIODevice */
   QIODevice* m_pDevice;
   /** True, if the device was created by the parser */
   bool m_bDeviceCreated;
   
private:
   /** Initializes the parser */
   void init( );
   
   /** The parser output (errors, warnings...) */
   QStringList m_messages;
   /** Number of warnings during parsing */
   unsigned int m_warnings;
   /** Number of errors during parsing */
   unsigned int m_errors;
   /** Flag for fatal errors */
   bool m_bFatalError;

   /** maximum number of errors */
   static unsigned int s_maxErrors;
   /** maximum number of warnings */
   static unsigned int s_maxWarnings;
   /** Already shown warnings or errors, that are reported only once */
   int m_shownMessages;
   /** The current line number */
   int m_lineNum;
   /** List of renamed declares */
   QPtrList<PMSymbol> m_renamedObjectSymbols;
   /** Dictionary of symbol names, that can be linked */
   QDict<bool> m_okDeclares;
   PMObject* m_pNextCheckDeclare;
   /** Symbol table used during parsing. The symbol table of the part
    * will not be changed. */
   PMSymbolTable m_pLocalST;
};



#endif
