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


#ifndef _GENCACHE_H_
#define _GENCACHE_H_

#include "genTerm.h"
#include <vector>

template<class T,int n> class genCache : public genTerm<T,n>
{
public:
  typedef typename TensorialTraits<T>::ValType ValType;
  typedef typename ContainerTraits<ValType,n>::Container ContainerValType;
  static const int Nsp=n;
private :
  typename genTerm<T,n>::ConstHandle gt;
  mutable MElement* cacheele;
  mutable std::vector<ContainerValType> cache;

public:
  genCache(const typename genTerm<T,n>::ConstHandle &other) : gt(other) {cacheele=NULL;}
  void reset(void) {cacheele=NULL;cache.clear();}
  virtual int getNumKeys(MElement* ele,int k=0) const {return gt->getNumKeys(ele,k);};
  virtual void getKeys(MElement* ele, std::vector<Dof> &keys, int k=0) const {gt->getKeys(ele,keys,k);};
  virtual int getIncidentSpaceTag(int k=0) const { return gt->getIncidentSpaceTag(k);}
  virtual void get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const
  {
    if (ele==cacheele)
    {
      vvals=cache;
    }
    else
    {
      cacheele=ele;
      gt->get(ele,npts,GP,vvals);
      cache=vvals;
    }
  }
  virtual void get(MElement* ele, int npts, IntPt* GP, ContainerValType &vals) const {genTerm<T,n>::get(ele,npts,GP,vals);}
  virtual genCache<T,n>* clone () const {return new genCache<T,n>(gt);};
};

template<class T,int n> class diffCache : public diffTerm<T,n>
{
public:
  typedef typename TensorialTraits<T>::ValType ValType;
  typedef typename TensorialTraits<T>::GradType GradType;
  typedef typename TensorialTraits<T>::HessType HessType;
  typedef typename ContainerTraits<ValType,n>::Container ContainerValType;
  typedef typename ContainerTraits<GradType,n>::Container ContainerGradType;
  typedef typename ContainerTraits<HessType,n>::Container ContainerHessType;
  static const int Nsp=n;
private :
  typename diffTerm<T,n>::ConstHandle dt;
  mutable MElement* cacheele;
  mutable MElement* cacheelegrad;
  mutable MElement* cacheelehess;
  mutable std::vector<ContainerValType> cache;
  mutable std::vector<ContainerGradType> cachegrad;
  mutable std::vector<ContainerHessType> cachehess;

public:
  diffCache(const typename diffTerm<T,n>::ConstHandle &other) : dt(other) {cacheele=NULL;cacheelegrad=NULL;cacheelehess=NULL;}
  void reset(void) {cacheele=NULL;cacheelegrad=NULL;cacheelehess=NULL;cache.clear();cachegrad.clear();cachehess.clear();}
  virtual int getNumKeys(MElement* ele,int k=0) const {return dt->getNumKeys(ele,k);};
  virtual void getKeys(MElement* ele, std::vector<Dof> &keys, int k=0) const {dt->getKeys(ele,keys,k);};
  virtual int getIncidentSpaceTag(int k=0) const { return dt->getIncidentSpaceTag(k);}
  virtual void get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const
  {
    if (ele==cacheele)
    {
      vvals=cache;
    }
    else
    {
      cacheele=ele;
      dt->get(ele,npts,GP,vvals);
      cache=vvals;
    }
  }
  virtual void getgradf(MElement* ele, int npts, IntPt* GP, std::vector< ContainerGradType > &vgrads) const
  {
    if (ele==cacheelegrad)
    {
      vgrads=cachegrad;
    }
    else
    {
      cacheelegrad=ele;
      dt->getgradf(ele,npts,GP,vgrads);
      cachegrad=vgrads;
    }
  }
  virtual void gethessf(MElement* ele, int npts, IntPt* GP, std::vector< ContainerHessType > &vhesss) const
  {
    if (ele==cacheelehess)
    {
      vhesss=cachehess;
    }
    else
    {
      cacheelehess=ele;
      dt->gethessf(ele,npts,GP,vhesss);
      cachehess=vhesss;
    }
  }
  virtual void get(MElement* ele, int npts, IntPt* GP, ContainerValType &vals) const {diffTerm<T,n>::get(ele,npts,GP,vals);}
  virtual void getgradf(MElement* ele, int npts, IntPt* GP, ContainerGradType &grads) const {diffTerm<T,n>::getgradf(ele,npts,GP,grads);}
  virtual void gethessf(MElement* ele, int npts, IntPt* GP, ContainerHessType &hesss) const {diffTerm<T,n>::gethessf(ele,npts,GP,hesss);}
  virtual diffCache<T,n>* clone () const {return new diffCache<T,n>(dt);};
};

#endif // _GENCACHE_H_