// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void AbaqusSurfaceMeshWriter::execute()
{
  int err = 0;
  std::stringstream ss;

  SurfaceMeshDataContainer* sm = getSurfaceMeshDataContainer();
  dataCheck(false, 1, 1, 1);
  if(getErrorCondition() < 0)
  {
    return;
  }

  // Make sure any directory path is also available as the user may have just typed
  // in a path without actually creating the full path
  std::string parentPath = MXAFileInfo::parentPath(getOutputFile());
  if(!MXADir::mkdir(parentPath, true))
  {
    std::stringstream ss;
    ss << "Error creating parent path '" << parentPath << "'";
    notifyErrorMessage(ss.str(), -1);
    setErrorCondition(-1);
    return;
  }

  DREAM3D::SurfaceMesh::VertListPointer_t nodesPtr = sm->getVertices();
  DREAM3D::SurfaceMesh::FaceListPointer_t trianglePtr = sm->getFaces();

  // Get the Labels(GrainIds or Region Ids) for the triangles
  Int32ArrayType::Pointer faceLabelsPtr = boost::dynamic_pointer_cast<Int32ArrayType>(sm->getFaceData(DREAM3D::FaceData::SurfaceMeshFaceLabels));
  int32_t* faceLabels = faceLabelsPtr->GetPointer(0);

  // Store all the unique Spins
  std::set<int> uniqueSpins;
  for (int i = 0; i < trianglePtr->GetNumberOfTuples(); i++)
  {
    uniqueSpins.insert(faceLabels[i*2]);
    uniqueSpins.insert(faceLabels[i*2+1]);
  }

  FILE* f = fopen(m_OutputFile.c_str(), "wb");
  ScopedFileMonitor fileMonitor(f);

  err = writeHeader(f, nodesPtr->GetNumberOfTuples(), trianglePtr->GetNumberOfTuples(), uniqueSpins.size()-1);
  err = writeNodes(f);
  err = writeTriangles(f);
  err = writeGrains(f);

  setErrorCondition(0);
  notifyStatusMessage("Complete");

  return;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void TriangleNormalFilter::execute()
{
  int err = 0;
  std::stringstream ss;
  setErrorCondition(err);
  SurfaceMeshDataContainer* m = getSurfaceMeshDataContainer();
  if(NULL == m)
  {
    setErrorCondition(-999);
    notifyErrorMessage("The SurfaceMesh DataContainer Object was NULL", -999);
    return;
  }
  setErrorCondition(0);
  notifyStatusMessage("Starting");

#ifdef DREAM3D_USE_PARALLEL_ALGORITHMS
  bool doParallel = true;
#endif

  DREAM3D::SurfaceMesh::VertListPointer_t nodesPtr = getSurfaceMeshDataContainer()->getVertices();

  DREAM3D::SurfaceMesh::FaceListPointer_t trianglesPtr = getSurfaceMeshDataContainer()->getFaces();
  size_t totalPoints = trianglesPtr->GetNumberOfTuples();

  // Run the data check to allocate the memory for the centroid array
  dataCheck(false, trianglesPtr->GetNumberOfTuples(), 0, 0);

#ifdef DREAM3D_USE_PARALLEL_ALGORITHMS
  if (doParallel == true)
  {
    tbb::parallel_for(tbb::blocked_range<size_t>(0, totalPoints),
                      CalculateNormalsImpl(nodesPtr, trianglesPtr, m_SurfaceMeshTriangleNormals), tbb::auto_partitioner());

  }
  else
#endif
  {
    CalculateNormalsImpl serial(nodesPtr, trianglesPtr, m_SurfaceMeshTriangleNormals);
    serial.generate(0, totalPoints);
  }


  /* Let the GUI know we are done with this filter */
  notifyStatusMessage("Complete");
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
void SurfaceMeshDataContainerWriter::writeXdmfGridHeader()
{
  if (m_WriteXdmfFile == false || m_XdmfPtr == NULL)
  {
    return;
  }
  DREAM3D::SurfaceMesh::FaceListPointer_t faces = getSurfaceMeshDataContainer()->getFaces();
  if (NULL == faces.get())
  {
    return;
  }
  DREAM3D::SurfaceMesh::VertListPointer_t verts = getSurfaceMeshDataContainer()->getVertices();
  if(NULL == verts.get())
  {
    return;
  }

  std::ostream& out = *m_XdmfPtr;
  out << "  <Grid Name=\"SurfaceMesh DataContainer\">" << std::endl;

  out << "    <Topology TopologyType=\"Triangle\" NumberOfElements=\"" << faces->GetNumberOfTuples() << "\">" << std::endl;
  out << "      <DataItem Format=\"HDF\" NumberType=\"Int\" Dimensions=\"" << faces->GetNumberOfTuples() << " 3\">" << std::endl;
  ssize_t nameSize = H5Fget_name(m_HdfFileId, NULL, 0) + 1;
  std::vector<char> nameBuffer(nameSize, 0);
  nameSize = H5Fget_name(m_HdfFileId, &(nameBuffer.front()), nameSize);
  std::string hdfFileName(&(nameBuffer.front()), nameSize);
  hdfFileName = MXAFileInfo::filename(hdfFileName);
  out << "        " << hdfFileName << ":/SurfaceMeshDataContainer/Faces" << std::endl;
  out << "      </DataItem>" << std::endl;
  out << "    </Topology>" << std::endl;

  out << "    <Geometry Type=\"XYZ\">" << std::endl;
  out << "      <DataItem Format=\"HDF\"  Dimensions=\"" << verts->GetNumberOfTuples() << " 3\" NumberType=\"Float\" Precision=\"4\">" << std::endl;
  out << "        " << hdfFileName << ":/SurfaceMeshDataContainer/Vertices" << std::endl;
  out << "      </DataItem>" << std::endl;
  out << "    </Geometry>" << std::endl;
  out << "" << std::endl;
}
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int AbaqusSurfaceMeshWriter::writeTriangles(FILE* f)
{
  int err = 0;
  DREAM3D::SurfaceMesh::FaceListPointer_t trianglePtr = getSurfaceMeshDataContainer()->getFaces();
  DREAM3D::SurfaceMesh::Face_t* triangles = trianglePtr->GetPointer(0);
  size_t numTri = trianglePtr->GetNumberOfTuples();

  fprintf(f, "*ELEMENT, TYPE=%s\n", TRI_ELEMENT_TYPE);
  for(size_t i = 1; i <= numTri; ++i)
  {

    // When we get the node index, add 1 to it because Abaqus number is 1 based.
    int nId0 = triangles[i-1].verts[0] + 1;
    int nId1 = triangles[i-1].verts[1] + 1;
    int nId2 = triangles[i-1].verts[2] + 1;
    fprintf(f, "%lu, %d, %d, %d\n", i, nId0, nId1, nId2);
  }
  return err;
}
    // -----------------------------------------------------------------------------
    //
    // -----------------------------------------------------------------------------
    void generateNeighborLists(DREAM3D::SurfaceMesh::VertListPointer_t nodes,
                               DREAM3D::SurfaceMesh::FaceListPointer_t faces,
                               MeshVertLinks::Pointer cellLinks)
    {

      size_t nFaces = faces->GetNumberOfTuples();

      allocate(faces->GetNumberOfTuples());

      // Allocate an array of bools that we use each iteration of triangle so that we don't put duplicates into the array
      boost::shared_array<bool> visitedPtr(new bool[nFaces]);
      bool* visited = visitedPtr.get();
      ::memset(visitedPtr.get(), 0, nFaces);

      // Reuse this vector for each loop. Avoids re-allocating the memory each time through the loop
      std::vector<int> loop_neighbors(32, 0);

      // Build up the Face Adjacency list now that we have the cell links
      for(size_t t = 0; t < nFaces; ++t)
      {
        //   std::cout << "Analyzing Face " << t << std::endl;
        DREAM3D::SurfaceMesh::Face_t& seedFace = *(faces->GetPointer(t));
        for(size_t v = 0; v < 3; ++v)
        {
          //   std::cout << " vert " << v << std::endl;
          int nTris = cellLinks->getNumberOfFaces(seedFace.verts[v]);
          int* vertIdxs = cellLinks->getFaceListPointer(seedFace.verts[v]);

          for(int vt = 0; vt < nTris; ++vt)
          {
            if (vertIdxs[vt] == static_cast<int>(t) ) { continue; } // This is the same triangle as our "source" triangle
            if (visited[vertIdxs[vt]] == true) { continue; } // We already added this triangle so loop again
            //      std::cout << "   Comparing Face " << vertIdxs[vt] << std::endl;
            DREAM3D::SurfaceMesh::Face_t& vertTri = *(faces->GetPointer(vertIdxs[vt]));
            int vCount = 0;
            // Loop over all the vertex indices of this triangle and try to match 2 of them to the current loop triangle
            // If there are 2 matches then that triangle is a neighbor of this triangle. if there are more than 2 matches
            // then there is a real problem with the mesh and the program is going to assert.
            // Unrolled the loop to shave about 25% of time off the outer loop.
            int seedTriVert0 = seedFace.verts[0];
            int seedTriVert1 = seedFace.verts[1];
            int seedTriVert2 = seedFace.verts[2];
            int trgtTriVert0 = vertTri.verts[0];
            int trgtTriVert1 = vertTri.verts[1];
            int trgtTriVert2 = vertTri.verts[2];

            if (seedTriVert0 == trgtTriVert0 || seedTriVert0 == trgtTriVert1 || seedTriVert0 == trgtTriVert2  )
            {
              vCount++;
            }
            if (seedTriVert1 == trgtTriVert0 || seedTriVert1 == trgtTriVert1 || seedTriVert1 == trgtTriVert2  )
            {
              vCount++;
            }
            if (seedTriVert2 == trgtTriVert0 || seedTriVert2 == trgtTriVert1 || seedTriVert2 == trgtTriVert2  )
            {
              vCount++;
            }

            BOOST_ASSERT(vCount < 3); // No way 2 faces can share all 3 vertices. Something is VERY wrong at this point

            // So if our vertex match count is 2 and we have not visited the triangle in question then add this triangle index
            // into the list of Face Indices as neighbors for the source triangle.
            if (vCount == 2)
            {
              //std::cout << "       Neighbor: " << vertIdxs[vt] << std::endl;
              // Use the current count of neighbors as the index
              // into the loop_neighbors vector and place the value of the vertex triangle at that index
              loop_neighbors[this->Array[t].ncells] = vertIdxs[vt];
              this->Array[t].ncells++;// Increment the count for the next time through
              if (this->Array[t].ncells >= loop_neighbors.size())
              {
                loop_neighbors.resize(loop_neighbors.size() + 10);
              }
              visited[vertIdxs[vt]] = true; // Set this triangle as visited so we do NOT add it again
            }
          }
        }
        BOOST_ASSERT(this->Array[t].ncells > 2);
        // Reset all the visited triangle indexs back to false (zero)
        for(size_t k = 0;k < this->Array[t].ncells; ++k)
        {
          visited[loop_neighbors[k]] = false;
        }
        // Allocate the array storage for the current triangle to hold its Face list
        this->Array[t].cells = new int[this->Array[t].ncells];
        // Only copy the first "N" values from the loop_neighbors vector into the storage array
        ::memcpy(this->Array[t].cells, &(loop_neighbors[0]), sizeof(int) * this->Array[t].ncells);
      }
    }
// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
int AbaqusSurfaceMeshWriter::writeGrains(FILE* f)
{

  //*Elset, elset=Grain1
  //1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16

  int err = 0;

  std::stringstream ss;
  SurfaceMeshDataContainer* sm = getSurfaceMeshDataContainer();
  DREAM3D::SurfaceMesh::VertListPointer_t nodesPtr = sm->getVertices();
  DREAM3D::SurfaceMesh::FaceListPointer_t trianglePtr = sm->getFaces();

  // Get the Labels(GrainIds or Region Ids) for the triangles
  Int32ArrayType::Pointer faceLabelsPtr = boost::dynamic_pointer_cast<Int32ArrayType>(sm->getFaceData(DREAM3D::FaceData::SurfaceMeshFaceLabels));
  int32_t* faceLabels = faceLabelsPtr->GetPointer(0);

  int nTriangles = trianglePtr->GetNumberOfTuples();

  // Store all the unique Spins
  std::set<int> uniqueSpins;
  for (int i = 0; i < nTriangles; i++)
  {
    uniqueSpins.insert(faceLabels[i*2]);
    uniqueSpins.insert(faceLabels[i*2+1]);
  }

  int spin = 0;

  //Loop over the unique Spins
  for (std::set<int>::iterator spinIter = uniqueSpins.begin(); spinIter != uniqueSpins.end(); ++spinIter )
  {
    spin = *spinIter;
    if(spin < 0) { continue; }

    fprintf(f, "*ELSET, ELSET=Grain%d\n", spin);

    ss.str("");
    ss << "Writing ELSET for Grain Id " << spin;
    notifyStatusMessage(ss.str());


    // Loop over all the triangles for this spin
    int lineCount = 0;
    for(int t = 0; t < nTriangles; ++t)
    {
      if (faceLabels[t*2] != spin && faceLabels[t*2+1] != spin)
      {
        continue; // We do not match either spin so move to the next triangle
      }

      // Only print 15 Triangles per line
      if (lineCount == 15)
      {
        fprintf(f, ", %d\n", t);
        lineCount = 0;
      }
      else if(lineCount == 0) // First value on the line
      {
        fprintf(f,"%d", t);
        lineCount++;
      }
      else
      {
        fprintf(f,", %d", t);
        lineCount++;
      }

    }
    // Make sure we have a new line at the end of the section
    if (lineCount != 0)
    {
      fprintf(f, "\n");
    }
  }
  return err;
}