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

#include <Surface.hpp>
#include <Attributes.hpp>
#include <Function.hpp>

namespace mgx
{
  // for the polar surfaces: 
  const int SAMPLES = 10000;  // Sample count for function/contours in PolarSurface

  /*
   * \class PolarSurface Surface.hpp <Surface.hpp>
   *
   * Growing surface using cylindrical coordinates on a contour
   *
   * \ingroup GrowingSurfaceProcesses
   */
  class mgxBase_EXPORT PolarSurface : public Surface
  {
    public:
      // Parameter names
      enum ParmNames { pGrowthType, pSurfaceContour, pArcLengthGrowth, pSurfaceScale, 
        pGrowthScaleInMult, pGrowthScaleOutMult, pGrowthScaleFunc, pRootSearchMaxSteps, pNumParms };

      // Polar vertex attribute data needed for simulations
      struct VertexData
      {
        double arcLength;
        double angle;  
        // Constructor, set initial values
        VertexData() : arcLength(0), angle(0) {}

        bool operator==(const VertexData &other) const
        {
          if(arcLength == other.arcLength and angle == other.angle)
            return true;
          return false;
        }
      };
      
      // Define attribute map
      typedef AttrMap<vertex, VertexData> VertexAttr;
      
      // Class to define methods for subdivision
       class mgxBase_EXPORT Subdivide : virtual public mgx::Subdivide
       {
         public:
          Subdivide(VertexAttr *vAttr, PolarSurface *surf) 
             : vertexAttr(vAttr), surface(surf) {}

         protected:
           virtual bool updateEdgeData(vertex l, vertex v, vertex r, double s);
  
         private:
          VertexAttr *vertexAttr;
          PolarSurface *surface;      
      };

      // ALR: Constructor should fill in default values, like in FemMGXM
      PolarSurface() {} 
      // ALR: is it important to have a destructor? FemMGXM doesn't have one
      ~PolarSurface() {} 
  
      bool processParms(const QStringList &parms);
      bool setPoint(vertex p, vertex sp, Point3d cp);
      bool updatePos(vertex p);
      bool updateNormal(vertex p);
      bool initialCell(CellTissue &T, double radius, int sides); 
      bool initialize(VertexAttr *vData, const QStringList &parms);
      bool growPoint(vertex p, double dt, double time);

    private:
      // vertex attributes required for simulation 
      VertexAttr *vertexAttr;

      bool loadFunction(const QString &funcFile, double *v);
      bool integrateFunction(const QString &funcFile, double *v);
      bool arcLengthParam(const QString &contFile, Point3d *v);
      Point3d polarToCart(double arcLength, double angle);

    
      double dArc;                  // arclength diff between points in posV
      Point3d dPos;                 // amount to add for next point extrapolate
      Point3d arcLV[SAMPLES + 1];   // Pos vec, param by arclength
      double growthVA[SAMPLES + 1]; // Growth vector, param by arclength

      // Parameters
      int growthType;
      double surfaceScale;          // Contour scaling constant
      Function *growthScaleFunc;
      QString growthScaleFile;      // Growth scaling function 
      double growthScaleOutMult;
      double growthScaleInMult;
      QString arcLengthGrowthFile;  // Arc length growth function file name
      QString surfaceContourFile;    // Surface Contour file name
      int rootSearchMaxSteps;        // Max steps for closest point on surface
  };


  // Read/write Vertex data
  bool inline readAttr(PolarSurface::VertexData &m, const QByteArray &ba, size_t &pos) 
  {
    return readChar((char *)&m, sizeof(PolarSurface::VertexData), ba, pos);
  }
  bool inline writeAttr(const PolarSurface::VertexData &m, QByteArray &ba) 
  {
    return writeChar((char *)&m, sizeof(PolarSurface::VertexData), ba);
  }

 }  
#endif

