#include <iostream>
#include <sstream>
#include <fstream> 

#include "flat_modelica_parser.hpp"
#include "flat_modelica_lexer.hpp"
#include "parse_tree_dumper.hpp"
#include "antlr/ANTLRException.hpp"
#include "antlr/CharStreamException.hpp"
#include "antlr/TokenStreamException.hpp"
#include "antlr/RecognitionException.hpp"
#include "antlr/NoViableAltException.hpp"
#include "antlr/MismatchedTokenException.hpp"
#include "antlr/TokenStreamRecognitionException.hpp"
#include "antlr/ASTFactory.hpp"
#include "MyAST.h"

using namespace std;

int main(int argc, char **argv) {
    char* filename = argv[1];
    string filestring(filename); 
    bool debug = false;
    bool parsedump = true;
    /* 2004-10-05 adrpo moved this declaration here to 
     * have the ast initialized before getting 
     * into the code. This way, if this relation fails at least the 
     * ast is initialized */
   void* ast= null;

    //For parsing flat modelica (mof) files, if such is given
    bool parseFlatModelica=false;
    if (filestring.size()-4 == filestring.rfind(".mof")){
      parseFlatModelica=true;
    }

    std::ifstream stream(filename);
    if (!stream) {    
      cerr << "File \"" << filename << "\" not found." << endl;
      exit(1);
    }
    //bool debug = true;
    flat_modelica_lexer *flat_lex=0;
    flat_modelica_parser *flat_parse=0;
    ANTLR_USE_NAMESPACE(antlr)ASTFactory my_factory( "MyAST", MyAST::factory );
    flat_lex = new flat_modelica_lexer(stream);
    flat_lex->setFilename(filename);

    if (!stream) 
      {
	std::cerr << "Error opening file" << std::endl;
      }
    RefMyAST t;
    if (parseFlatModelica){
      //We are parsing flat modelica and not modelica
      flat_parse = new flat_modelica_parser(*flat_lex);
      flat_parse->setFilename(filename); 

      // make factory with customized type of MyAST
      flat_parse->initializeASTFactory(my_factory);
      flat_parse->setASTFactory( &my_factory );

      try{
	cout << "Parsing flat modelica" << endl;
	flat_parse->stored_definition();
	cout << "done" << endl;
	t = RefMyAST(flat_parse->getAST());
      } 
      catch (ANTLR_USE_NAMESPACE(antlr)CharStreamException &e) 
	{
	  std::cerr << "Lexical error. CharStreamException. "  << std::endl;    
	}
      catch (ANTLR_USE_NAMESPACE(antlr)TokenStreamRecognitionException &e) 
	{
	  std::cerr << "Parsing error. TokenStreamRecognitionException on line "
		    << flat_lex->getLine() << "near :"<< flat_lex->getText() << std::endl;    
	}
      catch (ANTLR_USE_NAMESPACE(antlr)RecognitionException &e) 
	{
	  std::cerr << "[" << filestring << ":" << e.getLine() << ":" << e.getColumn() 
		    << "]: error: " << e.getMessage() << std::endl;
	}
      catch (ANTLR_USE_NAMESPACE(antlr)TokenStreamException &e) 
	{
	  std::cerr << "[" << filestring << ":" << flat_lex->getLine() << ":" << flat_lex->getColumn() 
		    << "]: error: illegal token" << std::endl;
	}
      catch (ANTLR_USE_NAMESPACE(antlr)ANTLRException &e) 
	{
	  std::cerr << "ANTLRException: " << e.getMessage() << std::endl;
	}
      catch (std::exception &e) 
	{
	  std::cerr << "Error while parsing:\n" << e.what() << "\n";
	}
      catch (...) 
	{
	  std::cerr << "Error while parsing\n";
	}

    }

    if (parsedump) 
      {
	parse_tree_dumper dumper(std::cout);
	//dumper.initializeASTFactory(factory);
	//dumper.setASTFactory(&factory);
	dumper.dump(t);
      }
	

    if (flat_parse) delete flat_parse;
    if (flat_lex) delete flat_lex;

}
