#include "platform.h"
#include <akaxiso/akaxiso.h>

#include <iostream>
#include <iomanip>
#include <fstream>

#include "exception.h"
#include "schema.h"
#include "classgen.h"
#include "type_registory.h"

#include <stdlib.h>


void usage() {

  std::cout << "Osixaka (" << PACKAGE << "-" << VERSION << ")" << std::endl
	    << " usage  osixaka [-o output directory] [-h]" << std::endl
	    << " Class/Serializer generator for akaxiso."
	    << "  -o: specify output directory to write generated files." << std::endl
	    << "  -h: show this message." << std::endl;

}


int main(int argc, char* argv[]){
  
  // Initialize Xerces.
#ifdef USE_XERCESC
  xercesc::XMLPlatformUtils::Initialize();
#endif
  aka::initialize();
  // Initialize XML-Schema Document Classes.
  xs::define_schemadoc();
  // std:: for C++ namespace.
  aka2::namespaces().register_namespace_uri("http://unittest.org/akaxiso/osixaka/c++std"); 
  osixaka::cppattrs_.associate_namespace_prefix("std", 
						"http://unittest.org/akaxiso/osixaka/c++std"); 
  osixaka::builtinTypes_.initialize();
  osixaka::arrays_.initialize();

  std::ostream & logstm = std::cout;
  std::string outputdir = ".";

  osixaka::generator gen;
  char c;
  
  while ((c = getopt(argc, argv, "o:h")) != -1) {
    switch (c) {
    case 'o': {
      outputdir = optarg;
      break;
    }
    case 'h' :{
      usage();
      exit(0);
    }
    default: {
      logstm << "Unknown option." << std::endl;
      exit(1);
    }
    }
  }


  // Parse
  aka::xml_parser parser;

  aka::document doc;
  try {
    doc = parser.parse_stdin();
  }
  catch (const aka::parse_exception &e) {
    logstm << e.what() << std::endl;
    logstm << "Unsupported features found in schema document, or wrong grammar." << std::endl
	   << "Aborting..." << std::endl;
    exit(1);
  }
   catch ( ... ) {
     logstm << "Unhandled parse error detected.  Aborting..." << std::endl;
     exit(1);
   }

   aka::xml_serializer ser;
   ser.serialize(doc, std::cout);
  
  try {
    gen.generate_classes(*aka::root_cast<xs::Schema>(doc));

    std::ofstream element_file(std::string(outputdir + "/element.h").c_str());
    gen.write_element_header("element.h", element_file);
    std::ofstream xixo_header(std::string(outputdir + "/xiso.h").c_str());
    gen.write_xiso_header("element.h", "xiso.h", xixo_header);
    std::ofstream xixo_impl(std::string(outputdir + "/xiso.cpp").c_str());
    gen.write_xiso_implementation("xiso.h", "xiso.cpp", xixo_impl);
  }
  catch (const osixaka::fatal_error &e) {
    logstm << e.what() << std::endl;
    logstm << "Failed to generate files. Aborting..." << std::endl;
    exit(1);
  }
  catch ( ... ) {
    logstm << "Unknown exception caught. Aborting..." << std::endl;
    exit(1);
  }
        
  //  delete doc;

  logstm << "Generation completed." << std::endl;

  // Uninitializers.
  aka::uninitialize();
#ifdef USE_XERCEC
  XMLPlatformUtils::Terminate();
#endif

  return 0;
}
