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

#ifndef DYNAMX_PROCESS_BEZIER_SURFACE_HPP
#define DYNAMX_PROCESS_BEZIER_SURFACE_HPP

#include <Process.hpp>
#include <BezierSurface.hpp>

namespace mgx
{
  // Class to hold bezier surface parameters
  class mgxBase_EXPORT BezierSurfaceParms : public Process 
  {
  public:
    BezierSurfaceParms(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 growth simulations using Bezier surfaces"; }

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

      vec[BezierSurface::pSurface] = "Surfaces";          
      vec[BezierSurface::pSurfScale] = "SurfScales";        
      vec[BezierSurface::pSurfTime] = "SurfTimes";         
      vec[BezierSurface::pSurfMaxDist] = "SurfMaxDist";          
      vec[BezierSurface::pRootSearchMaxSteps] = "RootSearchMaxSteps";     

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

      vec[BezierSurface::pSurface] = "Bezier surfaces to define leaf shape";          
      vec[BezierSurface::pSurfScale] = "Scale factors";        
      vec[BezierSurface::pSurfTime] = "Time factors";  
      vec[BezierSurface::pSurfMaxDist] = "Max distance from surface for closest point search";          
      vec[BezierSurface::pRootSearchMaxSteps] = "Max number of iterations for point inversion";     

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

      vec[BezierSurface::pSurface] = "leaf1.bez leaf2.bez";          
      vec[BezierSurface::pSurfScale] = "1 10";        
      vec[BezierSurface::pSurfTime] = "1 10";  
      vec[BezierSurface::pSurfMaxDist] = "0.2";          
      vec[BezierSurface::pRootSearchMaxSteps] = "500";  

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

  class mgxBase_EXPORT BezierSurfaceGrowth : public Process 
  {
  public:
    BezierSurfaceGrowth(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 Bezier surface"; }

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

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

      vec[pDt] = "Dt";
      vec[pDrawSteps] = "DrawSteps";
      vec[pCellInitWalls] = "CellInitWalls";
      vec[pCellInitSize] = "CellInitSize";
      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[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] = "100";
      vec[pCellInitSize] = "1.0";
      vec[pTissueParmsProc] = "TissueParms";
      vec[pSurfaceParmsProc] = "SurfaceParms";
      
      return vec.toList();
    }

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

    // Bezier surface
    BezierSurface bezierSurface;    

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

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

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

}  
#endif

