//
// This file is part of 3DCellAtlasOvule.
// Copyright (C) 2015-2016 George W. Bassel and collaborators.
//
// 3DCellAtlasOvule is an AddOn for MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2012 Richard S. Smith and collaborators.
//
// MorphoGraphX is free software, and are licensed under under the terms of the
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
//
#ifndef CELL_ATLAS_OVULE_HPP
#define CELL_ATLAS_OVULE_HPP

#include <CellAtlasOvuleConfig.hpp>
#include <Process.hpp>

namespace mgx {


 /**
   * \class Lobyness3D DivisionAnalysis.hpp <DivisionAnalysis.hpp>
   *
   * Lobyness3D
   */
  class CellAtlasOvule_EXPORT Lobyness3D : public Process
  {
    public:
      Lobyness3D(const Process& process) : Process(process){

      	setName("Mesh/Cell Atlas 3D/Ovule/Lobyness 3D");
		setDesc("Lobyness Plugin 3D Version\n"
        "This plugin provides several measures to analyse cell-outlines.\n"
        "Convex (Surface Area): Ratio of cell-surface area over that of its convex hull. Takes a value of 1 for convex shapes, and increases with the complexity of the volume.\n"
        "Convex (Volume): Like Convex (Surface Area), but uses volumes instead of surface areas.\n"
        "Sphericity: (6*cell-volume)^2/3 * PI^1/3 / (cell-area).\n");
		setIcon(QIcon(":/images/CHull.png"));

		addParm("Measure","Measure","Convexity",QStringList() << "Convexity" <<"Solidity"<<"Sphericity"<<"Compactness");
      }

      bool run()
     {
      QString measure = parm("Measure");
      Mesh *m = currentMesh();
      return run(m, measure);
     }

      bool run(Mesh *m, const QString &measure);

  };


class CellAtlasOvule_EXPORT Lobyness3DConvexSurfArea : public Process
  {
  public:
    Lobyness3DConvexSurfArea(const Process& process) : Process(process) {
      setName("Mesh/Cell Atlas 3D/Ovule/Lobyness 3D/Convexity");
		  setDesc("Lobyness Plugin 3D Version\n"
                "Convexity: Cell_Surface_Area / ConvexHull_Cell_Surface_Area\n"
                "Takes a value of 1 for convex shapes, and increases with the complexity of the volume.");
		  setIcon(QIcon(":/images/LobynessPlugin.png"));

    }

      bool run(){
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);

   };

class CellAtlasOvule_EXPORT Lobyness3DConvexVolume : public Process
  {
  public:
    Lobyness3DConvexVolume(const Process& process) : Process(process) {
      setName("Mesh/Cell Atlas 3D/Ovule/Lobyness 3D/Solidity");
      setDesc("Lobyness Plugin 3D Version\n"
                "Solidity: Volume / ConvexHull_Volume");
      setIcon(QIcon(":/images/LobynessPlugin.png"));
    }

      bool run(){
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);

  };

class CellAtlasOvule_EXPORT Lobyness3DSphericity : public Process
  {
  public:
    Lobyness3DSphericity(const Process& process) : Process(process) {
      setName("Mesh/Cell Atlas 3D/Ovule/Lobyness 3D/Sphericity");
      setDesc("Lobyness Plugin 3D Version\n"
                "Sphericity: (36 * PI * Volume^2) / (SurfaceArea^3).");
      setIcon(QIcon(":/images/LobynessPlugin.png"));

    }

      bool run(){
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);
  };

class CellAtlasOvule_EXPORT Lobyness3DCompactness : public Process
  {
  public:
    Lobyness3DCompactness(const Process& process) : Process(process) {
      setName("Mesh/Cell Atlas 3D/Ovule/Lobyness 3D/Compactness");
      setDesc("Lobyness Plugin 3D Version\n"
                "Enclosing Sphere: ((4 * PI * (Longest diameter/2))");
      setIcon(QIcon(":/images/LobynessPlugin.png"));

    }

      bool run(){
        Mesh *m = currentMesh();
        return run(m);
      }

      bool run(Mesh *m);
  };


// class CellAtlasOvule_EXPORT Lobyness3DLargestEmptySphere : public Process
//   {
//   public:
//     Lobyness3DLargestEmptySphere(const Process& process) : Process(process) {}

//       bool run(const QStringList &parms){
//         Mesh *m = currentMesh();
//         return run(m);
//       }

//     bool run(Mesh *m);
//     QString name() const { return "Mesh/Heat Map/Measures 3D/Lobyness/LargestEmptySphere"; }
//     QString description() const { return "Lobyness Plugin 3D Version\n"
//                 "LargestEmptySphere: diameter of the largest sphere the volume can contain";
//                  }
//     QStringList parmNames() const { return QStringList(); }
//     QStringList parmDefaults() const { return QStringList();}
//     QStringList parmDescs() const { return QStringList() ;}
//     QIcon icon() const { return QIcon(":/images/LobynessPlugin.png"); }
//     bool isMeasureProcess() const { return true; }

//   };
 

  // Extract the convex hull of a mesh
  class CellAtlasOvule_EXPORT ConvexHullCGAL : public Process
  {
  public:
    ConvexHullCGAL(const Process& process) : Process(process) 
    {
      setName("Mesh/Cell Atlas 3D/Ovule/Tools/Convex Hull From Mesh");
      setDesc("Convex Hull From Mesh\n"
        "Creates the convex hull from the current mesh &\n"
        "saves the result in the non-active mesh\n"
        "(uses the CGAL library)\n");
      setIcon(QIcon(":/images/CHull.png"));

      addParm("Work on Selection", "Work on Selection", "No", booleanChoice());
    } 

    bool run()
    {
      Mesh *mesh = currentMesh();
      if(!mesh) 
        throw QString("%1 No current mesh").arg(name());

      Mesh *mesh2 = otherMesh();
      
      // consider rotation of stack
      Stack *s = currentStack();
      Matrix4d rotMatrixS1;
      s->getFrame().getMatrix(rotMatrixS1.data());
      Matrix4d mGLTot = transpose(rotMatrixS1);
      
      bool result = run(mesh, mesh2, stringToBool(parm("Work on Selection")), mGLTot);

      return result;
    }
    bool run(Mesh* mesh, Mesh* mesh2, bool workOnSel, Matrix4d mGLTot);
  };


  class CellAtlasOvule_EXPORT LabelOvules : public Process
  {
    public:
      LabelOvules(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Label Ovules");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Max Size","Max Size","6");
    addParm("Export to Attr Map","Export to Attr Map","Ovule");
    }

      bool run() {
        Mesh *m1 = currentMesh();
        return run(m1, parm("Max Size").toInt(), parm("Export to Attr Map"));
      }

      bool run(Mesh *m1, int maxSize, QString ovuleAttr);

  };

  class CellAtlasOvule_EXPORT LabelCellsFromHeat : public Process
  {
    public:
      LabelCellsFromHeat(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Label Cells From Heat");
    setDesc("Detect cell layers and label them accordingly");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Heat Value 1","Heat Value 1","3");
    addParm("Heat Value 2","Heat Value 2","4");
    addParm("Heat Value 3","Heat Value 3","-1");
    addParm("Heat Value 4","Heat Value 4","-1");
    addParm("Heat Value 5","Heat Value 5","-1");
    addParm("Heat Value 6 or Greater","Heat Value 6","7");
    addParm("Overwrite Existing Parents","Overwrite Existing Parents","No",booleanChoice());
    }

      bool run() {
        Mesh *m1 = currentMesh();
        return run(m1, parm("Heat Value 1").toInt(), parm("Heat Value 2").toInt(), parm("Heat Value 3").toInt(),
          parm("Heat Value 4").toInt(), parm("Heat Value 5").toInt(), parm("Heat Value 6 or Greater").toInt(), stringToBool(parm("Overwrite Existing Parents")));
      }

      bool run(Mesh *m1, int h1, int h2, int h3, int h4, int h5, int h6, bool overwrite);

  };



  class CellAtlasOvule_EXPORT DetectCellLayersStack : public Process
  {
    public:
      DetectCellLayersStack(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Detect Cell Layers Stack");
    setDesc("Detect cell layers and label them accordingly");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Number of Layers","Number of Layers","3");
    addParm("Min Shared Voxels","Min Shared Voxels","1");
    addParm("Export to Attr Map","Export to Attr Map","Layers");

    }

      bool run() {
        Mesh *m1 = mesh(0);
        Stack* s1 = currentStack();
        Store* store1 = s1->currentStore();
        return run(m1, s1, store1, parm("Number of Layers").toInt(), parm("Min Shared Voxels").toInt(), parm("Export to Attr Map"));
      }

      bool run(Mesh *m1, Stack* s1, Store* store1, int layers, int minShared, QString exportAttr);

  };


  class CellAtlasOvule_EXPORT NeighborVoxelsStack : public Process
  {
    public:
      NeighborVoxelsStack(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Neighbor Voxels Stack");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Heat Map","Heat Map","Outside Voxels", QStringList() << "Outside Voxels");
    }

      bool run() {
        Mesh *m1 = mesh(0);
        Stack* s1 = currentStack();
        Store* store1 = s1->currentStore();
        return run(m1, s1, store1, parm("Heat Map"));
      }

      bool run(Mesh *m1, Stack* s1, Store* store1, QString heatmap);

  };

  class CellAtlasOvule_EXPORT RemoveRegressionHeatmap : public Process
  {
    public:
      RemoveRegressionHeatmap(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Remove Regression Heatmap");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Heatmap X","Heatmap X","X");
    addParm("Heatmap Y","Heatmap Y","Y");
    }

      bool run() {
        Mesh *m1 = mesh(0);
        //Stack* s1 = currentStack();
        //Store* store1 = s1->currentStore();
        return run(m1, parm("Heatmap X"), parm("Heatmap Y"));
      }

      bool run(Mesh *m, QString heatX, QString heatY);

  };


  class CellAtlasOvule_EXPORT RemoveRegressionStack : public Process
  {
    public:
      RemoveRegressionStack(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Remove Regression Stack");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Dimension","Dimension","Z");
    addParm("Low Threshold (%)","Ignore voxels with a value lower than this","1.0");
    addParm("High Threshold (%)","Ignore voxels with a value higher than this","99.0");
    }

      bool run() {
        Mesh *m1 = mesh(0);
        Stack* s1 = currentStack();
        Store* store1 = s1->currentStore();
        Store* store2 = s1->work();
        return run(m1, s1, store1, store2, parm("Dimension"), parm("Low Threshold (%)").toDouble(), parm("High Threshold (%)").toDouble());
      }

      bool run(Mesh *m, Stack* s1, Store* store1, Store* store2, QString dim, double lowT, double highT);

  };

  class CellAtlasOvule_EXPORT DeleteStackLabelsByParent : public Process
  {
    public:
      DeleteStackLabelsByParent(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Delete Stack Labels by Parent");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Parent Label","Parent Label","0");
    }

      bool run() {
        Mesh *m1 = mesh(0);
        Stack* s1 = currentStack();
        Store* store1 = s1->currentStore();
        return run(m1, s1, store1, parm("Parent Label").toInt());
      }

      bool run(Mesh *m, Stack* s1, Store* store1, int parentLabel);

  };

  class CellAtlasOvule_EXPORT DefineML : public Process
  {
    public:
      DefineML(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/DefineML");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Use Surface Dirs","Use Surface Dirs","No",booleanChoice());
    addParm("Custom Dir","Custom Dir","X",QStringList() << "X" << "Y" << "Z");
    addParm("Weight Surface Dirs (%)","Weight Use Surface Dirs (%)","50.0");
    }

      bool run() {
        Mesh *m1 = currentMesh();
        Mesh *m2 = otherMesh();
        return run(m1, m2, parm("Custom Dir"), stringToBool(parm("Use Surface Dirs")), parm("Weight Surface Dirs (%)").toDouble());
      }

      bool run(Mesh *m1, Mesh *m2, QString customDir, bool useSurf, double weightSurf);

  };


  class CellAtlasOvule_EXPORT DefineAntPost : public Process
  {
    public:
      DefineAntPost(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/DefineAntPost");
    setDesc("TBD");
    setIcon(QIcon(":/images/CellAtlas.png"));

    addParm("Separation","Separation","Mean",QStringList() << "Mean" << "Median");

    }

      bool run() {
        Mesh *m1 = currentMesh();
        return run(m1, parm("Separation"));
      }

      bool run(Mesh *m1, QString sep);

  };

  class CellAtlasOvule_EXPORT SelectCellCutByBezier : public Process
  {
    public:
      SelectCellCutByBezier(const Process& process) : Process(process)
      {
    setName("Mesh/Cell Atlas 3D/Ovule/Select Cells Cut By Bezier");
    setDesc("Select all cells that are cut by the current Bezier grid.");
    setIcon(QIcon(":/images/CellAtlas.png"));

    }

      bool run() {
        Mesh *m1 = currentMesh();
        Stack *s1 = currentStack();
        return run(s1, m1);
      }

      bool run(const Stack *s1, Mesh *m1);

  };




}


#endif
