// Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/gmsh/gmsh/issues.

#ifndef _CONVEX_COMBINATION_TERM_H_
#define _CONVEX_COMBINATION_TERM_H_

#include <assert.h>
#include "femTerm.h"
#include "simpleFunction.h"
#include "GmshGlobal.h"
#include "GModel.h"
#include "SElement.h"
#include "fullMatrix.h"
#include "Numeric.h"

class convexCombinationTerm : public femTerm<double> {
protected:
  const simpleFunction<double> *_k;
  const int _iField;

public:
  convexCombinationTerm(GModel *gm, int iField, simpleFunction<double> *k)
    : femTerm<double>(gm), _k(k), _iField(iField)
  {
  }
  virtual int sizeOfR(SElement *se) const
  {
    return se->getMeshElement()->getNumShapeFunctions();
  }
  virtual int sizeOfC(SElement *se) const
  {
    return se->getMeshElement()->getNumShapeFunctions();
  }
  Dof getLocalDofR(SElement *se, int iRow) const
  {
    return Dof(se->getMeshElement()->getShapeFunctionNode(iRow)->getNum(),
               Dof::createTypeWithTwoInts(0, _iField));
  }
  virtual void elementMatrix(SElement *se, fullMatrix<double> &m) const
  {
    MElement *e = se->getMeshElement();
    m.setAll(0.);
    const int nbSF = e->getNumShapeFunctions();
    for(int j = 0; j < nbSF; j++) {
      MVertex *vj = e->getShapeFunctionNode(j);
      double diag = 0.0;
      for(int k = 0; k < nbSF; k++) {
        MVertex *vk = e->getShapeFunctionNode(k);
        MVertex *vl = NULL;
        SVector3 a, b;
        double tan = 0.0;
        if(k != j && 3 - j - k >= 0 && 3 - j - k <= 2) {
          vl = e->getShapeFunctionNode(3 - j - k);
          a = SVector3(vk->x() - vj->x(), vk->y() - vj->y(), vk->z() - vj->z());
          b = SVector3(vl->x() - vj->x(), vl->y() - vj->y(), vl->z() - vj->z());
          double angle = myacos(dot(a, b) / (norm(a) * norm(b)));
          tan = sin(angle * 0.5) / cos(angle * 0.5);
        }
        double length = vj->distance(vk);
        m(j, k) = -tan / length; // mean value convex map
        // m(j, k) = -1; //convex map of Tutte
      }
      // m(j,j) = (nbSF - 1);// convex map of Tutte
      for(int k = 0; k < nbSF; k++) {
        if(k != j) diag += (-m(j, k));
      }
      m(j, j) = diag;
    }
  }
};

#endif
