//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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 "vtkDelosMeshReader.h"
#include "vtkNew.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkDoubleArray.h"
#include "vtkErrorCode.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkIntArray.h"
#include "vtkObjectFactory.h"
#include "vtkPoints.h"
#include "vtkPointData.h"
#include "vtkUnstructuredGrid.h"
#include "vtkMultiBlockWrapper.h"

#include <string>
#include <vtksys/SystemTools.hxx>
#include <sstream>
#include <sys/stat.h>

vtkStandardNewMacro(vtkDelosMeshReader);


//----------------------------------------------------------------------------
vtkDelosMeshReader::vtkDelosMeshReader()
{
  this->FileName = NULL;
  this->SetNumberOfInputPorts(0);
}

//----------------------------------------------------------------------------
vtkDelosMeshReader::~vtkDelosMeshReader()
{
  delete[] this->FileName;
}

//----------------------------------------------------------------------------
int vtkDelosMeshReader::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *outputVector)
{
  if (!this->FileName || (strlen(this->FileName) == 0))
    {
    vtkErrorMacro("FileName has to be specified!");
    return 0;
    }

  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  vtkPolyData *output = vtkPolyData::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  struct stat fs;
  if (stat(this->FileName, &fs) != 0)
    {
    vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    return 0;
    }

  ifstream infile(this->FileName, ios::in | ios::binary);
  if (infile.fail())
    {
    vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
    this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
    return 0;
    }

  vtkDebugMacro(<< "Executing Delos Mesh file reader");
  // Read the coordinates
  vtkNew<vtkPoints> points;
  output->SetPoints(points.GetPointer());
  std::string mode;
  infile >> mode;
  if (mode != "DEBXYZ")
    {
    vtkErrorMacro(<< "Missing Coordinate Block: "
                  << "Header Tag = " << mode);
    return 0;

    }
  int numPoints, dim, i;
  infile >> numPoints >> dim;
  points->SetNumberOfPoints(numPoints);
  double x, y, z = 0.0;
  if (dim == 2)
    {
    for (i = 0; i < numPoints; i++)
      {
      infile >> x >> y;
      points->SetPoint(i, x, y, 0.0);
      }
    }
  else
    {
    for (i = 0; i < numPoints; i++)
      {
      infile >> x >> y >> z;
      points->SetPoint(i, x, y, z);
      }
    }
  // Read close of section
  infile >> mode;
  if (mode != "FINXYZ")
    {
    vtkErrorMacro(<< "Missing Coordinate End of Block: "
                  << "Close Tag = " << mode);
    return 0;
    }

  // Read in Cells
  infile >> mode;
  if (mode != "DEBILM")
    {
    vtkErrorMacro(<< "Missing Connectivity Block: "
                  << "Header Tag = " << mode);
    return 0;

    }
  int numCells, numSides, id, code, regId, j;
  infile >> numCells;
  vtkNew<vtkCellArray> cells;
  vtkNew<vtkIntArray>  regionIds;
  regionIds->SetName("Model Entity ID");
  regionIds->SetNumberOfValues(numCells);
  output->GetCellData()->AddArray(regionIds.GetPointer());
  for (i = 0; i < numCells; i++)
    {
    infile >> numSides;
    cells->InsertNextCell(numSides);
    for (j = 0; j < numSides; j++)
      {
      infile >> id;
      // Correct to have a start index of 0 and not 1
      --id;
      cells->InsertCellPoint(id);
      }
    infile >> code >> regId;
    regionIds->SetValue(i, regId);
    }
  output->SetPolys(cells.GetPointer());
  // Read close of section
  infile >> mode;
  if (mode != "FINILM")
    {
    vtkErrorMacro(<< "Missing Connectivity End of Block: "
                  << "Close Tag = " << mode);
    return 0;
    }
  vtkDebugMacro(<< "Executed CMB Mesh file reader");
  return 1;
}

//----------------------------------------------------------------------------
int vtkDelosMeshReader::CanReadFile(const char *fname)
{
  struct stat fs;
  if (!fname || strlen(fname) == 0 || stat(fname, &fs) != 0)
    {
    return 0;
    }
  return 1;
}

//----------------------------------------------------------------------------
void vtkDelosMeshReader::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "File Name: " <<
    (this->FileName ? this->FileName : "(none)") << endl;
}

//----------------------------------------------------------------------------
int vtkDelosMeshReader::RequestInformation(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **vtkNotUsed(inputVector),
  vtkInformationVector *vtkNotUsed(outputVector))
{
  if (!this->FileName)
    {
    vtkErrorMacro("FileName has to be specified!");
    return 0;
    }

  return 1;
}
