// SpaFEDTe, a Template based C++ library for creating 
// Discontinuous Finite Element Spaces,
// Copyright (C) 2012 Lorenzo Alessio Botti

/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */ 
/* License as published by the Free Software Foundation either */ 
/* version 3.0 of the License, or (at your option) any later version. */

/* This software is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this software; if not, a copy of the full */
/* GNU Lesser General Public License can be found at */
/* http://www.gnu.org/licenses/. */

#ifndef __MappingBasisFunction_h__
#define __MappingBasisFunction_h__

#include "BasisFunction.hpp"
#include "Tuple.hpp"
#include "EnumElemType.hpp"
#include "Quadrature.hpp"
#include "Eigen/Dense"

template<unsigned int Dim, unsigned int DIm>
class MappingBasisFunction : public BasisFunction<Dim>
{
public:
  typedef typename BasisFunction<Dim>::ShapeDerivMatrix ShapeDerivMatrix;
  typedef typename BasisFunction<Dim>::ShapeMatrix ShapeMatrix;
  typedef Eigen::Matrix<Eigen::Matrix<double,DIm,Dim>,Eigen::Dynamic,1> MappingMatrix; 
  typedef Eigen::Matrix<Eigen::Matrix<double,Dim,DIm>,Eigen::Dynamic,1> MappingMatrixInv; 
  typedef Eigen::VectorXd JacVector; 
  typedef Quadrature::PointVector PointVector; 
  typedef Eigen::Matrix<double,DIm,1> CoordVector;   
  typedef Eigen::Matrix<double,Dim,1> DistanceVector;   
  typedef Eigen::Matrix<double,Dim,Dim> RotationMatrix; 
  typedef Eigen::Matrix<CoordVector,Eigen::Dynamic,1> NormalVector;
//  typedef Eigen::Matrix<Eigen::Matrix<double,Eigen::Dynamic,1>,DIm,1> CoeffVector;

  MappingBasisFunction():
    BasisFunction<Dim>()
    {
      ;
    } 
  
  MappingBasisFunction(unsigned int order, ElemType itemType):
    BasisFunction<Dim>(order, itemType)
    {
      ;
    } 
    
  ~MappingBasisFunction() { }
  
  const JacVector& getJacobian() const { return m_jac; }

  JacVector& getJacobian() { return m_jac; }
  
  const JacVector& getJacobianXweight() const { return m_jacXweight; }

  JacVector& getJacobianXweight() { return m_jacXweight; }

  const MappingMatrixInv& getdEdX() const { return m_dEdX; }

  MappingMatrixInv& getdEdX() { return m_dEdX; }

  const MappingMatrix& getdXdE() const { return m_dXdE; }

  MappingMatrix& getdXdE() { return m_dXdE; }

  const PointVector& getQpointX() const { return m_QpointX; }

  PointVector& getQpointX() { return m_QpointX; }
  
  const NormalVector& getNormalVec() const { return m_normalVec; }

  NormalVector& getNormalVec() { return m_normalVec; }
  
//  const CoeffVector& getMapCoeff() const { return m_mapCoeff; }
//  
//  CoeffVector& getMapCoeff() { return m_mapCoeff; }
  
  void resizeMapping(const unsigned int qp)
  {
    this->resize(qp);
  
    this->m_QpointX.resize(qp,Eigen::NoChange);
    this->m_QpointX.setZero();
   
    if (Dim != DIm)
      this->m_normalVec.resize(qp);

    this->m_jacXweight.resize(qp);
  }
  
  void resizeQpointsX(const unsigned int qp)
  {
    this->m_QpointX.resize(qp, Eigen::NoChange);
    this->m_QpointX.setZero();
  }
  
public:  
  static const unsigned int RefSpaceDim = Dim;

  static const unsigned int PhySpaceDIm = DIm;

  
protected:

  void resize(const unsigned int qpSize)
  {
    m_dXdE.resize(qpSize);
    for(unsigned int i = 0; i<qpSize; i++)
    {
      m_dXdE(i).setZero();
    }
    m_jac.resize(qpSize);
    m_jac.setZero();
    if (Dim == DIm)
    {
      m_dEdX.resize(qpSize);
    }
  }

  MappingMatrixInv m_dEdX;
  
  MappingMatrix m_dXdE;

  JacVector m_jac;

  JacVector m_jacXweight;
  
  PointVector m_QpointX;
  
  NormalVector m_normalVec;

  //CoeffVector m_mapCoeff;
};

#endif
