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

  Program:   Visualization Toolkit
  Module:    vtkPixelExtentIO.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.

=========================================================================*/
#include "vtkPixelExtentIO.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkCellType.h"
#include "vtkDataSetWriter.h"
#include "vtkFloatArray.h"
#include "vtkIdTypeArray.h"
#include "vtkIntArray.h"
#include "vtkPoints.h"
#include "vtkUnsignedCharArray.h"
#include "vtkUnstructuredGrid.h"

using std::deque;

//------------------------------------------------------------------------------
vtkUnstructuredGrid& operator<<(vtkUnstructuredGrid& data, const vtkPixelExtent& ext)
{
  // initialize empty dataset
  if (data.GetNumberOfCells() < 1)
  {
    vtkPoints* opts = vtkPoints::New();
    data.SetPoints(opts);
    opts->Delete();

    vtkCellArray* cells = vtkCellArray::New();
    vtkUnsignedCharArray* types = vtkUnsignedCharArray::New();

    data.SetCells(types, cells);

    cells->Delete();
    types->Delete();
  }

  // cell to node
  vtkPixelExtent next(ext);
  next.CellToNode();

  // build the cell
  vtkFloatArray* pts = dynamic_cast<vtkFloatArray*>(data.GetPoints()->GetData());
  vtkIdType ptId = pts->GetNumberOfTuples();
  float* ppts = pts->WritePointer(3 * ptId, 12);

  int id[12] = { 0, 2, -1, 1, 2, -1, 1, 3, -1, 0, 3, -1 };

  vtkIdType ptIds[4];

  for (int i = 0; i < 4; ++i)
  {
    ppts[3 * i + 2] = 0.0;
    for (int j = 0; j < 2; ++j)
    {
      int q = 3 * i + j;
      ppts[q] = next[id[q]];
    }
    ptIds[i] = ptId + i;
  }

  data.InsertNextCell(VTK_QUAD, 4, ptIds);

  return data;
}

//------------------------------------------------------------------------------
void vtkPixelExtentIO::Write(
  int commRank, const char* fileName, const deque<deque<vtkPixelExtent>>& exts)
{
  if (commRank != 0)
  {
    // only rank 0 writes
    return;
  }

  vtkUnstructuredGrid* data = vtkUnstructuredGrid::New();

  vtkIntArray* rank = vtkIntArray::New();
  rank->SetName("rank");
  data->GetCellData()->AddArray(rank);
  rank->Delete();

  vtkIntArray* block = vtkIntArray::New();
  block->SetName("block");
  data->GetCellData()->AddArray(block);
  block->Delete();

  size_t nRanks = exts.size();

  for (size_t i = 0; i < nRanks; ++i)
  {
    size_t nBlocks = exts[i].size();
    for (size_t j = 0; j < nBlocks; ++j)
    {
      const vtkPixelExtent& ext = exts[i][j];
      *data << ext;

      rank->InsertNextTuple1(i);
      block->InsertNextTuple1(j);
    }
  }

  vtkDataSetWriter* idw = vtkDataSetWriter::New();
  idw->SetFileName(fileName);
  idw->SetInputData(data);
  idw->Write();
  idw->Delete();

  data->Delete();
}

//------------------------------------------------------------------------------
void vtkPixelExtentIO::Write(int commRank, const char* fileName, const deque<vtkPixelExtent>& exts)
{
  if (commRank != 0)
  {
    // only rank 0 will write
    return;
  }

  vtkUnstructuredGrid* data = vtkUnstructuredGrid::New();

  vtkIntArray* rank = vtkIntArray::New();
  rank->SetName("rank");
  data->GetCellData()->AddArray(rank);
  rank->Delete();

  int nExts = static_cast<int>(exts.size());
  rank->SetNumberOfTuples(nExts);

  int* pRank = rank->GetPointer(0);

  for (int i = 0; i < nExts; ++i)
  {
    const vtkPixelExtent& ext = exts[i];
    *data << ext;
    pRank[i] = i;
  }

  vtkDataSetWriter* idw = vtkDataSetWriter::New();
  idw->SetFileName(fileName);
  idw->SetInputData(data);
  idw->Write();
  idw->Delete();

  data->Delete();
}

//------------------------------------------------------------------------------
void vtkPixelExtentIO::Write(int commRank, const char* fileName, const vtkPixelExtent& ext)
{
  vtkUnstructuredGrid* data = vtkUnstructuredGrid::New();

  vtkIntArray* rank = vtkIntArray::New();
  rank->SetName("rank");
  data->GetCellData()->AddArray(rank);
  rank->Delete();

  rank->SetNumberOfTuples(1);
  int* pRank = rank->GetPointer(0);

  *data << ext;
  pRank[0] = commRank;

  vtkDataSetWriter* idw = vtkDataSetWriter::New();
  idw->SetFileName(fileName);
  idw->SetInputData(data);
  idw->Write();
  idw->Delete();

  data->Delete();
}
