/*
** (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.
*/


//
// AmrDeriveStationData.cpp
//

#include <new>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using std::ios;
using std::set_new_handler;

#include <unistd.h>

#include "REAL.H"
#include "Array.H"
#include "Box.H"
#include "FArrayBox.H"
#include "ParmParse.H"
#include "ParallelDescriptor.H"
#include "DataServices.H"
#include "Utility.H"
//#include "VisMF.H"
#include "Derived.H"


static
void
PrintUsage (const char* progName)
{
    cout << '\n';
    cout << "Usage:" << '\n';
    cout << progName << '\n';
    cout << "    infile  = inputFileName" << '\n';
    cout << "    outfile = outputFileName" << '\n';
    cout << "   [maxlev  = maxleveltofill]" << '\n';
    cout << "   [-help]" << '\n';
    cout << "   [-verbose]" << '\n';
    cout << '\n';
    cout << "For example"  << progName
         << " inputs.station infile=plt0000 outfile=stations.plt0000";
    cout << '\n';
    cout << '\n';
    exit(1);
}






int
main (int   argc,
      char* argv[])
{
    if(argc == 1)
        PrintUsage(argv[0]);
    //
    // Make sure to catch new failures.
    //
    set_new_handler(Utility::OutOfMemory);

    ParallelDescriptor::StartParallel(&argc, &argv);

    //char *stationInFile = argv[1];
    //ParmParse pp(argc-2,argv+2, stationInFile);
    ParmParse pp(argc-1,argv+1);


    if(pp.contains("help"))
        PrintUsage(argv[0]);

    //FArrayBox::setFormat(FABio::FAB_IEEE_32);
    //
    // Scan the arguments.
    //
    aString iFile, oFile;

    bool verbose = false;
    if(pp.contains("verbose")) {
        verbose = true;
        AmrData::SetVerbose(true);
    }
    pp.query("infile", iFile);
    cout << "iFile = " << iFile << endl;
    if(iFile.isNull()) {
        BoxLib::Abort("You must specify `infile'");
    }

    pp.query("outfile", oFile);
    if(oFile.isNull()) {
        BoxLib::Abort("You must specify `outfile'");
    }

    if(verbose) {
      pp.dumpTable(cout);
    }

    DataServices::SetBatchMode();
    FileType fileType(NEWPLT);
    
    DataServices dataServices(iFile, fileType);

    if( ! dataServices.AmrDataOk()) {
      //DataServices::Dispatch(DataServices::ExitRequest, NULL);
      ParallelDescriptor::EndParallel();
    }

    AmrData& amrData = dataServices.AmrDataRef();


// ----------------------
    int nStationVars(0), nStationCoords(0);
    Array<aString>      stationVars;     // Names of StationData components.
    Array<Array<Real> > stationCoords;   // Array of stations [nvars][spacedim].
{
    //
    // ParmParse variables:
    //
    //   StationData.vars     -- Names of StateData components to output
    //   StationData.coord    -- BL_SPACEDIM array of Reals
    //   StationData.coord    -- the next one
    //
    // example:
    //
    //   StationData.vars  = pressure
    //   StationData.coord = 0.343 0.05075 0.1014
    //   StationData.coord = 0.1 0.2 0.3
    //

    ParmParse pp("StationData");

    if(pp.contains("vars")) {
        nStationVars = pp.countval("vars");
	BL_ASSERT(nStationVars > 0);

        stationVars.resize(nStationVars);

        for(int i(0); i < nStationVars; ++i) {
            pp.get("vars", stationVars[i], i);

            if(amrData.CanDerive(stationVars[i]) == false) {
                cerr << "Error:  StationData.var `" << stationVars[i]
                     << "' is not in the plot file.\n";
                BoxLib::Abort();
            }
        }
    } else {
      BoxLib::Abort("Error:  must specify StationData.vars");
    }

    if(pp.contains("coord")) {

        Array<Real> data(BL_SPACEDIM);
        nStationCoords  = pp.countname("coord");
        stationCoords.resize(nStationCoords);

        for(int k(0); k < nStationCoords; ++k) {
	    stationCoords[k].resize(BL_SPACEDIM);
            pp.getktharr("coord", k, data, 0, BL_SPACEDIM);

            D_TERM(stationCoords[k][0] = data[0];,
                   stationCoords[k][1] = data[1];,
                   stationCoords[k][2] = data[2];);

            //BL_ASSERT(Geometry::ProbDomain().contains(data.dataPtr()));
        }
    } else {
      BoxLib::Abort("Error:  must specify StationData.coords");
    }
}
// ----------------------


  int finestLevel = amrData.FinestLevel();
  int finestFillLevel = finestLevel;

  if(pp.contains("maxlev")) {
    pp.query("maxlev", finestFillLevel);
    //finestFillLevel = max((int)0, (int)finestFillLevel);
    //finestFillLevel = min(finestLevel, finestFillLevel);
    cout << "*--* filling data to finestFillLevel = " << finestFillLevel << endl;
  }

  ofstream os;
  if(verbose && ParallelDescriptor::IOProcessor()) {
    cout << "Opening file = " << oFile << '\n';
  }
    os.open(oFile.c_str(), ios::out | ios::binary | ios::app);

  if(os.fail()) {
    Utility::FileOpenFailed(oFile);
  }


  for(int iVar(0); iVar < nStationVars; ++iVar) {
    for(int iCoord(0); iCoord < nStationCoords; ++iCoord) {

      int ivLevel;
      IntVect ivLoc, ivFinestFillLev;
      amrData.IntVectFromLocation(finestFillLevel, stationCoords[iCoord],
				  ivLoc, ivLevel, ivFinestFillLev);
      Box destBox(ivFinestFillLev, ivFinestFillLev);
      FArrayBox destFab(destBox, 1);
      amrData.FillVar(&destFab, destBox, finestFillLevel, stationVars[iVar], 0);
      //amrData.FillVar(&destFab, destBox, ivLevel, stationVars[iVar], 0);


      if(ParallelDescriptor::IOProcessor()) {
        cout << "ivFinestFillLev = " << ivFinestFillLev << endl;
        os << amrData.Time() << "  "
	   << destFab.dataPtr()[0] << endl;
      }
    }
  }

  os.close();

  ParallelDescriptor::EndParallel();
}

