//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2016 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.
//
#ifndef MESHPROCESSEXPORT_HPP
#define MESHPROCESSEXPORT_HPP
#include <Process.hpp>

#include <QFileDialog>
#include <GraphUtils.hpp>
#include <QTreeWidget>

#include <MeshProcessPDG.hpp> //jInfo

class Ui_PlyCellGraphDlg;

namespace mgx
{


  struct PlyCellData{

    QString name, type;

    std::map<int, int> intData;
    std::map<int, float> floatData;
    std::map<int, Point3f> pointData;
    std::map<int, SymmetricTensor> tensorData;

  };

  struct PlyWallData{

    QString name, type;
    std::map<std::pair<int, int>, int> intData;
    std::map<std::pair<int, int>, float> floatData;
    std::map<std::pair<int, int>, Point3f> pointData;
    std::map<std::pair<int, int>, SymmetricTensor> tensorData;


  };


  void createPlyDataFromAttr(Mesh* m, QStringList attrMapsToBeSaved, std::vector<PlyCellData>& cellVec, std::vector<PlyWallData>& wallVec);
  void fillTreeWidgetWithAttrMaps(Mesh* m, QTreeWidget* tree, QStringList *selected = 0);

  class mgxBase_EXPORT SavePlyFile : public Process
  {
    Q_OBJECT
  public:
    QStringList attrMapsToBeSaved;

    Ui_PlyCellGraphDlg* ui;

    SavePlyFile(const Process& process) : Process(process)
    {
	  setName("Mesh/Export/Cell Graph Ply File Save");
	  setDesc("Saves a standard PLY file and a cell graph PLY file with specified attributes. If Marion's file is selected than it will create a file with a fixed set of attributes.");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));

	  addParm("Filename","Filename","");
	  addParm("Mesh Type","Mesh Type","2D", QStringList() << "2D" << "3D");
	}
    bool processParms();

    bool initialize(QWidget* parent);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, parm("Filename"), parm("Mesh Type"));
    }

    bool run(Mesh* mesh, QString filename, QString meshType);

  public slots:

    void selectAll();
    void unselectAll();
 };

  class mgxBase_EXPORT LoadPlyFileCellGraph : public Process
  {
  public:
    LoadPlyFileCellGraph(const Process& process) : Process(process)
    {
	  setName("Mesh/Export/Cell Graph Ply File Load");
	  setDesc("Loads Cell Graph data from a file and creates Attribute Maps from the data.");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));

	  addParm("Filename","Filename","");
	}

    bool processParms();

    bool initialize(QWidget* parent);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, parm("Filename"));
    }

    bool run(Mesh* mesh, const QString& filename);

  };

  class mgxBase_EXPORT SaveCellContourFile : public Process
  {
  public:
    SaveCellContourFile(const Process& process) : Process(process)
    {
	  setName("Mesh/Export/Cell Contour File Save");
	  setDesc("Saves a cell contour file to be used in Babak's leaf interogator software");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));

	  addParm("Filename","Filename","");
	}

    bool processParms();

    bool initialize(QWidget* parent);

    bool run()
    {
      if(!checkState().mesh(MESH_ANY))
        return false;
      Mesh *mesh = currentMesh();
      return run(mesh, parm("Filename"));
    }

    bool run(Mesh* mesh, const QString& filename);

  };


    /**
     * \class ExportInternalAngles
     *
     * TODO
     */
    class mgxBase_EXPORT ExportInternalAngles : public Process {
    public:
      ExportInternalAngles(const Process& proc) : Process(proc)
      {
      setName("Mesh/Export/Export Internal Angles");
      setDesc("TBD");
      setIcon(QIcon(":/images/open.png"));

      addParm("Filename","Filename","");
      addParm("Junction Merging Threshold","Junction Merging Threshold","0.1");

      }

      bool run()
      {
        Mesh* m = currentMesh();
        return run(m, parm("Filename"), parm("Junction Merging Threshold").toDouble());
      }
      bool run(Mesh* m, QString filename, double threshold);

      bool initialize(QWidget* parent);
    };

    /**
     * \class ExportJunctionAngles
     *
     * TODO
     */
    class mgxBase_EXPORT ExportJunctionAngles : public Process {
    public:
      ExportJunctionAngles(const Process& proc) : Process(proc)
      {
      setName("Mesh/Export/Export Junction Angles");
      setDesc("Compute wall angles at the cell junctions and export them to a file.");
      setIcon(QIcon(":/images/open.png"));

      addParm("Filename","Filename","");
      addParm("Inclusion Radius","Inclusion Radius","1.0");
      addParm("Method","Method","Furthest", QStringList() << "Closest" << "Average" << "Furthest");

      }

      bool run()
      {
        Mesh* m = currentMesh();
        Mesh* m2 = otherMesh();
        return run(m, m2, parm("Filename"), parm("Inclusion Radius").toDouble(), parm("Method"));
      }
      bool run(Mesh* m, Mesh* m2, QString filename, double thresholdDis, QString method);

      bool initialize(QWidget* parent);
    };

    /**
     * \class ExportJunctionAngles
     *
     * TODO
     */
    class mgxBase_EXPORT ExportJunctionAnglesNew : public Process {
    public:
      ExportJunctionAnglesNew(const Process& proc) : Process(proc)
      {
      setName("Mesh/Export/Export Junction Angles New");
      setDesc("Compute wall angles at the cell junctions and export them to a file.");
      setIcon(QIcon(":/images/open.png"));

      addParm("Filename","Filename","");
      addParm("Inclusion Radius","Inclusion Radius","1.0");
      addParm("Method","Method","Furthest", QStringList() << "Closest" << "Average" << "Furthest");
      addParm("Change Map","Change Map","No",booleanChoice());

      }

      bool run()
      {
        Mesh* m = currentMesh();
        Mesh* m2 = otherMesh();
        return run(m, m2, parm("Filename"), parm("Inclusion Radius").toDouble(), parm("Method"), stringToBool(parm("Change Map")));
      }
      bool run(Mesh* m, Mesh* m2, QString filename, double thresholdDis, QString method, bool changeMap);

      bool initialize(QWidget* parent);
    };

}

#endif
