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

#include "EnumElemType.hpp"
#include "BasisFunction.hpp"
#include "Tuple.hpp"
#include "Quadrature.hpp"
#include <stdexcept>

class ExplicitLagrangianFiniteElementBasis
{
public:
  typedef Quadrature::PointVector PointVector;

  ExplicitLagrangianFiniteElementBasis()  
    {
      ;
    }
  
  ~ExplicitLagrangianFiniteElementBasis() {}
  
public:
  template<unsigned int Dim> static void initBasisFunction(BasisFunction<Dim>& basisFunction, const PointVector& points)
  {
    const ElemType itemType = basisFunction.getItemType();
    const unsigned int b_order = basisFunction.getOrder();
    if (basisFunction.computeShape())
    {
      evaluateFunction(basisFunction, itemType, b_order, points);
    }
    if (basisFunction.computeShapeDeriv())
    {
      evaluateDerivative(basisFunction, itemType, b_order, points);
    }
  }
  
  static unsigned int dofsNumber(const unsigned int Dim, const unsigned int order, const ElemType itemType)
  {
    if (itemType == INVALID_ELEM)
    {
      std::cout<<"Error in ExplicitLagrangianFiniteElementBasis, dofs number required without specifing itemType"<<std::endl; 
      std::exit(1);
    }
    return nbShapeFunction(order, itemType);
  }

  static unsigned int nbShapeFunction(const unsigned int order, const ElemType itemType);
  
  static bool is_hierarchical();

private:
  //! Evaluate \$\varphi_i(x)\$
  static void evaluateFunction(BasisFunction<0>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector& points);
  static void evaluateFunction(BasisFunction<1>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector& points);
  static void evaluateFunction(BasisFunction<2>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector& points);
  static void evaluateFunction(BasisFunction<3>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector& points);

  //! Evaluate \$\partial_j \varphi_i(x)\$
  static void evaluateDerivative(BasisFunction<0>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector & points);
  static void evaluateDerivative(BasisFunction<1>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector & points);
  static void evaluateDerivative(BasisFunction<2>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector & points); 
  static void evaluateDerivative(BasisFunction<3>& basisFunction, const ElemType itemType, const unsigned int order, const PointVector & points); 

};

#endif 
