/* Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2017 Frederik Heber. All rights reserved.
 *
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder 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.
 *
 *    MoleCuilder 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 General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoleCuilder.  If not, see .
 */
/** \file MPCJob_Work.cpp
 *
 * Function implementations for the class vector.
 *
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include 
#include "MPQCJob.hpp"
#include "CodePatterns/Log.hpp"
#include 
#ifdef HAVE_JOBMARKET
// include headers that implement a archive in simple text format
// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
#include 
#include 
#include "JobMarket/Results/FragmentResult.hpp"
#include 
#include 
#include 
#include 
#include 
#include "mpqc.h"
using namespace std;
using namespace sc;
FragmentResult::ptr MPQCJob::Work()
{
  char mpqc[] = "mpqc" ;
  char **argv = new char*[1];
  argv[0] = &mpqc[0];
  int argc = 1;
  // now comes the actual work
  mpqc::InitValues initvalues;
  int nfilebase = (int) inputfile.length();
  initvalues.in_char_array = new char[nfilebase + 1];
  strncpy(initvalues.in_char_array, inputfile.c_str(), nfilebase);
  initvalues.in_char_array[nfilebase] = '\0';
  initvalues.grp = MessageGrp::get_default_messagegrp();
  // create unique, temporary name and check whether it exists
  char *tempfilename = NULL;
  {
    std::ifstream test;
    do {
      if (initvalues.output != NULL) // free buffer from last round
        delete initvalues.output;
      char filename_template[] = "mpqc_temp_XXXXXX\0";
      char filename_suffix[] = ".in\0";
      tempfilename = (char *) malloc ( (strlen(filename_template)+strlen(filename_suffix)+2)*(sizeof(char)));
      strncpy(tempfilename, mktemp(filename_template), strlen(filename_template));
      tempfilename[strlen(filename_template)] = '\0';
      strncat(tempfilename, filename_suffix, strlen(filename_suffix));
      initvalues.output = tempfilename;
      //free(tempfilename); // don't free! output takes over pointer!
      test.open(initvalues.output);
    } while (test.good()); // test whether file does not(!) exist
    test.close();
  }
  // put info how to sample the density into MPQCData
  MPQCData data(grid);
  data.DoLongrange = DoLongrange; // set whether we sample the density
  data.DoValenceOnly = DoValenceOnly; // set whether we sample just valence electron and nuclei densities
// now call work horse
  try {
    mpqc::mainFunction(initvalues, argc, argv, static_cast(&data));
  }
  catch (SCException &e) {
    cout << argv[0] << ": ERROR: SC EXCEPTION RAISED:" << endl
         << e.what()
         << endl;
    detail::clean_up();
  }
  //delete[] in_char_array; // is deleted in mainFunction()
  if (initvalues.output != 0) {
    free(tempfilename);
  }
  delete[] argv;
  initvalues.grp = NULL;
  // place into returnstream
  std::stringstream returnstream;
  boost::archive::text_oarchive oa(returnstream);
  oa << data;
  FragmentResult::ptr s( new FragmentResult(getId(), returnstream.str()) );
  if (s->exitflag != 0)
    cerr << "Job #" << s->getId() << " failed to reach desired accuracy." << endl;
  return s;
}
#else
FragmentResult::ptr MPQCJob::Work()
{
  // instantiate empty data
  const MPQCData data;
  std::stringstream returnstream;
  boost::archive::text_oarchive oa(returnstream);
  oa << data;
  // create the result
  FragmentResult::ptr ptr( new FragmentResult(getId(), returnstream.str()) );
  if (data.desired_accuracy != 0.) {
    ptr->exitflag = data.accuracy < data.desired_accuracy ? 0 : 1;
    if (ptr->exitflag != 0)
      ELOG(1, "Job #" << ptr->getId() << " failed to reach desired accuracy.");
  } else {
    LOG(3, "INFO: No precision returned from MPQC job, not checking.");
  }
  return ptr;
}
#endif
// we need to explicitly instantiate the serialization functions as
// its is only serialized through its base class FragmentJob
BOOST_CLASS_EXPORT_IMPLEMENT(MPQCJob)