// 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: Frederic Duboeuf (rev.654)


#include <fstream>
#include <cstdio>
#include <cassert>
#include "savedGenTerm.h"


template<class T,int n> void SavedGenTerm<T,n>::get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const
{
  typename std::map< int, std::vector<ContainerValType> >::const_iterator it;
  it = mapvvals->find(ele->getNum());
  assert(it != mapvvals->end());
  vvals = it->second;
}

template<class T,int n> void SavedGenTerm<T,n>::set(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals)
{ // Par convention le nombre et l'ordre des points de gauss doivent etre conserves
  (*mapvvals)[ele->getNum()] = vvals;
}

template<class T,int n> void SavedGenTerm<T,n>::print(const char* name)
{
  typename std::map< int, std::vector<ContainerValType> >::iterator it;
  for ( it=mapvvals->begin(); it!=mapvvals->end(); ++it)
  {
    int eleNum = it->first;
    std::vector<ContainerValType> vvals = it->second;
    printf("\n");
    printf("Print %s :\n", name);
    printf(" Element : %d\n", eleNum);
    int nbpts = vvals.size();
    printf(" GPoint : %d\n", nbpts);
    for ( int i=0; i<nbpts; ++i)
    {
      char temp[16];
      sprintf(temp,"%d", i);
      Print(vvals[i],temp);
    }
  }
}

template<class T,int n> bool SavedGenTerm<T,n>::printfile(const std::string &fileName, const std::ios_base::openmode mode, const int precision)
{
  std::ofstream f;
  f.open(fileName.c_str(), std::ios::out | mode);
  if (f.bad())
    return 0;

  f << std::setiosflags( std::ios::scientific ) ;
  f << std::setprecision(precision);

  int endOfName = fileName.find('.');
  std::string name = fileName.substr(0,endOfName);
  
  f << "Description : \n";
  f << "\n";
  f << " Class : SavedGenTerm \n";
  f << " Name : " << name.c_str() << "\n";
  f << " NbElt : " << size() << "\n";
  f << " ValType : " << TensorialProperties<T>::Name() << "\n";
  f << " ContainerDim : " << n << "\n";
  f << "\n";
  f << "\n";
  f << "Values : \n";
  f << "\n";
  typename std::map< int, std::vector<ContainerValType> > ::const_iterator it;
  for ( it=mapvvals->begin(); it!=mapvvals->end(); ++it )
  {
    int elt = it->first;
    const std::vector<ContainerValType>* vvals = & (it->second);

    f << " Element : " << elt << ", NbPoint : " << (int)vvals->size() << "\n";
    f << "\n";

    int i=0;
    typename std::vector<ContainerValType>::const_iterator itvals;
    for ( itvals=vvals->begin(); itvals!=vvals->end(); ++itvals )
    {
      f << "  Point : " << i << ", ";
      writeContainer(*itvals,f);
      f << "\n";
      ++i;
    }
    f << "\n";
  }
  f.close();
  return true;
}



template<class T> void ConstantField<T>::get(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals) const
{
  for (int i=0; i<npts;++i)
  vvals[i] = value;
}

template<class T> void ConstantField<T>::set(MElement* ele, int npts, IntPt* GP, std::vector<ContainerValType> &vvals)
{
  value = vvals[0];
}

template<class T> void ConstantField<T>::print(const char* name)
{
  printf("Print %s :\n", name);
  printf(" Constant :\n");
  PrintOp(value);
}

template<class T> bool ConstantField<T>::printfile(const std::string &fileName, const std::ios_base::openmode mode, const int precision)
{
  std::ofstream f;
  f.open(fileName.c_str(), std::ios::out | mode);
  if (f.bad())
    return 0;

  f << std::setiosflags( std::ios::scientific ) ;
  f << std::setiosflags( std::ios::showpos ) ;
  f << std::setprecision(precision);

  int endOfName = fileName.find('.');
  std::string name = fileName.substr(0,endOfName);

  f << "Description : \n";
  f << "\n";
  f << " Class : ConstantField \n";
  f << " Name : " << name.c_str() << "\n";
  f << " ValType : " << TensorialProperties<T>::Name() << "\n";
  f << " ContainerDim : " << 0 << "\n";
  f << "\n";
  f << "\n";
  f << "Values : \n";
  f << "\n";

  int tensLength = TensorialProperties<T>::Length();
  for(int l = 0; l < tensLength; ++l)
  {
    f << " ";
    writeTensor(value,f,l);
    f << "\n";
  }
  f << "\n";

  f.close();
  return true;
}


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

  double u, v, w;
  int nbSFfct = elep->getNumShapeFunctions();
  IntPt pts[nbSFfct];
  for (int j=0; j<nbSFfct; ++j)
  {
    elep->getNode(j, u, v, w);
    pts[j].pt[0]=u;
    pts[j].pt[1]=v;
    pts[j].pt[2]=w;
    pts[j].weight=1.0;
  }
  std::vector<ContainerValType> vvalsf(nbSFfct);
  SavedGenTerm<T,0>::get(elep,nbSFfct,pts,vvalsf);
  assert(vvalsf.size()==nbSFfct);

  double jac[3][3];
  for (int i=0; i<npts; ++i)
  {
    double val[nbSFfct];
    u = GP[i].pt[0]; v = GP[i].pt[1]; w = GP[i].pt[2];
    elep->getShapeFunctions(u, v, w, val);
    for (int j=0; j<nbSFfct; ++j)
      vvals[i]() += vvalsf[j]() * val[j];
  }
}

