// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void WriteTriangleGeometry::readFilterParameters(AbstractFilterParametersReader* reader, int index)
{
  reader->openFilterGroup(this, index);
  setDataContainerSelection( reader->readString("DataContainerSelection", getDataContainerSelection()));
  setOutputNodesFile( reader->readString( "OutputNodesFile", getOutputNodesFile() ) );
  setOutputTrianglesFile( reader->readString( "OutputTrianglesFile", getOutputTrianglesFile() ) );
  reader->closeFilterGroup();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void RequiredZThickness::readFilterParameters(AbstractFilterParametersReader* reader, int index)
{
  AbstractDecisionFilter::readFilterParameters(reader, index);
  reader->openFilterGroup(this, index);
  setDataContainerSelection(reader->readString("DataContainerSelection", getDataContainerSelection()));
  setNumZVoxels(reader->readValue("NumZVoxels", getNumZVoxels()));
  setPreflightCheck(reader->readValue("PreflightCheck", getPreflightCheck()));
  reader->closeFilterGroup();
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void RequiredZThickness::setupFilterParameters()
{
  FilterParameterVector parameters = getFilterParameters();

  {
    DataContainerSelectionFilterParameter::RequirementType req;
    parameters.push_back(DataContainerSelectionFilterParameter::New("DataContainer", "DataContainerSelection", getDataContainerSelection(), FilterParameter::RequiredArray, req));
  }
  parameters.push_back(IntFilterParameter::New("Minimum Z Dimension", "NumZVoxels", getNumZVoxels(), FilterParameter::Parameter, 0));
  parameters.push_back(BooleanFilterParameter::New("Preflight Check", "PreflightCheck", getPreflightCheck(), FilterParameter::Parameter));
  setFilterParameters(parameters);
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void RequiredZThickness::execute()
{
  setErrorCondition(0);
  dataCheck();
  if(getErrorCondition() < 0) { return; }

  DataContainer::Pointer dataContainer = getDataContainerArray()->getPrereqDataContainer<AbstractFilter>(this, getDataContainerSelection());
  if (getErrorCondition() < 0) { return; }

  ImageGeom::Pointer image = dataContainer->getGeometryAs<ImageGeom>();

  size_t dims[3] = { 0, 0, 0 };
  image->getDimensions(dims);


  if (dims[2] < getNumZVoxels())
  {
    QString str;
    QTextStream ss(&str);
    ss << "Number of Z Voxels does not meet required value during execution of the filter. \n";
    ss << "  Required Z Voxels: " << m_NumZVoxels << "\n";
    ss << "  Current Z Voxels: " << dims[2];

    setErrorCondition(-7788);
    notifyErrorMessage(getHumanLabel(), str, getErrorCondition());
    bool needMoreData = true;
    emit decisionMade(needMoreData);
  }

  notifyStatusMessage(getHumanLabel(), "Complete");
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void RequiredZThickness::dataCheck()
{
  setErrorCondition(0);
  if(getErrorCondition() < 0) { return; }

  DataContainer::Pointer dataContainer = getDataContainerArray()->getPrereqDataContainer<AbstractFilter>(this, getDataContainerSelection());
  if (getErrorCondition() < 0) { return; }

  ImageGeom::Pointer image = dataContainer->getGeometryAs<ImageGeom>();
  if( NULL == image.get() )
  {
    setErrorCondition(-7789);
    notifyErrorMessage(getHumanLabel(), "Missing Image Geometry in the selected DataContainer", getErrorCondition());
    return;
  }

  size_t dims[3] = { 0, 0, 0 };
  image->getDimensions(dims);


  if (dims[2] < getNumZVoxels() && m_PreflightCheck)
  {
    setErrorCondition(-7787);
    QString str;
    QTextStream ss(&str);
    ss << "Number of Z Voxels does not meet required value during preflight of the filter. \n";
    ss << "  Required Z Voxels: " << m_NumZVoxels << "\n";
    ss << "  Current Z Voxels: " << dims[2];

    notifyErrorMessage(getHumanLabel(), str, getErrorCondition());
  } 
  else if (dims[2] < getNumZVoxels() && !m_PreflightCheck)
  {
    QString str;
    QTextStream ss(&str);
    ss << "Number of Z Voxels does not meet required value during preflight but will be checked during pipeline execution.\n";
    ss << "  Required Z Voxels: " << m_NumZVoxels << "\n";
    ss << "  Current Z Voxels: " << dims[2];

    notifyWarningMessage(getHumanLabel(), str, getErrorCondition());
  }

}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void WriteTriangleGeometry::setupFilterParameters()
{
  FilterParameterVector parameters;


  parameters.push_back(OutputFileFilterParameter::New("Output Nodes File", "OutputNodesFile", getOutputNodesFile(), FilterParameter::Parameter));
  parameters.push_back(OutputFileFilterParameter::New("Output Triangles File", "OutputTrianglesFile", getOutputTrianglesFile(), FilterParameter::Parameter));

  {
    DataContainerSelectionFilterParameter::RequirementType req;
    parameters.push_back(DataContainerSelectionFilterParameter::New("DataContainer", "DataContainerSelection", getDataContainerSelection(), FilterParameter::RequiredArray, req));
  }

  setFilterParameters(parameters);
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void WriteTriangleGeometry::execute()
{
  int err = 0;
  setErrorCondition(err);

  dataCheck();
  if(getErrorCondition() < 0) { return; }
  DataContainer::Pointer dataContainer = getDataContainerArray()->getPrereqDataContainer<AbstractFilter>(this, getDataContainerSelection());

  TriangleGeom::Pointer triangleGeom = dataContainer->getGeometryAs<TriangleGeom>();
  QString geometryType = triangleGeom->getGeometryTypeAsString();
  float* nodes = triangleGeom->getVertexPointer(0);
  int64_t* triangles = triangleGeom->getTriPointer(0);

  qint64 numNodes = triangleGeom->getNumberOfVertices();
  qint64 maxNodeId = numNodes - 1;
  int64_t numTriangles = triangleGeom->getNumberOfTris();

  // ++++++++++++++ Write the Nodes File +++++++++++++++++++++++++++++++++++++++++++
  // Make sure any directory path is also available as the user may have just typed
  // in a path without actually creating the full path
  notifyStatusMessage(getHumanLabel(), "Writing Nodes Text File");
  QFileInfo fi(getOutputNodesFile());
  QDir parentPath = fi.path();

  if(!parentPath.mkpath("."))
  {

    QString ss = QObject::tr("Error creating parent path '%1'").arg(parentPath.absolutePath());
    notifyErrorMessage(getHumanLabel(), ss, -1);
    setErrorCondition(-1);
    return;
  }
  FILE* nodesFile = NULL;
  nodesFile = fopen(getOutputNodesFile().toLatin1().data(), "wb");
  if (NULL == nodesFile)
  {
    setErrorCondition(-100);
    notifyErrorMessage(getHumanLabel(), "Error opening Nodes file for writing", -100);
    return;
  }
  fprintf(nodesFile, "# All lines starting with '#' are comments\n");
  fprintf(nodesFile, "# DREAM.3D Nodes file\n");
  fprintf(nodesFile, "# DREAM.3D Version %s\n", SIMPLib::Version::Complete().toLatin1().constData());
  fprintf(nodesFile, "# Node Data is X Y Z space delimited.\n");
  fprintf(nodesFile, "Node Count: %lld\n", numNodes);
  for (int i = 0; i < numNodes; i++)
  {
    fprintf(nodesFile, "%8.5f %8.5f %8.5f\n", nodes[i * 3], nodes[i * 3 + 1], nodes[i * 3 + 2]);
  }
  fclose(nodesFile);

  // ++++++++++++++ Write the Triangles File +++++++++++++++++++++++++++++++++++++++++++
  notifyStatusMessage(getHumanLabel(), "Writing Triangles Text File");
  QFileInfo triFI(getOutputTrianglesFile());
  parentPath = triFI.path();
  if(!parentPath.mkpath("."))
  {

    QString ss = QObject::tr("Error creating parent path '%1'").arg(parentPath.absolutePath());
    notifyErrorMessage(getHumanLabel(), ss, -1);
    setErrorCondition(-1);
    return;
  }
  FILE* triFile = fopen(getOutputTrianglesFile().toLatin1().data(), "wb");
  if (NULL == triFile)
  {
    setErrorCondition(-100);
    notifyErrorMessage(getHumanLabel(), "Error opening Triangles file for writing", -100);
    return;
  }

  fprintf(triFile, "# All lines starting with '#' are comments\n");
  fprintf(triFile, "# DREAM.3D Triangle file\n");
  fprintf(triFile, "# DREAM.3D Version %s\n", SIMPLib::Version::Complete().toLatin1().constData());
  fprintf(triFile, "# Each Triangle consists of 3 Node Ids.\n");
  fprintf(triFile, "# NODE IDs START AT 0.\n");
  fprintf(triFile, "Geometry Type: %s\n", geometryType.toLatin1().constData());
  fprintf(triFile, "Node Count: %lld\n", numNodes);
  fprintf(triFile, "Max Node Id: %lld\n", maxNodeId );
  fprintf(triFile, "Triangle Count: %lld\n", (long long int)(numTriangles));

  int n1, n2, n3;
  for (int64_t j = 0; j < numTriangles; ++j)
  {
    n1 = triangles[j * 3];
    n2 = triangles[j * 3 + 1];
    n3 = triangles[j * 3 + 2];

    fprintf(triFile, "%d %d %d\n",  n1, n2, n3);
  }

  fclose(triFile);

  /* Let the GUI know we are done with this filter */
  notifyStatusMessage(getHumanLabel(), "Complete");
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void WriteTriangleGeometry::dataCheck()
{
  setErrorCondition(0);

  if(true == m_OutputNodesFile.isEmpty())
  {
    setErrorCondition(-380);
    notifyErrorMessage(getHumanLabel(), "The output Nodes file needs to be set", getErrorCondition());
  }

  if(true == m_OutputTrianglesFile.isEmpty())
  {
    setErrorCondition(-382);
    notifyErrorMessage(getHumanLabel(), "The output Triangles file needs to be set", getErrorCondition());
  }

  DataContainer::Pointer dataContainer = getDataContainerArray()->getPrereqDataContainer<AbstractFilter>(this, getDataContainerSelection());
  if(getErrorCondition() < 0) { return; }

  TriangleGeom::Pointer triangles =  dataContainer->getPrereqGeometry<TriangleGeom, AbstractFilter>(this);
  if(getErrorCondition() < 0) { return; }

  // We MUST have Nodes
  if (NULL == triangles->getVertices().get())
  {
    setErrorCondition(-386);
    notifyErrorMessage(getHumanLabel(), "DataContainer Geometry missing Vertices", getErrorCondition());
  }
  // We MUST have Triangles defined also.
  if (NULL == triangles->getTriangles().get())
  {
    setErrorCondition(-387);
    notifyErrorMessage(getHumanLabel(), "DataContainer Geometry missing Triangles", getErrorCondition());
  }

}