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

// ----------------------------------------------------------------------
// AmrDerivePeriodicFab.cpp
// ----------------------------------------------------------------------
#include <new.h>
#include <iostream.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "REAL.H"
#include "Box.H"
#include "FArrayBox.H"
#include "ParmParse.H"
#include "ParallelDescriptor.H"
#include "Utility.H"

const int XDIR = 0;
const int YDIR = 1;
#if (BL_SPACEDIM == 3)
const int ZDIR = 2;
#endif

#define SHOWVAL(val) {  \
		 cout << #val << " = " << val << '\n';  }

void PrintUsage(char *progName);

// ----------------------------------------------------------------------
int main(int argc, char *argv[]) {
    if(argc == 1) {
      PrintUsage(argv[0]);
    }

    ParmParse pp(argc-1,argv+1);
    FArrayBox::setFormat(FABio::FAB_IEEE_32);

    std::string iFile;
    std::string oFile;

    pp.get("infile", iFile);
    pp.get("outfile", oFile);
    SHOWVAL(iFile)
    SHOWVAL(oFile)

    ifstream inFabStream(iFile.c_str());
    FArrayBox inFab(inFabStream);
    SHOWVAL(inFab.box());
    inFabStream.close();

    Box grownBox(inFab.box());

    bool bPerX(false), bPerY(false), bPerZ(false);
    int  nPerX(0), nPerY(0), nPerZ(0);

    if(pp.contains("perx")) {
      bPerX = true;
      pp.query("perx", nPerX);
      grownBox.growHi(XDIR, inFab.box().length(XDIR) * nPerX);
    }
    if(pp.contains("pery")) {
      bPerY = true;
      pp.query("pery", nPerY);
      grownBox.growHi(YDIR, inFab.box().length(YDIR) * nPerY);
    }
#if (BL_SPACEDIM == 3)
    if(pp.contains("perz")) {
      bPerZ = true;
      pp.query("perz", nPerZ);
      grownBox.growHi(ZDIR, inFab.box().length(ZDIR) * nPerZ);
    }
#endif

    SHOWVAL(grownBox);
    FArrayBox grownFab(grownBox, inFab.nComp());
    Box progressiveGrownBox(inFab.box());
    int srcComp(0), destComp(0), nComps(inFab.nComp());

    grownFab.copy(inFab, inFab.box());
    if(bPerX) {
      Box srcBox(progressiveGrownBox);
      SHOWVAL(progressiveGrownBox);
      for(int nShifts(1); nShifts <= nPerX; ++nShifts) {  // start at 1
        progressiveGrownBox.shift(XDIR, inFab.box().length(XDIR) * nShifts);
	cout << "----- shifted:  ";  SHOWVAL(progressiveGrownBox);
	cout << "----- copying from:  ";  SHOWVAL(srcBox);
	cout << "----- copying to:    ";  SHOWVAL(progressiveGrownBox);
        grownFab.copy(grownFab, srcBox, srcComp,
		      progressiveGrownBox, destComp, nComps);
        progressiveGrownBox.shift(XDIR, -inFab.box().length(XDIR) * nShifts);
	cout << "----- unshifted:  ";  SHOWVAL(progressiveGrownBox);
      }
      progressiveGrownBox.growHi(XDIR, inFab.box().length(XDIR) * nPerX);
    }
    if(bPerY) {
      Box srcBox(progressiveGrownBox);
      for(int nShifts(1); nShifts <= nPerY; ++nShifts) {  // start at 1
        progressiveGrownBox.shift(YDIR, inFab.box().length(YDIR) * nShifts);
        grownFab.copy(grownFab, srcBox, srcComp,
		      progressiveGrownBox, destComp, nComps);
        progressiveGrownBox.shift(YDIR, -inFab.box().length(YDIR) * nShifts);
      }
      progressiveGrownBox.growHi(YDIR, inFab.box().length(YDIR) * nPerY);
    }
#if (BL_SPACEDIM == 3)
    if(bPerZ) {
      Box srcBox(progressiveGrownBox);
      for(int nShifts(1); nShifts <= nPerZ; ++nShifts) {  // start at 1
        progressiveGrownBox.shift(ZDIR, inFab.box().length(ZDIR) * nShifts);
        grownFab.copy(grownFab, srcBox, srcComp,
		      progressiveGrownBox, destComp, nComps);
        progressiveGrownBox.shift(ZDIR, -inFab.box().length(ZDIR) * nShifts);
      }
      progressiveGrownBox.growHi(ZDIR, inFab.box().length(ZDIR) * nPerZ);
    }
#endif

    ofstream outFabStream(oFile.c_str());
    grownFab.writeOn(outFabStream);
    outFabStream.close();


}


// ----------------------------------------------------------------------
void PrintUsage(char *progName) {
  cout << '\n';
  cout << "Usage:" << '\n';
  cout << progName << '\n';
  cout << "    infile  = inputFileName" << '\n';
  cout << "    outfile = outputFileName" << '\n';
  cout << "   [perx    = nTimes]" << '\n';
  cout << "   [pery    = nTimes]" << '\n';
  cout << "   [perz    = nTimes]" << '\n';
  cout << '\n';

  exit(-1);
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
