//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2015 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#include "ExportMeshToFile.hpp"
#include "Progress.hpp"
#include <omp.h>

#include <QFileDialog>

namespace mgx 
{
  // Initialize, pop-up dialog to get filename (runs in GUI thread)
  bool ExportMeshToFile::initialize(QWidget* parent)
  {
    QString fileName = parm("File Name");
    QString fileType = parm("File Type");
  
    QString objFilter("Wavefront OBJ files (*.obj)");
    QString plyFilter("Stanford Polygon Files (*.ply)");
  
    QString filterList = QString("%1;;%2").arg(objFilter).arg(plyFilter);
  
    QString filter;
  
    if(fileName.endsWith(".obj", Qt::CaseInsensitive))
      filter = objFilter;
    else if(fileName.endsWith(".ply", Qt::CaseInsensitive))
      filter = plyFilter;
  
    // Get the file name
    fileName = QFileDialog::getSaveFileName(parent, QString("Select export file"), fileName, filterList, &filter, 0);
  
    // Return error if no file name
    if(fileName.isEmpty())
      return false;
  
    // Add extension if not there
    if(filter == objFilter) {
      if(!fileName.endsWith(".obj", Qt::CaseInsensitive))
        fileName += ".obj";
      setParm("File Type", "obj");
    } else if(filter == plyFilter) {
      if(!fileName.endsWith(".ply", Qt::CaseInsensitive))
        fileName += ".ply";
      setParm("File Type", "ply");
    }
  
    // Save the fileName to the parameters
    setParm("File Name", fileName);
  
    return true;
  }
  
  
  // Do the work (runs in process thread)
  bool ExportMeshToFile::run(Mesh* mesh, const QString &fileName, const QString &fileType)
  {
    QFile file(fileName);
  
    // Open file fopr writing
    if(!file.open(QIODevice::WriteOnly))
      throw QString("%1: Cannot open output file: %2").arg(name()).arg(fileName);
  
    // Get the graph for the mesh
    const vvGraph &S = mesh->graph();
  
    // Create output stream
    QTextStream out(&file);
  
    // Start the progress bar
    Progress& progress = Progress::instance();
    progress.start(QString("Saving Text Mesh %1 in File '%2'").arg(mesh->userId()).arg(fileName), S.size() * 2);
  
    // Used to number vertices
    int saveId = 0, i = 0;
    // Save OBJ File
    if(fileType == "obj") {
      // First write the vertices and normals, mark the id of each
      forall(const vertex& v, S) {
        if(!progress.advance(i++))
          userCancel();
        v->saveId = saveId++;
        out << "v " << v->pos << endl;
        out << "vn " << v->nrml << endl;
      }
  
      // Write the triangles
      forall(const vertex& v, S)
        // loop over the neighborhoods of the vertices
        forall(const vertex& n, S.neighbors(v)) {
          if(!progress.advance(i++))
            userCancel();
          // Get vertex next to n in neighborhood of v
          vertex m = S.nextTo(v, n);
          // The three vertices make a triangle, write if unique
          if(S.uniqueTri(v, n, m))
            out << "f " << v->saveId + 1 << " " << n->saveId + 1 << " " << m->saveId + 1 << endl;
        }
    } else if(fileType == "ply") {
      // First count the triangles for the header
      int triCount = 0;
      forall(const vertex& v, S)
        forall(const vertex& n, S.neighbors(v)) {
          vertex m = S.nextTo(v, n);
          if(S.uniqueTri(v, n, m))
            triCount++;
        }
      // Write header
      out << "ply" << endl;
      out << "format ascii 1.0" << endl;
      out << "element vertex " << S.size() << endl;
      out << "property float x" << endl;
      out << "property float y" << endl;
      out << "property float z" << endl;
      out << "property float signal" << endl;
      out << "property int label" << endl;
      out << "element face " << triCount << endl;
      out << "property list int int vertex_index" << endl;
      out << "end_header" << endl;
  
      // First write vertices
      forall(const vertex& v, S) {
        if(!progress.advance(i++))
          userCancel();
        out << v->pos << " " << v->signal << " " << v->label << endl;
        v->saveId = saveId++;
      }
      // Now write cells (faces)
      forall(const vertex& v, S) {
        if(!progress.advance(i++))
          userCancel();
        forall(const vertex& n, S.neighbors(v)) {
          vertex m = S.nextTo(v, n);
          if(S.uniqueTri(v, n, m))
            out << "3 " << v->saveId << " " << n->saveId << " " << m->saveId << endl;
        }
      }
    } else
      throw QString("%1: Invalid file type: '%2'").arg(name()).arg(fileType);
  
    file.close();
    SETSTATUS("Export mesh to file:" << mesh->file() << ", vertices:" << S.size());
  
    return true;
  }
  REGISTER_PROCESS(ExportMeshToFile);
}
