// GenFem - A high-level finite element library
// Copyright (C) 2010-2026 Eric Bechet
//
// See the LICENSE file for license information and contributions.
// Please report all bugs and problems to <bechet@cadxfem.org>.
//
// Initial design: Eric Bechet (rev.1460)

#ifndef _GEN_FUNCTION_H_
#define _GEN_FUNCTION_H_

#include "genTraits.h"
#include "genTerm.h"

template<class T> class genFunction : public diffTerm<T,0>
{
public:
  typedef typename TensorialTraits<T>::ValType ValType;
  typedef typename TensorialTraits<T>::GradType GradType;
  typedef typename TensorialTraits<T>::HessType HessType;
  typedef typename ContainerTraits<ValType,0>::Container ContainerValType;
  typedef typename ContainerTraits<GradType,0>::Container ContainerGradType;
  typedef typename ContainerTraits<HessType,0>::Container ContainerHessType;
  static const int Nsp=0;
protected:
  const genSimpleFunction<ValType> &value;

public:
  genFunction(const genSimpleFunction<ValType> &value_) : value(value_) {}
  virtual int getNumKeys(MElement* ele,int k=0) const  {return 0;};
  virtual void getKeys(MElement* ele, std::vector<Dof> &keys, int k=0) const {};
  virtual int getIncidentSpaceTag(int k=0) const { return 0;}
  virtual void get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const;
  virtual void get(MElement* ele, int npts, IntPt* GP, ContainerValType &vals) const
  {
    genTerm<T,0>::get(ele,npts,GP,vals);
  }
  virtual void getgradf(MElement* ele, int npts, IntPt* GP, std::vector< ContainerGradType > &vgrads) const ;
  virtual void getgradf(MElement* ele, int npts, IntPt* GP, ContainerGradType &grads) const
  {
    diffTerm<T,0>::getgradf(ele,npts,GP,grads);
  }
  virtual void getgradfuvw(MElement* ele, int npts, IntPt* GP, std::vector< ContainerGradType > &vgrads) const {};
  virtual void gethessf(MElement* ele, int npts, IntPt* GP, std::vector< ContainerHessType > &vhesss) const ;
  virtual void gethessf(MElement* ele, int npts, IntPt* GP, ContainerHessType &hesss) const
  {
    diffTerm<T,0>::gethessf(ele,npts,GP,hesss);
  }
  virtual genFunction<T>* clone () const { return new genFunction<T>(value);}
};


template<class T> void genFunction<T>::get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const
{
  MElement* elep = ele->getParent();
  if(!elep) elep = ele;

  for (int i=0; i<npts;++i)
  {
    const double u = GP[i].pt[0]; const double v = GP[i].pt[1]; const double w = GP[i].pt[2];
    SPoint3 p;
    elep->pnt(u, v, w, p);
    typename TensorialTraits<T>::ValType val = value(p.x(), p.y(), p.z());
    vvals[i] = val;
  }
}

template<class T> void genFunction<T>::getgradf(MElement* ele, int npts, IntPt* GP, std::vector<ContainerGradType> &vvals) const
{
  MElement* elep = ele->getParent();
  if(!elep) elep = ele;

  for (int i=0; i<npts;++i)
  {
    const double u = GP[i].pt[0]; const double v = GP[i].pt[1]; const double w = GP[i].pt[2];
    SPoint3 p;
    elep->pnt(u, v, w, p);
    typename TensorialTraits<T>::GradType val = value.grad(p.x(), p.y(), p.z());
    vvals[i] = val;
  }
}

template<class T> void genFunction<T>::gethessf(MElement* ele, int npts, IntPt* GP, std::vector<ContainerHessType> &vvals) const
{
  MElement* elep = ele->getParent();
  if(!elep) elep = ele;

  for (int i=0; i<npts;++i)
  {
    const double u = GP[i].pt[0]; const double v = GP[i].pt[1]; const double w = GP[i].pt[2];
    SPoint3 p;
    elep->pnt(u, v, w, p);
    typename TensorialTraits<T>::HessType val = value.hess(p.x(), p.y(), p.z());
    vvals[i] = val;
  }
}
#endif //_GEN_FUNCTION_H_