/*
 * Copyright University of Reims Champagne-Ardenne
 * Authors and Contributors: Akilan RAJAMANI, Corentin LEFEBVRE, Johanna KLEIN,
 *                           Emmanuel PLUOT, Gaetan RUBEZ, Hassan KHARTABIL,
 *                           Jean-Charles BOISSON and Eric HENON
 * (24/07/2017)
 * jean-charles.boisson@univ-reims.fr, eric.henon@univ-reims.fr
 *
 * This software is a computer program whose purpose is to
 * detect and quantify interactions from electron density
 * obtained either internally from promolecular density or
 * calculated from an input wave function input file. It also
 * prepares for the visualization of isosurfaces representing
 * several descriptors (dg) coming from the IGM methodology.
 *
 * This software is governed by the CeCILL-C license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL-C
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 *
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.
 *
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 *
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL-C license and that you accept its terms.
 *
 * */

/**
 * @file igmplot.cpp
 * @brief Main of the IGMplot application */

#ifndef _IGMPLOT_CPP_
#define _IGMPLOT_CPP_

// LOCAL
#include <igmplot.h>


/*********************  M A I N  ****************************************/

int
main(int argc, char ** argv)
{

  bool haveToExit, outputSizeLimitActivated;
  // C classical way to have running time
  struct timeval stop, start, interm;

  haveToExit=false;
  outputSizeLimitActivated=false;  //if true, the program will stop if the estimated amount of data generated exceeds the limit passed in parameter
 
  // the number of parameter can be either 2 or 3 
  if(argc < 2 || argc > 3)
    {
      std::cerr << std::endl << "[ERROR] Bad number of arguments." << std::endl;
      haveToExit=true;
    }

  // for instance: IGMPLOT --limit param.igm
  if(argc == 3 )
    {
      if (strcmp(argv[1],"--limit") == 0) 
	{
	  outputSizeLimitActivated=true;
	}
      else
	{
	  std::cerr << std::endl << "[ERROR] \"" << argv[1] 
                    << "\" is not an allowed option (maybe have you put the parameter file name before the option(s))." 
                    << std::endl;
	  haveToExit=true;
	}
    }

  if(haveToExit)
    {
      howUsingIGMplot();
      std::cerr << "[ERROR] The program will now exit." << std::endl << std::endl;
      exit(EXIT_FAILURE);
    }
  
  
  std::cout << std::endl;

  // ============ I N I T I A L I Z A T I O N   PRO  && WFN  ==========
  // create an object NCISolver with filename param.igm (argv[argc-1])
  // Input DATA are read here (PRO & WFN)
  gettimeofday(&start, NULL);
  time_t t = start.tv_sec;
  struct tm *info = localtime(&t);
  std::cout << asctime(info) << std::flush;
  std::cout << "Reading input data  ... \n" << std::flush;
  NCISolver ncis(argv[argc-1]);

  // ..................................................................


  // for a calculation performed on romeolab: a disk limit is detected
  if(outputSizeLimitActivated)
    {
      // test the output Size Limit  
      checkOutputFileSize(ncis.getPredictedSize(), outputSizeLimitActivated);
    }
  
  //gettimeofday(&start, NULL);

  // ============  C A L C U L A T I O N   P R O    &&    W F N  ======
  gettimeofday(&interm, NULL); 
  if (not isParseRKF() )
     { ncis.solve(); }
  // (output WFN is inside nci.solve)  ................................
  //

  // delete runinfo file
  if (ncis.getRuninfostate()) {
    if (remove(runinfo.c_str()) !=0 ) 
     {
       std::cerr << " " << std::endl;
       // addentum : this warning can occur if there is latency on file system
       std::cerr << "[WARNING] Error while deleting file [" << runinfo << "] after calculation." <<std::endl;
     }
    else
     {
       // nothing to write
     }
  } // end of if (getRuninfostate

  
  // ============  O U T P U T    P R O M O L E C U L A R ============= 
  if( !isWFmodeActivated())
    {	
      gettimeofday(&stop, NULL);
      std::cout << "CPU time            : " << stop.tv_sec - interm.tv_sec << "s" << std::endl;
      std::cout << "Writing files ..." << std::flush << "\n";
      ncis.output(); // ----> OUTPUT DAT, CUBE, ... see NCISolver.cpp
    }
  // ..................................................................



  // ============ T I M E    I N F O ===================================
  gettimeofday(&stop, NULL);
  std::cout << "Wall-clock time     : " << stop.tv_sec - start.tv_sec << "s" << std::endl;
  t = stop.tv_sec;
  info = localtime(&t);
  std::cout << asctime(info) << std::flush;
  // ...................................................................

  
  std::cout << "Done" << std::endl << std::endl << std::endl ;
  
  return EXIT_SUCCESS;
}// end of MAIN



/*********************  checkOutputFileSize *****************************/
void
checkOutputFileSize(const double predictedOutputSize, const bool outputSizeLimitActivated, const unsigned int outputSizeLimitInMB)
{
  std::cout << std::endl << "Predicted amount of output data: ";
  if(predictedOutputSize<1)
    {
      std::cout << predictedOutputSize*1024 << " KB" << std::endl << std::endl;
    }
  else
    {
      if(predictedOutputSize >= 1024)
	{
	  std::cout << predictedOutputSize/1024 << " GB" << std::endl << std::endl;
	}
      else
	{
	  std::cout << predictedOutputSize << " MB" << std::endl << std::endl;
	}
    }

  /*std::cout << "[INFO ] For small systems (with .dat < 100 MB), the predicted size may be underestimated" << std::endl 
    << "[INFO ] For bigger systems, the predicted size may be overestimated" << std::endl << std::endl;*/
  
  std::cout << "[INFO ] Due to empiric estimation, the predicted size may be relatively" << std::endl
  	    << "[INFO ] underestimated or overestimated according to the chosen configuration." << std::endl << std::endl;

  if(outputSizeLimitActivated)
    {
      if(predictedOutputSize > outputSizeLimitInMB )
	{
	  std::cerr <<  std::endl;	
	  std::cerr << "[ERROR] Predicted amount of output data exceeds " << outputSizeLimitInMB << " MB." << std::endl;
	  std::cerr << "[ERROR] The program will now exit." << std::endl << std::endl;
	  exit(EXIT_FAILURE);
	}
      else
	{
	  std::cout <<  std::endl;	
	  std::cout << "[INFO ] Predicted amount of output data does not exceed " << outputSizeLimitInMB << " MB." << std::endl;
	  std::cout << "[INFO ] Computation proceeds." << std::endl;
	  std::cout << std::endl;
      
	}
    }
} // end of checkOutputFileSize

#endif
