/*
 *  Copyright (c) 2010 Cyrille Berger <cberger@cberger.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

// C++ Headers
#include <iostream>
#include <fstream>
#include <cstdlib>

#include <Cauchy/Version.h>
#include <Cauchy/Source.h>
#include <Cauchy/CompilationMessages.h>
#include <Cauchy/Options.h>
#include <Cauchy/DeclarationsRegistry.h>

void printVersion()
{
  std::cout << Cauchy::LibraryShortName() << " - " << Cauchy::LibraryName() << " - " << Cauchy::LibraryVersionString() << std::endl;
  std::cout << Cauchy::LibraryCopyright() << std::endl;
}
void printHelp()
{
  std::cout << "Usage : cauchymc [option] fileName.m" << std::endl;
  std::cout << std::endl;
  std::cout << "Options : " << std::endl;
  std::cout << "  -o --output [output]    specify an output file" << std::endl;
  std::cout << "  -I --include-dir [directory]  add an include directory for finding functions definition" << std::endl;
  std::cout << "  -i [file]               load a specific function definition" << std::endl;
  std::cout << "  -b --backend [backend]  the name of the backend used to generate the code" << std::endl;
  std::cout << std::endl;
  std::cout << "  -h --help               print this message" << std::endl;
  std::cout << "  -v --version            print the version information" << std::endl;
}

#define ARG_IS(a,b) argv[ai] == Cauchy::String(a) or argv[ai] == Cauchy::String(b)

int main(int argc, char** argv)
{
  Cauchy::String backend = "eigen3";
  Cauchy::String fileName = "";
  Cauchy::String output = "";
  Cauchy::Options options;
  Cauchy::DeclarationsRegistry r;
  for(int ai = 1; ai < argc; ai++)
  {
    if(ARG_IS("-h","--help"))
    {
      printHelp();
      return EXIT_SUCCESS;
    } else if(ARG_IS("-v","--version"))
    {
      printVersion();
      return EXIT_SUCCESS;
    } else if(ARG_IS("-I", "--include-dir")) {
      if( ai == argc - 1 )
      {
        std::cerr << "Expected filename after -I --include-dir." << std::endl;
        return EXIT_FAILURE;
      } else {
        ++ai;
        r.addSearchPath(argv[ai]);
      }
    } else if(ARG_IS("-i", "")) {
      if( ai == argc - 1 )
      {
        std::cerr << "Expected filename after -i." << std::endl;
        return EXIT_FAILURE;
      } else {
        ++ai;
        r.load(argv[ai]);
      }
    } else if(ARG_IS("-o", "--output")) {
      if( ai == argc - 1 )
      {
        std::cerr << "Expected filename after -o --output." << std::endl;
        return EXIT_FAILURE;
      } else {
        ++ai;
        output = argv[ai];
      }
    } else if(ARG_IS("-b", "--backend")) {
      if( ai == argc - 1 )
      {
        std::cerr << "Expected backend name after -b --backend." << std::endl;
        return EXIT_FAILURE;
      } else {
        ++ai;
        backend = argv[ai];
      }
    } else {
      if( ai != argc - 1)
      {
        std::cerr << "Invalid command line parameters." << std::endl;
        printHelp();
        return EXIT_FAILURE;
      } else {
        fileName = argv[ai];
      }
    }
  }
  
  if(not r.load("Cauchy/xUnit.cfd"))
  {
    std::cerr << "Could not find xUnit.cfd file." << std::endl;
    return -1;
  }
  if(not r.load("Cauchy/Standard.cfd"))
  {
    std::cerr << "Could not find Standard.cfd file." << std::endl;
  }
  if(not r.load("Cauchy/Octave.cfd"))
  {
    std::cerr << "Could not find Octave.cfd file." << std::endl;
  }
  
  
  if( fileName == "")
  {
    printHelp();
  } else {
    Cauchy::String source;
    std::ifstream in;
    in.open(fileName.c_str() );
    if(not in)
    {
      std::cerr << "Impossible to open file " << fileName << std::endl;
      return EXIT_FAILURE;
    }
    std::string str;
    std::getline(in,str);
    while ( in ) {
      source += str;
      source += "\n";
      std::getline(in,str);
    }
    Cauchy::Source p;
    p.setSource( fileName, source, &r );
    p.compile();
    if(not p.isCompiled())
    {
      std::cout << "Error: " << std::endl << p.compilationMessages().toString() << std::endl;
      return EXIT_FAILURE;
    }
    if(output.isEmpty())
    {
      std::cout << p.generate(options, backend) << std::endl;
    } else {
      std::ofstream file;
      file.open(output.c_str());
      if(file)
      {
        file << p.generate(options, backend);
      } else {
        std::cerr << "Impossible to open file " << output << std::endl;
        return EXIT_FAILURE;
      }
    }
  }
  return EXIT_SUCCESS;
}
