/*
** (c) 1996-2000 The Regents of the University of California (through
** E.O. Lawrence Berkeley National Laboratory), subject to approval by
** the U.S. Department of Energy.  Your use of this software is under
** license -- the license agreement is attached and included in the
** directory as license.txt or you may contact Berkeley Lab's Technology
** Transfer Department at TTD@lbl.gov.  NOTICE OF U.S. GOVERNMENT RIGHTS.
** The Software was developed under funding from the U.S. Government
** which consequently retains certain rights as follows: the
** U.S. Government has been granted for itself and others acting on its
** behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, and perform publicly
** and display publicly.  Beginning five (5) years after the date
** permission to assert copyright is obtained from the U.S. Department of
** Energy, and subject to any subsequent five (5) year renewals, the
** U.S. Government is granted for itself and others acting on its behalf
** a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, distribute copies to
** the public, perform publicly and display publicly, and to permit
** others to do so.
*/


#include <algorithm>
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>

#include <REAL.H>
#include <math.h>
#include <IntVect.H>
#include <Box.H>
#include <Grid.H>
#include <ParmParse.H>
#include <BCTypes.H>

// declare global variables here
Real init_shrink    = 1.0;
Real     gravity    = 0.0;

int      bcx_lo;
int      bcx_hi;
int      bcy_lo;
int      bcy_hi;
int      bcz_lo;
int      bcz_hi;

const int * lo;
const int * hi;

typedef char* charString;

// functions called 
void print_usage(int,char**);
void parse_command_line(int, char**, charString&, charString&);
void writePlotFile(Grid *, int, Real, std::string&);

// ###################################################################
// ##### MAIN PROGRAM
// ###################################################################
main(int argc, char *argv[])
{
    BoxLib::Initialize(argc,argv);

   charString   in_file = NULL;
   charString   res_file = NULL;
   parse_command_line(argc,argv,in_file,res_file);

   ParmParse pp;

   int max_step;
   Real stop_time;
   Real cfl;
   int  check_int;
   int  plot_int;
   std::string check_file_root = "chk";
   std::string plot_file_root = "plt";
   pp.get("max_step",max_step);
   pp.get("stop_time",stop_time);
   pp.get("cfl",cfl);
   pp.query("init_shrink",init_shrink);
   pp.query("gravity",gravity);
   pp.get("check_int",check_int);
   pp.query("check_file_root",check_file_root);
   pp.get("plot_int",plot_int);
   pp.query("plot_file_root",plot_file_root);
   std::string probin_file;
   if (pp.contains("probin_file"))
   {
       pp.get("probin_file",probin_file);
   }

   pp.get("bcx_lo",bcx_lo);
   pp.get("bcx_hi",bcx_hi);
   pp.get("bcy_lo",bcy_lo);
   pp.get("bcy_hi",bcy_hi);
   pp.get("bcz_lo",bcz_lo);
   pp.get("bcz_hi",bcz_hi);

   if (bcx_lo == PERIODIC && bcx_hi != PERIODIC) {
     std::cout << "IF bcx_lo is periodic then bcx_hi must be periodic " << std::endl;
     exit(0);
   }
   if (bcx_hi == PERIODIC && bcx_lo != PERIODIC) {
     std::cout << "IF bcx_hi is periodic then bcx_lo must be periodic " << std::endl;
     exit(0);
   }
   if (bcy_lo == PERIODIC && bcy_hi != PERIODIC) {
     std::cout << "IF bcy_lo is periodic then bcy_hi must be periodic " << std::endl;
     exit(0);
   }
   if (bcy_hi == PERIODIC && bcy_lo != PERIODIC) {
     std::cout << "IF bcy_hi is periodic then bcy_lo must be periodic " << std::endl;
     exit(0);
   }
   if (bcz_lo == PERIODIC && bcz_hi != PERIODIC) {
     std::cout << "IF bcz_lo is periodic then bcz_hi must be periodic " << std::endl;
     exit(0);
   }
   if (bcz_hi == PERIODIC && bcz_lo != PERIODIC) {
     std::cout << "IF bcz_hi is periodic then bcz_lo must be periodic " << std::endl;
     exit(0);
   }


   Grid* grid = new Grid(probin_file);

   Real time = 0.0;
   Real dt   = 0.0;
   int nstep = 0;

   grid->init(nstep,time,dt);

// First do the iterations to calculate an initial pressure
   if (nstep == 0) {
     dt = std::min(init_shrink * grid->estimateDt(dt,cfl), stop_time - time);
     grid->initialIter(time,dt);
     grid->writeCheckPoint(nstep,time,dt,check_file_root);
   }

   writePlotFile(grid,nstep,time,plot_file_root);

   int last_checkpoint = nstep;
   int last_plotpoint  = nstep;

   while (nstep < max_step && time <= stop_time - 1.e-10) {

      if (nstep > 0) 
        dt = std::min(grid->estimateDt(dt,cfl), stop_time - time);

      nstep++;

      // do a timestep
      grid->advance(time, dt);
      time += dt;

      std::cout << "STEP = " << nstep << " TIME = " << time;
      std::cout << " DT = " << dt << std::endl;

      // checkpoint file?
      if (check_int > 0 && nstep%check_int == 0) {
         last_checkpoint = nstep;
         grid->writeCheckPoint(nstep,time,dt,check_file_root);
      };

      if (plot_int > 0 && nstep%plot_int == 0) {
         last_plotpoint = nstep;
         writePlotFile(grid,nstep,time,plot_file_root);
      };

   };

   // dump final checkpoint file if needed
   if (nstep != last_checkpoint) {
      grid->writeCheckPoint(nstep,time,dt,check_file_root);
   };

   // dump final pltfile file if needed
   if (nstep != last_plotpoint) {
      writePlotFile(grid,nstep,time,plot_file_root);
   };

   // clean up memory usage
   delete grid;

    BoxLib::Finalize();
}

// ###################################################################
// ##### print_usage
// ###################################################################
void print_usage(int /* argc */, char *argv[]) {
   std::cerr << "usage:\n";
   std::cerr << argv[0] << " infilename " << std::endl;
   std::cerr << "\n";
   exit(1);
}

// ###################################################################
// ##### parse_command_line
// ###################################################################
void parse_command_line(int argc, char *argv[],
                        charString &in_file, charString &res_file)
{

   // first input must be input file name
   if (argc < 2) print_usage(argc,argv);
   if (argv[1][0] == '-') {
      std::cerr << "first command line argument must be file name\n";
      print_usage(argc,argv);
   };
   in_file = argv[1];
}

// ###################################################################
// ##### writePlotFile
// ###################################################################

void writePlotFile(Grid* grid, int nstep, Real time, std::string& plot_file_root)
{
    grid->writePlotFile(nstep,time,plot_file_root);
}

