// 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 __finite_element_mapping_h__
#define __finite_element_mapping_h__

#include "MappingBasisFunction.hpp"
#include "Quadrature.hpp"
#include "EnumElemType.hpp"
#include <stdexcept>
#include <cassert>
#include "Mesh.hpp"

template <class MappingFunctionT>
class FiniteElementMapping
{
public:
  typedef MappingFunctionT MappingFunctionType;
  typedef SpaMesh::Connectivity::TopoPointVector TopoPointVector;
  typedef SpaMesh::Connectivity::TopoIndexVector TopoIndexVector;

  /** Constructeur de la classe */
  FiniteElementMapping() 
    {
      ;
    }
  
  /** Destructeur de la classe */
  ~FiniteElementMapping() { }
  
public:
  template<unsigned int Dim, unsigned int DIm,
	   template <unsigned int, unsigned int> class MappingBasisFunctionType>
    static void init(MappingBasisFunctionType<Dim,DIm>& mappingFunction, 
	             const Quadrature& quadrature, 
                     const ElemType& elemType, 
		     const TopoPointVector& coord, 
		     const unsigned int morder)
  {
    assert(elemType == quadrature.getItemType());
    MappingFunctionType::initMappingFunction(mappingFunction, quadrature, elemType, coord, morder);  
  }
  
  template<unsigned int Dim, unsigned int DIm,
	   template <unsigned int, unsigned int> class MappingBasisFunctionType>
    static void computePhysicalSpacePoints(MappingBasisFunctionType<Dim,DIm>& mappingFunction, 
	                                   const Quadrature::PointVector& refSpacePoints, 
	                                   const ElemType& elemType, 
					   const TopoPointVector& coord, 
					   const int morder)
  {
    MappingFunctionType::computePhysicalSpacePointsX(mappingFunction, refSpacePoints, elemType, coord, morder);
  }
  
  template<unsigned int Dim, unsigned int DIm,
	   template <unsigned int, unsigned int> class MappingBasisFunctionType,
	   template <typename> class WrapMappingFunctionType>
    static void computePhysicalSpacePoints(WrapMappingFunctionType<MappingBasisFunctionType<Dim,DIm> >& mappingFunction, 
	                                   const Quadrature::PointVector& refSpacePoints, 
	                                   const ElemType& elemType, 
					   const TopoPointVector& coord, 
					   const int morder)
  {
    MappingFunctionType::computePhysicalSpacePointsX(mappingFunction.getMappingFunction(), refSpacePoints, elemType, coord, morder);
  }
  
  template<unsigned int Dim, unsigned int DIm,
	   template <unsigned int, unsigned int> class MappingBasisFunctionType>
    static void computePhysicalSpacePointsWithMap(MappingBasisFunctionType<Dim,DIm>& mappingFunction, 
	                                         const Quadrature::PointVector& refSpacePoints, 
	                                         const ElemType& elemType, 
					         const TopoPointVector& coord, 
					         const int morder)
  {
    MappingFunctionType::computePhysicalSpacePointsWithMapX(mappingFunction, refSpacePoints, elemType, coord, morder);
  }

  template<unsigned int DIm, 
           template <unsigned int, unsigned int> class MappingBasisFunctionType>
    static void reInitSide(MappingBasisFunctionType<DIm,DIm>& mappingFunction, 
	                   const typename Quadrature::PointVector& qVec, 
	                   const ElemType& elemType, 
			   const TopoPointVector& coord, 
			   const unsigned int morder)
  {
    MappingFunctionType::reInitMappingFunctionElemSide(mappingFunction, qVec, elemType, coord, morder);  
  }
  
  template<unsigned int DIm,
	   template <unsigned int, unsigned int> class MappingBasisFunctionType>
    static void referenceSpaceSideMap(const ElemType& elemType, const ElemType& sideType, 
	                              const TopoIndexVector& side_indices, 
	                              MappingBasisFunctionType<DIm-1,DIm>& mappingFunction, 
                                      typename Quadrature::PointVector& elemQuadrature)
                                                      
  {
    MappingFunctionType::referenceSpaceSideMap(elemType, sideType, side_indices, mappingFunction, elemQuadrature);
  }
};

#endif
