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

  Program:   Visualization Toolkit
  Module:    vtkExodusIIWriter.cxx

  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.

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

/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

#include "vtkPExodusIIWriter.h"
#include "vtkObjectFactory.h"
#include "vtkModelMetadata.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkDoubleArray.h"
#include "vtkDataObject.h"
#include "vtkFieldData.h"
#include "vtkCompositeDataSet.h"
#include "vtkCompositeDataIterator.h"
#include "vtkUnstructuredGrid.h"
#include "vtkCellData.h"
#include "vtkPointData.h"
#include "vtkIdList.h"
#include "vtkThreshold.h"
#include "vtkIntArray.h"
#include "vtkCellArray.h"
#include "vtkFloatArray.h"
#include "vtkArrayIteratorIncludes.h"

#include "vtkMultiProcessController.h"

#include "vtk_exodusII.h"
#include <ctime>
#include <cctype>

vtkStandardNewMacro (vtkPExodusIIWriter);

//----------------------------------------------------------------------------

vtkPExodusIIWriter::vtkPExodusIIWriter ()
{
}

vtkPExodusIIWriter::~vtkPExodusIIWriter ()
{
}

void vtkPExodusIIWriter::PrintSelf (ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}

//----------------------------------------------------------------------------
int vtkPExodusIIWriter::CheckParameters ()
{
  vtkMultiProcessController *c = vtkMultiProcessController::GetGlobalController();
  int numberOfProcesses = c ? c->GetNumberOfProcesses() : 1;
  int myRank = c ? c->GetLocalProcessId() : 0;

  if (this->GhostLevel > 0)
  {
    vtkWarningMacro(<< "ExodusIIWriter ignores ghost level request");
  }

  return this->Superclass::CheckParametersInternal(numberOfProcesses, myRank);
}

//----------------------------------------------------------------------------
int vtkPExodusIIWriter::RequestUpdateExtent (
  vtkInformation* request,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  this->Superclass::RequestUpdateExtent(request, inputVector, outputVector);
  vtkMultiProcessController *c = vtkMultiProcessController::GetGlobalController();
  if (c)
  {
    int numberOfProcesses = c->GetNumberOfProcesses();
    int myRank = c->GetLocalProcessId();

    vtkInformation *info = inputVector[0]->GetInformationObject(0);
    info->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), myRank);
    info->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), numberOfProcesses);
  }

  return 1;
}

void vtkPExodusIIWriter::CheckBlockInfoMap ()
{
  // if we're multiprocess we need to make sure the block info map matches
  if (this->NumberOfProcesses > 1)
  {
    int maxId = -1;
    std::map<int, Block>::const_iterator iter;
    for (iter = this->BlockInfoMap.begin (); iter != this->BlockInfoMap.end (); ++iter)
    {
      if (iter->first > maxId)
      {
        maxId = iter->first;
      }
    }
    vtkMultiProcessController *c = vtkMultiProcessController::GetGlobalController();
    int globalMaxId;
    c->AllReduce (&maxId, &globalMaxId, 1, vtkCommunicator::MAX_OP);
    maxId = globalMaxId;
    for (int i = 1; i <= maxId; i ++)
    {
      Block &b = this->BlockInfoMap[i]; // ctor called (init all to 0/-1) if not preset
      int globalType;
      c->AllReduce (&b.Type, &globalType, 1, vtkCommunicator::MAX_OP);
      if (b.Type != 0 && b.Type != globalType)
      {
        vtkWarningMacro (
          << "The type associated with ID's across processors doesn't match");
      }
      else
      {
        b.Type = globalType;
      }
      int globalNodes;
      c->AllReduce (&b.NodesPerElement, &globalNodes, 1, vtkCommunicator::MAX_OP);
      if (b.NodesPerElement != globalNodes &&
          // on a processor with no data, b.NodesPerElement == 0.
          b.NodesPerElement != 0)
      {
        vtkWarningMacro (
          << "NodesPerElement associated with ID's across "
             "processors doesn't match: "
          << b.NodesPerElement << " != " << globalNodes);
      }
      else
      {
        b.NodesPerElement = globalNodes;
      }
    }
  }
}

//----------------------------------------------------------------------------
int vtkPExodusIIWriter::GlobalContinueExecuting(int localContinue)
{
  vtkMultiProcessController *c =
    vtkMultiProcessController::GetGlobalController();
  int globalContinue = localContinue;
  if (c)
  {
    c->AllReduce (&localContinue, &globalContinue, 1, vtkCommunicator::MIN_OP);
  }
  return globalContinue;
}

//----------------------------------------------------------------------------
unsigned int vtkPExodusIIWriter::GetMaxNameLength()
{
  unsigned int maxName = this->Superclass::GetMaxNameLength();

  vtkMultiProcessController *c =
    vtkMultiProcessController::GetGlobalController();
  unsigned int globalMaxName = 0;
  c->AllReduce(&maxName, &globalMaxName, 1, vtkCommunicator::MAX_OP);
  return maxName;
}
