//
// 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.
//

// Surface class
#ifndef DYNAMX_PROCESS_POLAR_SURFACE_HPP
#define DYNAMX_PROCESS_POLAR_SURFACE_HPP

#include <Process.hpp>
#include <PolarSurface.hpp>
#include <Function.hpp>

namespace mgx
{
  // Process to hold polar surface parameters
  class mgxBase_EXPORT PolarSurfaceParms : public Process 
  {
  public:
    PolarSurfaceParms(const Process &process) : Process(process) {}

    // Don't do anything, process is only for parms
    bool run(const QStringList &) { return true; }

    // Functions for Gui
    QString description() const { return "Parameters for Polar Surface"; }

    QStringList parmNames() const 
    {
						// make a vector of size pNumParms containing the names of parameters for the GUI
      QVector <QString> vec(PolarSurface::pNumParms);

      vec[PolarSurface::pGrowthType] = "GrowthType";
      vec[PolarSurface::pSurfaceContour] = "SurfaceContour";
      vec[PolarSurface::pArcLengthGrowth] = "ArcLengthGrowth";
      vec[PolarSurface::pSurfaceScale] = "SurfaceScale";
      vec[PolarSurface::pGrowthScaleInMult] = "GrowthScaleInMult";
      vec[PolarSurface::pGrowthScaleOutMult] = "GrowthScaleOutMult";
      vec[PolarSurface::pGrowthScaleFunc] = "GrowthScaleFunc";
      vec[PolarSurface::pRootSearchMaxSteps] = "RootSearchMaxSteps";

      return vec.toList();
    }
    QStringList parmDescs() const 
    {
      QVector <QString> vec(PolarSurface::pNumParms);

      vec[PolarSurface::pGrowthType] = "Arclength surface of revolution";
      vec[PolarSurface::pSurfaceContour] = "Surface contour definition file";
      vec[PolarSurface::pArcLengthGrowth] = "Arclength growth function";
      vec[PolarSurface::pSurfaceScale] = "Contour function Multiplier";
      vec[PolarSurface::pGrowthScaleInMult] = "Growth function Multiplier";
      vec[PolarSurface::pGrowthScaleOutMult] = "Growth function Multiplier";
      vec[PolarSurface::pGrowthScaleFunc] = "Growth scale function";
      vec[PolarSurface::pRootSearchMaxSteps] = "Max number of iterations for point inversion";

      return vec.toList();
    }
    QStringList parmDefaults() const 
    {
      QVector <QString> vec(PolarSurface::pNumParms);

      vec[PolarSurface::pGrowthType] = "0";
      vec[PolarSurface::pSurfaceContour] = "Surface.con";
      vec[PolarSurface::pArcLengthGrowth] = "Growth.func";
      vec[PolarSurface::pSurfaceScale] = "100";
      vec[PolarSurface::pGrowthScaleInMult] = "1";
      vec[PolarSurface::pGrowthScaleOutMult] = "150";
      vec[PolarSurface::pGrowthScaleFunc] = "GrowthScale.func";
      vec[PolarSurface::pRootSearchMaxSteps] = "100";

      return vec.toList();
    }
    // Icon file
    QIcon icon() const { return QIcon(":/images/Parameters.png"); }
  };

  class mgxBase_EXPORT PolarSurfaceGrowth : public Process 
  {
  public:
    PolarSurfaceGrowth(const Process &process) : Process(process) {}

    // Initialize the surface
    bool initialize(QStringList &parms, QWidget *parent);

    // Run a step of the growth
    bool step(const QStringList &parms);

		// Rewind the surface
		bool rewind(QStringList &parms, QWidget *parent);

    // Process long description
    QString description() const { return "Growing polar surface"; }

    // Parameters
		enum ParmNames { pDt, pDrawSteps, pCellInitWalls, pCellInitSize, pCellKill, 
                     pTissueParmsProc, pSurfaceParmsProc, pNumParms }; 

    QStringList parmNames() const 
    {
      QVector <QString> vec(pNumParms);

      vec[pDt] = "Dt";
      vec[pDrawSteps] = "DrawSteps";
      vec[pCellInitWalls] = "CellInitWalls";
      vec[pCellInitSize] = "CellInitSize";
      vec[pCellKill] = "CellKill";
      vec[pTissueParmsProc] = "Tissue Parms Process";
      vec[pSurfaceParmsProc] = "Surface Parms Process";

			return vec.toList();
    }

    QStringList parmDescs() const 
    {
      QVector <QString> vec(pNumParms);

      vec[pDt] = "Growth timestep";
      vec[pDrawSteps] = "Steps between drawn frames";
      vec[pCellInitWalls] = "Initial cell walls";
      vec[pCellInitSize] = "Size of initial cell";
      vec[pCellKill] = "Distance from the tip to kill cell";
      vec[pTissueParmsProc] = "Process to hold tissue parameters";
      vec[pSurfaceParmsProc] = "Process to hold surface parameters";
			
			return vec.toList();
    }

    QStringList parmDefaults() const 
    {
      QVector <QString> vec(pNumParms);

      vec[pDt] = "0.1";
      vec[pDrawSteps] = "3";
      vec[pCellInitWalls] = "6";
      vec[pCellInitSize] = "10";
      vec[pCellKill] = "80"; 
      vec[pTissueParmsProc] = "TissueParms";
      vec[pSurfaceParmsProc] = "SurfaceParms";
      
			return vec.toList();
    }

    ParmChoiceMap parmChoice() const 
    {
      ParmChoiceMap map;
      return map;
    }

    // Plug-in icon
    QIcon icon() const { return QIcon(":/images/CellApex.png"); }

		// Apex surface
    PolarSurface polarSurface;    

  private:
    // Read parameters
		bool processParms(const QStringList &parms);
        
		// Model parameters from GUI
    double dt;                 // Timestep
    int drawSteps;             // Steps per GUI update
    double cellKill;           // Arclength to kill cells at
    int cellInitWalls;         // Initial cell number of walls
    double cellInitSize;       // Initial cell size

		// Mesh object
    Mesh *mesh;         // Current mesh
    CellTissue *T;      // Cellular tissue

		// Polar vertex atttributes
    PolarSurface::VertexAttr *vertexAttr; 
		
    // Define all global data you want to save in the mesh in the attributes 
    double &time() 
    { 
      return mesh->attributes().attrMap<QString, double>("PolarSurface Time")["Time"]; 
    }
  };
}  
#endif

