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

#include <Surface.hpp>
#include <Bezier.hpp>

namespace mgx
{
  /*
   * \class BezierSurface Surface.hpp <Surface.hpp>
   *
   * Growing surface using Bezier key-frames
   *
   * \ingroup GrowingSurfaceProcesses
   */
  class mgxBase_EXPORT BezierSurface : public Surface
  {
    public:    
      // Parameter names
      enum ParmNames { pSurface, pSurfScale, pSurfTime, pSurfMaxDist, pRootSearchMaxSteps, pNumParms };  

      BezierSurface() {}
      ~BezierSurface() {}
      
      // Bezier vertex attribute data needed for simulations
      struct VertexData
      {
        double u;
        double v;  
        // Constructor, set initial values
        VertexData() : u(0), v(0) {}

        bool operator==(const VertexData &other) const
        {
          if(u == other.u and v == other.v)
            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, BezierSurface *surf) 
            : vertexAttr(vAttr), surface(surf) {}

        virtual bool updateEdgeData(vertex l, vertex v, vertex r, double s);

        VertexAttr *vertexAttr;
        BezierSurface *surface;      
      };

      // Methods similar to other surfaces
      bool processParms(const QStringList &parms); 
      bool setPoint(vertex p, vertex sp, Point3d cp);
      bool updatePos(vertex p);
      bool updateNormal(vertex p);
      // Initial cell, square. 
      bool initialCell(CellTissue &T, double squareSize, int cellInitWall);

      // Methods proper to this kind of surface
      bool initialize(VertexAttr *vData, const QStringList &parms);
      bool growSurface(double time);

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

      std::vector<Bezier> surface;      // Bezier surfaces
      std::vector<double> surfScale;    // Surface scaling constants
      std::vector<double> surfTime;     // Surface time scales
      double surfMaxDist;               // Max dist for closest point search
      int rootSearchMaxSteps;           // Max steps for closest point on surface

      Bezier surfCurr;                  // Current surface
  };

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