#ifndef CELL_ATLAS_MERISTEM_HPP
#define CELL_ATLAS_MERISTEM_HPP

#include <CellAtlasConfig.hpp>

#include <Process.hpp>
#include <RootCellAnalyzing.hpp>
#include <CellAtlas.hpp>

using namespace std;

namespace mgx
{

 class CellAtlas_EXPORT AnalyzeMeristem : public Process
  {
    public:
      AnalyzeMeristem(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Atlas 3D/Meristem/Advanced/Analyze Meristem");
		setDesc("Analyzes the meristem and calculates the cell centroids, volumes and radial distances to the surface mesh.  \n"
		"Requires the meristem mesh in mesh 1 and a surface mesh in mesh 2. \n"
		"Use Tools/Heatmaps or Create Point Cloud to visualize the data.");
		setIcon(QIcon(":/images/CellAtlas.png"));

		addParm("Min Volume","Minimum cell volume (cells with smaller volume will be ignored)","0");	// 0
	  }

      bool run()
      {
        Mesh *m1 = mesh(0);
        Mesh *m2 = mesh(1);
        return run(m1, m2, parm("Min Volume").toDouble());
      }

      bool run(Mesh *m1, Mesh *m2, double volThreshold);


  };

  class CellAtlas_EXPORT DetectLayers : public Process
  {
    public:
      DetectLayers(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Atlas 3D/Meristem/Advanced/Detect Cell Layers L1 to L3");
		setDesc("Sets the Parents of the first three cell layers to 1, 2 and 3. \n"
		"Requires the process Analyze Meristem.");
		setIcon(QIcon(":/images/CellAtlas.png"));

		addParm("Cone Angle","Cone Angle (in Rad)","0.9");
		addParm("Detect L2/3 by neighborhood","If No use cones for all 3 layers, if Yes use cone only for L1 and detect L2/3 by neighborhood","No",booleanChoice());
	  }

      bool run(){
        Mesh *m1 = mesh(0);
        return run(m1, parm("Cone Angle").toDouble(), stringToBool(parm("Detect L2/3 by neighborhood")));
      }

      bool run(Mesh *m1, double coneAngle, bool detectByNeighborhood);

  };

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

		addParm("Use Surface","Use Surface","Yes",booleanChoice());
		addParm("Cone Angle","Cone Angle (in Rad)","0.9");
		addParm("Number of Layers","Number of Layers","3");
		addParm("Min Shared Cell Wall","Min Shared Cell Wall","0.0");
		addParm("Min Cell Volume","Min Cell Volume","0");
	  }

      bool run() {
        Mesh *m1 = mesh(0);
        return run(m1, stringToBool(parm("Use Surface")), parm("Cone Angle").toDouble(), parm("Number of Layers").toInt(), parm("Min Shared Cell Wall").toDouble(), parm("Min Cell Volume").toDouble());
      }

      bool run(Mesh *m1, bool useSurface, double coneAngle, int layers, double minWall, double minVolume);

  };

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

    addParm("Use Surface","Use Surface","Yes",booleanChoice());
    addParm("Cone Angle","Cone Angle (in Rad)","0.9");
    addParm("Number of Layers","Number of Layers","3");
    addParm("Min Shared Cell Wall","Min Shared Cell Wall","0.0");
    addParm("Min Cell Volume","Min Cell Volume","0");
    }

      bool run() {
        Mesh *m1 = mesh(0);
        return run(m1, stringToBool(parm("Use Surface")), parm("Cone Angle").toDouble(), parm("Number of Layers").toInt(), parm("Min Shared Cell Wall").toDouble(), parm("Min Cell Volume").toDouble());
      }

      bool run(Mesh *m1, bool useSurface, double coneAngle, int layers, double minWall, double minVolume);

  };



  class CellAtlas_EXPORT MarkMeristem : public Process
  {
    public:
      MarkMeristem(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Atlas 3D/Meristem/Advanced/Mark Meristem");
		setDesc("Sets the Parents of the first 2 cell layers, the stem cells and the organizing center. \n"

		"Requires a selected center cell and the process Analyze Meristem.");
		setIcon(QIcon(":/images/CellAtlas.png"));


		addParm("Depth Org Center","Specifying the depth of the organizing center under the selected center of the meristem","1.25");
		addParm("Radius","Radius of stem cell region and organizing center","1.0");
	  }

      bool run() {
        Mesh *m1 = mesh(0);
        return run(m1, parm("Depth Org Center").toDouble(), parm("Radius").toDouble());
      }

      bool run(Mesh *m1, double disDown, double radius);


  };

class CellAtlas_EXPORT LabelMeristem : public Process
  {
    public:
      LabelMeristem(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Atlas 3D/Meristem/Label Meristem");
		setDesc("Analyzes the cells of the meristem, sets the Parents of the first 2 cell layers, \n"
		"the stem cells and the organizing center. \n"
		"This process calls the following processes (in this order): Analyze Meristem, Detect Layers and Mark Meristem.");
		setIcon(QIcon(":/images/CellAtlas.png"));

		addParm("Min Volume","Min Volume","0");
		addParm("Depth Org Center","Specifying the depth of the organizing center under the selected center of the meristem","1.25");
		addParm("Radius","Radius of stem cell region and organizing center","1.0");
		addParm("Cone Angle","Cone Angle (in Rad)","0.9");


		  }

      bool run() {
        Mesh *m1 = mesh(0);
        Mesh *m2 = mesh(1);
        return run(m1, m2, parm("Min Volume").toDouble(), parm("Depth Org Center").toDouble(), parm("Radius").toDouble(), parm("Cone Angle").toDouble());
      }

      bool run(Mesh *m1, Mesh *m2, double minVolume, double disDown, double radius, double coneAngle);

  };

  class CellAtlas_EXPORT MarkPrim : public Process
  {
    public:
      MarkPrim(const Process& process) : Process(process)
      {
		setName("Mesh/Cell Atlas 3D/Meristem/Mark Primordium");
		setDesc("Distinguishes a primordium from the meristem by changing the color of the parents. \n"

		"Select the primordium center cell and the saddle cell between primordium center and meristem center. \n"
		"Requires the process Label Meristem (or Mark Meristem) to know which cell is the meristem center.");
		setIcon(QIcon(":/images/CellAtlas.png"));

		addParm("Ratio Parameter","Parameter specifying the width of the boundary region between meristem and primordium","0.8");
		addParm("Abs Dis Parameter","Parameter specifying the depth of the boundary region between meristem and primordium","1.3");
		addParm("Primordia Label Same","Primordia specific label prefix, if set to No all primordia will have the same labels","No",booleanChoice());
		addParm("Label Saddle Cell","Label of the saddle cell between meristem and primodrium center","0");
		addParm("Label Prim Center","Label of the primordium center cell","0");

	  }

      bool run(){
        Mesh *m1 = mesh(0);
        return run(m1, parm("Ratio Parameter").toDouble(), parm("Abs Dis Parameter").toDouble(), stringToBool(parm("Primordia Label Same")), parm("Label Saddle Cell").toInt(), parm("Label Prim Center").toInt());
      }

      bool run(Mesh *m1, double ratioParm, double absDisParm, bool primLabelSame, int labelSaddle, int labelPrim);

  };



}

#endif
