/*=========================================================================

  Program:   Visualization Toolkit
  Module:    AMRCommon.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// .NAME AMRCommon.h -- Encapsulates common functionality for AMR data.
//
// .SECTION Description
// This header encapsulates some common functionality for AMR data to
// simplify and expedite the development of examples.

#ifndef AMRCOMMON_H_
#define AMRCOMMON_H_

#include <cassert> // For C++ assert
#include <sstream> // For C++ string streams

#include "vtkCell.h"
#include "vtkCompositeDataWriter.h"
#include "vtkHierarchicalBoxDataSet.h"
#include "vtkImageToStructuredGrid.h"
#include "vtkMultiBlockDataSet.h"
#include "vtkOverlappingAMR.h"
#include "vtkStructuredGridWriter.h"
#include "vtkUniformGrid.h"
#include "vtkUniformGrid.h"
#include "vtkXMLHierarchicalBoxDataReader.h"
#include "vtkXMLImageDataWriter.h"
#include "vtkXMLMultiBlockDataWriter.h"
#include "vtkXMLUniformGridAMRWriter.h"

namespace AMRCommon {



//------------------------------------------------------------------------------
// Description:
// Writes a uniform grid as a structure grid
void WriteUniformGrid( vtkUniformGrid *g, const std::string &prefix )
{
  assert( "pre: Uniform grid (g) is NULL!" && (g != nullptr) );

  vtkXMLImageDataWriter *imgWriter = vtkXMLImageDataWriter::New();

  std::ostringstream oss;
  oss << prefix << "." << imgWriter->GetDefaultFileExtension();
  imgWriter->SetFileName( oss.str().c_str() );
  imgWriter->SetInputData( g );
  imgWriter->Write();

  imgWriter->Delete();
}

//------------------------------------------------------------------------------
// Description:
// Writes the given AMR dataset to a *.vth file with the given prefix.
void WriteAMRData( vtkOverlappingAMR *amrData, const std::string &prefix )
{
  // Sanity check
  assert( "pre: AMR dataset is NULL!" && (amrData != nullptr) );

  vtkCompositeDataWriter *writer = vtkCompositeDataWriter::New();

  std::ostringstream oss;
  oss << prefix << ".vthb";
  writer->SetFileName(oss.str().c_str());
  writer->SetInputData(amrData);
  writer->Write();
  writer->Delete();
}

//------------------------------------------------------------------------------
// Description:
// Reads AMR data to the given data-structure from the prescribed file.
vtkHierarchicalBoxDataSet* ReadAMRData( const std::string &file )
{
  // Sanity check
//  assert( "pre: AMR dataset is NULL!" && (amrData != NULL) );

  vtkXMLHierarchicalBoxDataReader *myAMRReader=
   vtkXMLHierarchicalBoxDataReader::New();
  assert( "pre: AMR Reader is NULL!" && (myAMRReader != nullptr) );

  std::ostringstream oss;
  oss.str("");
  oss.clear();
  oss << file << ".vthb";

  std::cout << "Reading AMR Data from: " << oss.str() << std::endl;
  std::cout.flush();

  myAMRReader->SetFileName( oss.str().c_str() );
  myAMRReader->Update();

  vtkHierarchicalBoxDataSet *amrData =
   vtkHierarchicalBoxDataSet::SafeDownCast( myAMRReader->GetOutput() );
  assert( "post: AMR data read is NULL!" && (amrData != nullptr) );
  return( amrData );
}

//------------------------------------------------------------------------------
// Description:
// Writes the given multi-block data to an XML file with the prescribed prefix
void WriteMultiBlockData( vtkMultiBlockDataSet *mbds, const std::string &prefix )
{
  // Sanity check
  assert( "pre: Multi-block dataset is NULL" && (mbds != nullptr) );
  vtkXMLMultiBlockDataWriter *writer = vtkXMLMultiBlockDataWriter::New();

  std::ostringstream oss;
  oss.str(""); oss.clear();
  oss << prefix << "." << writer->GetDefaultFileExtension();
  writer->SetFileName( oss.str( ).c_str( ) );
  writer->SetInputData( mbds );
  writer->Write();
  writer->Delete();
}

//------------------------------------------------------------------------------
// Constructs a uniform grid instance given the prescribed
// origin, grid spacing and dimensions.
vtkUniformGrid* GetGrid( double* origin,double* h,int* ndim )
{
  vtkUniformGrid *grd = vtkUniformGrid::New();
  grd->Initialize();
  grd->SetOrigin( origin );
  grd->SetSpacing( h );
  grd->SetDimensions( ndim );
  return grd;
}

//------------------------------------------------------------------------------
// Computes the cell center for the cell corresponding to cellIdx w.r.t.
// the given grid. The cell center is stored in the supplied buffer c.
void ComputeCellCenter( vtkUniformGrid *grid, const int cellIdx, double c[3] )
{
  assert( "pre: grid != NULL" && (grid != nullptr) );
  assert( "pre: Null cell center buffer" && (c != nullptr)  );
  assert( "pre: cellIdx in bounds" &&
          (cellIdx >= 0) && (cellIdx < grid->GetNumberOfCells() ) );

  vtkCell *myCell = grid->GetCell( cellIdx );
  assert( "post: cell is NULL" && (myCell != nullptr) );

  double pCenter[3];
  double *weights = new double[ myCell->GetNumberOfPoints() ];
  int subId       = myCell->GetParametricCenter( pCenter );
  myCell->EvaluateLocation( subId,pCenter,c,weights );
  delete [] weights;
}


} // END namespace

#endif /* AMRCOMMON_H_ */
