/*=========================================================================

  Program:   Advanced Normalization Tools

  Copyright (c) ConsortiumOfANTS. All rights reserved.
  See accompanying COPYING.txt or
 https://github.com/stnava/ANTs/blob/master/ANTSCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef _SurfaceMeshCurvature_h
#define _SurfaceMeshCurvature_h

#include "itkSurfaceCurvatureBase.h"

namespace itk
{
/** \class SurfaceMeshCurvature
 *
 * This class takes a surface as input and creates a local
 * geometric frame for each surface point.
 *
 *
 */
template <typename TSurface, typename TSurfacePatch>
class SurfaceMeshCurvature : public SurfaceCurvatureBase<TSurface, 3>
{
public:
  /** Standard class typedefs. */
  typedef SurfaceMeshCurvature           Self;
  typedef SurfaceCurvatureBase<TSurface> Superclass;
  typedef SmartPointer<Self>             Pointer;
  typedef SmartPointer<const Self>       ConstPointer;

  /** Run-time type information (and related methods). */
  itkTypeMacro(SurfaceMeshCurvature, SurfaceCurvatureBase);

  /** Method for creation through the object factory. */
  itkNewMacro(Self);

  typedef typename Superclass::RealType   RealType;
  typedef typename Superclass::PointType  VectorType;
  typedef typename Superclass::PointType  FixedVectorType;
  typedef typename Superclass::PointType  PointType;
  typedef typename Superclass::MatrixType MatrixType;

  typedef TSurfacePatch                            SurfacePatch;
  typedef typename TSurfacePatch::Pointer          SurfacePatchPointer;
  typedef typename TSurfacePatch::NodeLocationType VertexType;
  typedef typename TSurfacePatch::PixelType        FunctionValueType;
  typedef TSurface *                               SurfacePointer; // probably vtkmesh

  /** Find all points within some distance of the origin.
   * The argument gives the number of times to apply the
   * mean shift algorithm to find the best neighborhood.
   */
  virtual void
  FindNeighborhood(unsigned int numMeanShifts = 0)
  {
    this->m_PointList.clear();
    this->m_FunctionValueList.clear();
    VertexType origin = m_SurfacePatch->GetLocation();
    PointType  pt;
    for (int j = 0; j < 3; j++)
    {
      pt(j) = origin[j];
    }
    this->m_Origin = pt;
    this->m_PointList.insert(this->m_PointList.begin(), pt);
    this->m_FunctionValueList.insert(this->m_FunctionValueList.begin(), m_SurfacePatch->GetValue());
    for (unsigned int i = 0; i < m_SurfacePatch->m_Neighbors.size(); i++)
    {
      VertexType neigh = m_SurfacePatch->m_Neighbors[i]->GetLocation();
      PointType  pti;
      for (int j = 0; j < 3; j++)
      {
        pti(j) = neigh[j];
      }
      this->m_PointList.insert(this->m_PointList.begin(), pti);
      this->m_FunctionValueList.insert(this->m_FunctionValueList.begin(),
                                       this->m_SurfacePatch->m_Neighbors[i]->GetValue(0));
    }
  }

  void
  SetSurface(SurfacePointer s)
  {
    m_Surface = s;
  }

  void
  SetSurfacePatch(SurfacePatchPointer s)
  {
    m_SurfacePatch = s;
  }

  SurfaceMeshCurvature()
  {
    this->m_Origin.fill(0.0);
    this->m_ArbitraryTangent.fill(0.);
    this->m_Normal.fill(0.);
    this->m_Tangent1.fill(0.);
    this->m_Tangent2.fill(0.);
    this->m_DirectionalKappa = 0.0;
    this->m_Kappa1 = 0.0;
    this->m_Kappa2 = 0.0;
    this->m_GaussianKappa = 0.0;
    this->m_A = 0.0;
    this->m_B = 0.0;
    this->m_C = 0.0;
    this->m_W1 = 3. / 8.;
    this->m_W2 = 1. / 8.;
    this->m_Eval0 = 0.0;
    this->m_Eval1 = 0.0;
    this->m_Eval2 = 0.0;
    this->m_CurrentNeighborhoodPointIndex = 0;
    this->m_ParameterFileName = "";
    this->m_Pi = 3.14159265358979323846;
    this->m_Debug = true;
    this->m_Debug = false;
    this->m_UseGeodesicNeighborhood = false;
    this->m_TotalArea = 0.0;
  }

  ~SurfaceMeshCurvature(){};

protected:
private:
  SurfacePointer      m_Surface;
  SurfacePatchPointer m_SurfacePatch;
};
} // namespace itk

#ifndef ITK_MANUAL_INSTANTIATION
// #include "itkSurfaceMeshCurvature.hxx"
#endif

#endif
