//
// 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.
// 
#ifndef TISSUECURVATURE_HPP
#define TISSUECURVATURE_HPP

#include <Process.hpp>

#include <MeshProcessCellMesh.hpp>

namespace mgx
{
  ///\addtogroup MeshProcess
  ///@{
  /**
   * \class TissueCurvature ProcessCurv.hpp <MeshProcessCurv.hpp>
   *
   * Compute the curvature tensor for each cell of a cell mesh. If the tissue
   * is a full mesh, it will first be simplified into a cell mesh.
   * */
  class mgxBase_EXPORT TissueCurvature : public Process {
  public:
    TissueCurvature(const Process& process) : Process(process) 
    {
	  setName("Mesh/Cell Axis/Curvature/Compute Tissue Curvature");
	  setDesc("Compute curvature based on simplified mesh (from Make Cells) for a neighborhood of given radius.");
	  setIcon(QIcon(":/images/Curvature.png"));

	  addParm("Radius","Radius for curvature calculation (µm)","10.0");
	  addParm("Selected Cell","Compute curvature only for selected cell","No",booleanChoice());
	}
  
    bool run()
    {
      double radius = parm("Radius").toDouble();
      if(radius <= 0)
        throw QString("%1::run Radius must be > 0").arg(name());
      return run(currentMesh(), radius, stringToBool(parm("Selected Cell")));
    }
  
    bool run(Mesh* mesh, float neighborhood, bool checkLabel);
  
  };
  
  /**
   * \class DisplayTissueCurvature ProcessCurv.hpp <MeshProcessCurv.hpp>
   *
   * Once the curvature tensor has been computed, this process allows to change
   * how it is displayed.
   */
  class mgxBase_EXPORT DisplayTissueCurvature : public Process {
  public:
    DisplayTissueCurvature(const Process& process) : Process(process) 
    {
	  setName("Mesh/Cell Axis/Curvature/Display Tissue Curvature");
	  setDesc("Display curvature based on cellular mesh");
	  setIcon(QIcon(":/images/Curvature.png"));	

	  addParm("Heatmap","Display curvature values in max or min direction as a color map. \n"
	  "Average: (CurvMax + CurvMin)/2,  SignedAverageAbs: sign(CurvMax or CurvMin) x (abs(CurvMax) + abs(CurvMin))/2,\n"
	  "Gaussian:(CurvMax x CurvMin), RootSumSquare: sqrt(CurvMax^2 + CurvMin^2), Anisotropy: (CurvMax / CurvMin).","SignedAverageAbs", QStringList() << "None" << "CurvMax" << "CurvMin" << "Average" << "SignedAverageAbs" << "Gaussian" << "RootSumSquare" << "Anisotropy");
	  addParm("Compare to 0","Center the color map on zero, if negtive values exist.","Yes",booleanChoice());
	  addParm("Heatmap percentile","Percentile of values used for color map upper-lower bounds.","85.0");
	  addParm("Show Axis","Draw main curvature directions as vectors, scaled by 1/(curvature radius).","Both", QStringList() << "Both" << "CurvMax" << "CurvMin" << "None");	// 3
	  addParm("Color +","Color used for convex (curvature > 0)","white", QColor::colorNames());
	  addParm("Color -","Color used for concave (curvature < 0)","red", QColor::colorNames());
	  addParm("Line Width","Line width","2.0");
	  addParm("Line Scale","Length of the vectors = Scale * 1/(curvature radius).","100.0");
	  addParm("Line Offset","Draw the vector ends a bit tilted up for proper display on surfaces.","0.1");
	  addParm("Threshold","Minimal value of curvature required for drawing the directions.","0.0");	
	}
  
    bool run()
    {
      if(!checkState().mesh(MESH_NON_EMPTY))
        return false;
  
      bool ok;
      float heatmapPercentile = parm("Heatmap percentile").toFloat(&ok);
      if(not ok)
        return setErrorMessage("Error, argument 'Heatmap percentile' must be a number");
      float axisLineWidth = parm("Line Width").toFloat(&ok);
      if(not ok)
        return setErrorMessage("Error, argument 'Line Width' must be a number");
      float axisLineScale = parm("Line Scale").toFloat(&ok);
      if(not ok)
        return setErrorMessage("Error, argument 'Line Scale' must be a number");
      float axisOffset = parm("Line Offset").toFloat(&ok);
      if(not ok)
        return setErrorMessage("Error, argument 'Line Offset' must be a number");
      float threshold = parm("Threshold").toFloat(&ok);
      if(not ok)
        return setErrorMessage("Error, argument 'Threshold' must be a number");
  
      return run(currentMesh(), parm("Heatmap"), stringToBool(parm("Compare to 0")), heatmapPercentile, 
                 parm("Show Axis"), QColor(parm("Color +")), QColor(parm("Color -")), axisLineWidth, axisLineScale, 
                                                                      axisOffset, threshold);
    }
  
    bool run(Mesh* mesh, QString DisplayHeatMap, bool compareZero, float heatmapPercentile, 
                 QString DisplayCurv, const QColor& ColorExpansion, const QColor& ColorShrinkage, 
                 float AxisLineWidth, float AxisLineScale, float AxisOffset, float CurvThreshold);
  
  };
  ///@}
}

#endif
