//
// 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 STACKPROCESSANALYSES_HPP
#define STACKPROCESSANALYSES_HPP

#include <Process.hpp>

namespace mgx
{
  ///\addtogroup StackProcess
  ///@{
  /**
   * \class ComputeVolume ProcessAnalyses.hpp <StackProcessAnalyses.hpp>
   *
   * Compute the volume of each label and write the result in a CSV file.
   *
   * The volume is computed as the product between the number of voxel for each
   * label, and the volume of a single voxel.
   */
  class mgxBase_EXPORT ComputeVolume : public Process
  {
  public:
    ComputeVolume(const Process& process) : Process(process)
    {
	  setName("Stack/Analyses/Compute Volumes");
	  setDesc("Compute the volumes of the labels, i.e. the number of voxels multiplied by the voxel size.");
	  setIcon(QIcon(":/images/CellFiles3D.png"));

	  addParm("Filename","Filename","output.csv");
	}

    bool run()
    {
      if(!checkState().store(STORE_NON_EMPTY | STORE_LABEL))
        return false;
      Store* input = currentStack()->currentStore();
      return run(input, parm("Filename"));
    }

    bool run(const Store* input, QString filename);

  };


class mgxBase_EXPORT StackVoxelCount : public Process
  {
  public:
    StackVoxelCount(const Process& process) : Process(process)
    {
      setName("Stack/Analyses/Export Voxel Count");
      setDesc("Count the occurance of different voxel values along the z-axis and export it to a file");
      setIcon(QIcon(":/images/MakeHeatMap.png"));

      addParm("Filename","Filename","");
	}
    //bool initialize(QStringList& parms, QWidget* parent);

    bool run()
    {
      Stack* s1 = currentStack();
      Store* store1 = s1->main();
      //Store* store2 = s1->work();
      //Mesh* m = currentMesh();
      return run(s1, store1, parm("Filename"));
    }
    bool run(Stack* s1, Store* store1, QString filename);

  };

class mgxBase_EXPORT StackCircularHistogram : public Process
  {
  public:
    StackCircularHistogram(const Process& process) : Process(process)
    {
	  setName("Stack/Analyses/Export Histogram Circular");
	  setDesc("Computes a circular histogram in counter-clockwise direction of the active main store signal values around the given cartesian axis.");
      setIcon(QIcon(":/images/StackHistoCirc.png"));

	  addParm("Central Axis","Central Axis","Z", QStringList() << "X" << "Y" << "Z");
	  addParm("Bin Number","Number of bins for the whole circle","360");
    addParm("Voxel Value Threshold (%)","Ignore voxels with values lower than this threshold (% from 16bit value). Set to 0 to include all. Ignoring low values can speed this process up significantly","1.0");
    addParm("Voxel Distance Min (um)","Only consider voxels with a minimum distance to the Bezier larger than this. Set to -1 to include all.","-1");
    addParm("Voxel Distance Max (um)","Only consider voxels with a maximum distance to the Bezier smaller than this. Set to -1 to include all.","-1");
    addParm("Align at Max","Align at Max","No", QStringList() << "Align at Max of Signal Sum" << "Align at Signal Max" << "No");
	  addParm("Weight by Volume","Weight signal values by the voxel volume","Yes",booleanChoice());
	  addParm("Filename","Filename","");
    addParm("Fill Labels in Other Store","Fill the other store with the bin labels of all voxels in range","No",booleanChoice());
	}

    bool initialize(QWidget* parent);

    bool run()
    {
      Stack* s1 = currentStack();
      //Store* store1 = s1->currentStore();
      Store* store1 = s1->main();
      Store* store2 = s1->work();
      return run(s1, store1, store2, parm("Central Axis"), parm("Bin Number").toInt(), parm("Voxel Value Threshold (%)").toDouble(), parm("Voxel Distance Min (um)").toDouble(),
        parm("Voxel Distance Max (um)").toDouble(), parm("Align at Max"), stringToBool(parm("Weight by Volume")), parm("Filename"), stringToBool(parm("Fill Labels in Other Store")));
    }
    bool run(Stack* s1, Store* store1, Store* store2, QString centralAxis, int binNumber, double thresholdValue, double minDis, double maxDis, QString align, bool weightVol, QString filename, bool writeStack);

  };


  class mgxBase_EXPORT StackHistogramBezier : public Process
  {
  public:
    StackHistogramBezier(const Process& process) : Process(process)
    {
    setName("Stack/Analyses/Export Histogram Bezier");
    setDesc("Export a histogram of voxel (signal) values of the active main store binned according to coordinates along a Bezier line.");
    setIcon(QIcon(":/images/StackHistoLine.png"));

    addParm("Bin Size (um)","Bin Size (um)","10");
    addParm("Voxel Value Threshold (%)","Ignore voxels with values lower than this threshold (% from 16bit value). Set to 0 to include all. Ignoring low values can speed this process up significantly","1.0");
    addParm("Voxel Distance Min (um)","Only consider voxels with a minimum distance to the Bezier larger than this. Set to -1 to include all.","-1");
    addParm("Voxel Distance Max (um)","Only consider voxels with a maximum distance to the Bezier smaller than this. Set to -1 to include all.","-1");
    addParm("Bezier Discretization","Bezier Discretization","100");
    addParm("Filename","Filename","");
    addParm("Fill Labels in Other Store","Fill the other store with the bin labels of all voxels in range","No",booleanChoice());
  }

    bool initialize(QWidget* parent);

    bool run()
    {
      Stack* s1 = currentStack();
      //Store* store1 = s1->currentStore();
      Store* store1 = s1->main();
      Store* store2 = s1->work();
      Mesh* m = currentMesh();
      return run(s1, store1, store2, m, parm("Bin Size (um)").toDouble(), parm("Voxel Value Threshold (%)").toDouble(), parm("Voxel Distance Min (um)").toDouble(),
        parm("Voxel Distance Max (um)").toDouble(), parm("Bezier Discretization").toInt(), parm("Filename"), stringToBool(parm("Fill Labels in Other Store")));
    }

    bool run(Stack* s1, Store* store1, Store* store2, Mesh* m, double binSize, double ignoreLow, double minDis, double maxDis, int bezPoints, QString filename, bool writeStack);

  };


class mgxBase_EXPORT StackBorderFromSegmented : public Process
  {
  public:
    StackBorderFromSegmented(const Process& process) : Process(process)
    {
	  setName("Stack/Analyses/Border from Segmented Stack");
	  setDesc("From a segmented stack in the main stack border voxels are set to max in the work stack.");
	  setIcon(QIcon(":/images/MakeHeatMap.png"));

	  addParm("Width","Width","1");
	  addParm("Ignore X","Ignore X","No",booleanChoice());
	  addParm("Ignore Y","Ignore Y","No",booleanChoice());
	  addParm("Ignore Z","Ignore Z","Yes",booleanChoice());
		}

    bool run()
    {
      Stack* s1 = currentStack();
      Store* store1 = s1->main();
      return run(s1, store1, parm("Width").toInt(), stringToBool(parm("Ignore X")), stringToBool(parm("Ignore Y")), stringToBool(parm("Ignore Z")));
    }
    bool run(Stack* s1, Store* store1, int width, bool ignX, bool ignY, bool ignZ);

  };

  ///@}
}
#endif
