// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_FACEUTILITY_IMP_HH
#define DUNE_FACEUTILITY_IMP_HH

namespace Dune
{


  template< ALU3dGridElementType type, class Comm >
  inline ALU3dGridFaceInfo< type, Comm >::
  ALU3dGridFaceInfo( const bool conformingRefinement, const bool ghostCellsEnabled ) :
    face_(0),
    innerElement_(0),
    outerElement_(0),
    innerFaceNumber_(-1),
    outerFaceNumber_(-1),
    innerTwist_(-665),
    outerTwist_(-665),
    segmentIndex_( -1 ),
    bndId_( -1 ),
    bndType_( noBoundary ),
    conformanceState_(UNDEFINED),
    conformingRefinement_( conformingRefinement ),
    ghostCellsEnabled_( ghostCellsEnabled )
  {}

  // points face from inner element away?
  template< ALU3dGridElementType type, class Comm >
  inline void
  ALU3dGridFaceInfo< type, Comm >::
  updateFaceInfo(const GEOFaceType& face,
                 int innerLevel,
                 int innerTwist)
  {
    face_ = &face;

    innerElement_ = 0;
    outerElement_ = 0;
    innerFaceNumber_ = -1;
    outerFaceNumber_ = -1;
    bndType_ = noBoundary;
    segmentIndex_ = -1;
    bndId_ = 0; // inner face

    // points face from inner element away?
    if (innerTwist < 0)
    {
      innerElement_    = face.nb.rear().first;
      innerFaceNumber_ = face.nb.rear().second;
      outerElement_    = face.nb.front().first;
      outerFaceNumber_ = face.nb.front().second;
    }
    else
    {
      innerElement_    = face.nb.front().first;
      innerFaceNumber_ = face.nb.front().second;
      outerElement_    = face.nb.rear().first;
      outerFaceNumber_ = face.nb.rear().second;
    } // end if

    // if not true we are accessing a fake bnd
    assert( innerElement_->isRealObject() );
    // if not true we are accessing a fake bnd
    assert( outerElement_->isRealObject() );

    // we only have to do this in parallel runs
    if( parallel() && innerElement_->isboundary() )
    {
      bndType_ = innerGhostBoundary;
      assert( ! dynamic_cast< const GEOPeriodicType* > ( innerElement_ ) );
    }

    if( parallel() && innerBoundary() )
    {
      // check for ghosts
      // this check is only need in the parallel case
      const BNDFaceType * bnd = static_cast<const BNDFaceType *> (innerElement_);

      if(bnd->bndtype() == ALU3DSPACE ProcessorBoundary_t)
      {
        // if nonconformity occurs then go up one level
        if( bnd->level () != bnd->ghostLevel() )
        {
          bnd = static_cast<const BNDFaceType *>(bnd->up());
          assert( bnd );
          innerElement_ = static_cast<const HasFaceType*> (bnd);
        }

        // get ghost and internal number
        GhostPairType p  = bnd->getGhost();

        // get face number
        innerFaceNumber_ = p.second;

        // this doesn't count as outer boundary
        const GEOElementType* ghost = static_cast<const GEOElementType*> (p.first);
        assert(ghost);

        innerTwist_ = ghost->twist(innerFaceNumber_);
      }
      else
      {
        innerTwist_ = innerFace().twist(innerALUFaceIndex());
      }
    }
    else
    {
      // set inner twist
      assert(innerTwist == innerEntity().twist(innerFaceNumber_));
      innerTwist_ = innerTwist;
    }

    if( outerElement_->isboundary() )
    {
      assert( ! innerBoundary() );
      // set to default boundary (with domain boundary)
      bndType_ = domainBoundary ;

      // check for ghosts
      // this check is only need in the parallel case
      // if this cast fails we have a periodic element
      //#ifdef ALUGRID_PERIODIC_BOUNDARY_PARALLEL
      ///      const bool periodicBnd = outerElement_->isperiodic();
      //      const BNDFaceType * bnd = 0;
      //      const BNDFaceType * bnd = static_cast<const BNDFaceType *> (outerElement_);
      //#else
      const BNDFaceType * bnd = dynamic_cast<const BNDFaceType *> (outerElement_);
      const bool periodicBnd = ( bnd == 0 ) ;
      //#endif
      if( periodicBnd ) // the periodic case
      {
        bndType_ = periodicBoundary ;
        assert( dynamic_cast< const GEOPeriodicType* > ( outerElement_ ) );
        const GEOPeriodicType* periodicClosure = static_cast< const GEOPeriodicType* > ( outerElement_ ) ;

#ifdef ALUGRID_PERIODIC_BOUNDARY
        // previously, the segmentIndex( 1 - outerFaceNumber_ ) was used, why?
        segmentIndex_ = periodicClosure->segmentIndex( outerFaceNumber_ );
#else
        // set to zero (grid test will fail)
        segmentIndex_ = 0 ;
#endif
#ifdef ALUGRID_PERIODIC_BOUNDARY_PARALLEL
        bndId_  = periodicClosure->bndtype( outerFaceNumber_ );
#endif

        const GEOFaceType* face = ImplTraits::getFace( *periodicClosure, 1 - outerFaceNumber_ );
        assert( (face->nb.front().first == periodicClosure) || (face->nb.rear().first == periodicClosure) );
        if( face->nb.rear().first == periodicClosure )
        {
          assert( dynamic_cast< const GEOPeriodicType * >( face->nb.rear().first ) );
          outerElement_    = face->nb.front().first ;
          outerFaceNumber_ = face->nb.front().second ;
        }
        else
        {
          assert( dynamic_cast< const GEOPeriodicType * >( face->nb.front().first ) );
          outerElement_    = face->nb.rear().first ;
          outerFaceNumber_ = face->nb.rear().second ;
        }

        assert( outerElement_->isRealObject() );
        if( outerElement_->isboundary() )
        {
          assert( dynamic_cast< const BNDFaceType * >( outerElement_ ) );
          bnd = static_cast< const BNDFaceType * >( outerElement_ );
        }
        else
          outerTwist_ = outerEntity().twist( outerFaceNumber_ );
      }

      if ( bnd ) // the boundary case
      {
        assert( bnd );

        // if this cast is valid we have either
        // a boundary or a ghost element
        // the ghost element case
        if( parallel() && bnd->bndtype() == ALU3DSPACE ProcessorBoundary_t)
        {
          // if nonconformity occurs then go up one level
          if( bnd->level () != bnd->ghostLevel() )
          {
            bnd = static_cast<const BNDFaceType *>(bnd->up());
            assert( bnd );
            outerElement_ = static_cast<const HasFaceType*> (bnd);
          }

          // set boundary type to ghost boundary
          bndType_ = outerGhostBoundary ;

          // access ghost only when ghost cells are enabled
          if( ghostCellsEnabled_ )
          {
            // get ghost and internal number
            GhostPairType p  = bnd->getGhost();
            outerFaceNumber_ = p.second;

            const GEOElementType* ghost = static_cast<const GEOElementType*> (p.first);
            assert( ghost );
            outerTwist_ = ghost->twist(outerFaceNumber_);
          }
        }
        else // the normal boundary case
        {
          // get outer twist
          outerTwist_ = boundaryFace().twist(outerALUFaceIndex());
          // store segment index
          segmentIndex_ = boundaryFace().segmentIndex();
          bndId_ = boundaryFace().bndtype();
        }
      }
    }
    else
    {
      // get outer twist
      outerTwist_ = outerEntity().twist(outerALUFaceIndex());
    }

    // make sure we got boundary id correctly
    assert( bndType_ == periodicBoundary || bndType_ == domainBoundary ? bndId_ > 0 : bndId_ == 0 );

    // set conformance information
    conformanceState_ = getConformanceState(innerLevel);
  }

  // points face from inner element away?
  template< ALU3dGridElementType type, class Comm >
  inline ALU3dGridFaceInfo< type, Comm >::
  ALU3dGridFaceInfo(const GEOFaceType& face,
                    int innerTwist)
  {
    updateFaceInfo(face,innerTwist);
  }

  template< ALU3dGridElementType type, class Comm >
  inline ALU3dGridFaceInfo< type, Comm >::~ALU3dGridFaceInfo() {}

  template< ALU3dGridElementType type, class Comm >
  ALU3dGridFaceInfo< type, Comm >::
  ALU3dGridFaceInfo ( const ALU3dGridFaceInfo &orig )
    : face_(orig.face_),
      innerElement_(orig.innerElement_),
      outerElement_(orig.outerElement_),
      innerFaceNumber_(orig.innerFaceNumber_),
      outerFaceNumber_(orig.outerFaceNumber_),
      innerTwist_(orig.innerTwist_),
      outerTwist_(orig.outerTwist_),
      segmentIndex_( orig.segmentIndex_ ),
      bndId_( orig.bndId_ ),
      bndType_( orig.bndType_ ),
      conformanceState_(orig.conformanceState_),
      conformingRefinement_( orig.conformingRefinement_ ),
      ghostCellsEnabled_( orig.ghostCellsEnabled_ )
  {}

  template< ALU3dGridElementType type, class Comm >
  inline bool ALU3dGridFaceInfo< type, Comm >::isElementLike() const {
    return bndType_ < domainBoundary;
  }

  template< ALU3dGridElementType type, class Comm >
  inline bool ALU3dGridFaceInfo< type, Comm >::innerBoundary() const {
    return bndType_ == innerGhostBoundary;
  }

  template< ALU3dGridElementType type, class Comm >
  inline bool ALU3dGridFaceInfo< type, Comm >::outerBoundary() const {
    return bndType_ == domainBoundary;
  }

  template< ALU3dGridElementType type, class Comm >
  inline bool ALU3dGridFaceInfo< type, Comm >::boundary() const {
    return outerBoundary() || (bndType_ == periodicBoundary);
  }

  template< ALU3dGridElementType type, class Comm >
  inline bool ALU3dGridFaceInfo< type, Comm >::neighbor() const
  {
    return isElementLike() || ( ghostBoundary() && ghostCellsEnabled_ );
  }

  template< ALU3dGridElementType type, class Comm >
  inline bool ALU3dGridFaceInfo< type, Comm >::ghostBoundary () const
  {
    // when communicator is No_Comm there is no ghost boundary
    return parallel() ? ( bndType_ == outerGhostBoundary ) : false ;
  }

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridFaceInfo< type, Comm >::GEOFaceType&
  ALU3dGridFaceInfo< type, Comm >::face() const
  {
    return *face_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridFaceInfo< type, Comm >::GEOElementType&
  ALU3dGridFaceInfo< type, Comm >::innerEntity() const
  {
    assert( ! innerElement_->isboundary() );
    return static_cast<const GEOElementType&>(*innerElement_);
  }

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridFaceInfo< type, Comm >::GEOElementType&
  ALU3dGridFaceInfo< type, Comm >::outerEntity() const
  {
    assert( isElementLike() );
    return static_cast<const GEOElementType&>(*outerElement_);
  }

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridFaceInfo< type, Comm >::BNDFaceType&
  ALU3dGridFaceInfo< type, Comm >::innerFace() const
  {
    assert( innerElement_->isboundary() );
    return static_cast<const BNDFaceType&>(*innerElement_);
  }

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridFaceInfo< type, Comm >::BNDFaceType&
  ALU3dGridFaceInfo< type, Comm >::boundaryFace() const {
    assert( ! isElementLike() );
    return static_cast<const BNDFaceType&>(*outerElement_);
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::outsideLevel() const
  {
    assert( outerElement_ );
    assert( !isElementLike() || outerEntity().level() == outerElement_->nbLevel() );
    assert( isElementLike() || boundaryFace().level() == outerElement_->nbLevel() );
    return outerElement_->nbLevel();
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::segmentIndex() const
  {
    assert( segmentIndex_ >= 0 );
    return segmentIndex_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::boundaryId() const
  {
    return bndId_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::innerTwist() const
  {
    // don't check ghost boundaries here
    assert( ( ! innerBoundary() ) ?
            innerEntity().twist(innerALUFaceIndex()) == innerTwist_ : true );
    return innerTwist_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::duneTwist(const int faceIdx, const int aluTwist) const
  {
    typedef ElementTopologyMapping<type> ElementTopo;
    typedef FaceTopologyMapping<type> FaceTopo;

    const int mappedZero =
      FaceTopo::twist(ElementTopo::dune2aluFaceVertex( faceIdx, 0), aluTwist);

    const int twist =
      (ElementTopo::faceOrientation( faceIdx ) * sign(aluTwist) < 0 ?
       mappedZero : -mappedZero-1);

    // see topology.* files
    return FaceTopo :: aluTwistMap( twist );
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::outerTwist() const
  {
    // don't check ghost boundaries here
    //assert( (outerBoundary_) ?
    //          (outerTwist_ == boundaryFace().twist(0)) :
    //          (! ghostBoundary_) ?
    //          (outerTwist_ == outerEntity().twist(outerALUFaceIndex())) : true
    //      );
    return outerTwist_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::innerALUFaceIndex() const {
    return innerFaceNumber_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridFaceInfo< type, Comm >::outerALUFaceIndex() const {
    return outerFaceNumber_;
  }

  template< ALU3dGridElementType type, class Comm >
  typename ALU3dGridFaceInfo< type, Comm >::ConformanceState
  inline ALU3dGridFaceInfo< type, Comm >::conformanceState() const
  {
    assert( conformanceState_ != UNDEFINED );
    return conformanceState_;
  }

  // calculate conformance state
  template< ALU3dGridElementType type, class Comm >
  typename ALU3dGridFaceInfo< type, Comm >::ConformanceState
  inline ALU3dGridFaceInfo< type, Comm >::getConformanceState(const int innerLevel) const
  {
    ConformanceState result = CONFORMING;

    // in case of non-conforming refinement check level difference
    if( ! conformingRefinement_ )
    {
      // A boundary is always unrefined
      int levelDifference = 0 ;
      if ( isElementLike() )
        levelDifference = innerLevel - outerEntity().level();
      else
        levelDifference = innerLevel - boundaryFace().level();

      if (levelDifference < 0) {
        result = REFINED_OUTER;
      }
      else if (levelDifference > 0) {
        result = REFINED_INNER;
      }
    }

    return result;
  }

  template< ALU3dGridElementType type, class Comm >
  inline ALU3dGridGeometricFaceInfoBase< type, Comm >::
  ALU3dGridGeometricFaceInfoBase(const ConnectorType& connector) :
    connector_(connector),
    coordsSelfLocal_(-1.0),
    coordsNeighborLocal_(-1.0),
    generatedGlobal_(false),
    generatedLocal_(false)
  {}

  template< ALU3dGridElementType type, class Comm >
  inline void
  ALU3dGridGeometricFaceInfoBase< type, Comm >::
  resetFaceGeom()
  {
    generatedGlobal_ = false;
    generatedLocal_  = false;
  }

  template< ALU3dGridElementType type, class Comm >
  inline ALU3dGridGeometricFaceInfoBase< type, Comm >::
  ALU3dGridGeometricFaceInfoBase ( const ALU3dGridGeometricFaceInfoBase &orig )
    : connector_(orig.connector_),
      coordsSelfLocal_(orig.coordsSelfLocal_),
      coordsNeighborLocal_(orig.coordsNeighborLocal_),
      generatedGlobal_(orig.generatedGlobal_),
      generatedLocal_(orig.generatedLocal_)
  {}

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridGeometricFaceInfoBase< type, Comm >::CoordinateType&
  ALU3dGridGeometricFaceInfoBase< type, Comm >::intersectionSelfLocal() const {
    generateLocalGeometries();
    assert(generatedLocal_);
    return coordsSelfLocal_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline const typename ALU3dGridGeometricFaceInfoBase< type, Comm >::CoordinateType&
  ALU3dGridGeometricFaceInfoBase< type, Comm >::intersectionNeighborLocal() const {
    assert(!connector_.outerBoundary());
    generateLocalGeometries();
    assert(generatedLocal_);
    return coordsNeighborLocal_;
  }


  //sepcialisation for tetra and hexa
  template< class Comm >
  inline ALU3dGridGeometricFaceInfoTetra< Comm >::
  ALU3dGridGeometricFaceInfoTetra(const ConnectorType& connector)
    : Base( connector ), normalUp2Date_( false )
  {}

  template< class Comm >
  inline void ALU3dGridGeometricFaceInfoTetra< Comm >::
  resetFaceGeom()
  {
    Base::resetFaceGeom();
    normalUp2Date_ = false;
  }

  template< class Comm >
  inline ALU3dGridGeometricFaceInfoTetra< Comm >::
  ALU3dGridGeometricFaceInfoTetra(const ALU3dGridGeometricFaceInfoTetra& orig)
    : Base( orig ), normalUp2Date_( orig.normalUp2Date_ )
  {}

  template< class Comm >
  template <class GeometryImp>
  inline void
  ALU3dGridGeometricFaceInfoTetra< Comm >::
  buildGlobalGeom(GeometryImp& geo) const
  {
    if (! this->generatedGlobal_)
    {
      // calculate the normal
      const GEOFaceType & face = this->connector_.face();

      geo.buildGeom( face.myvertex(FaceTopo::dune2aluVertex(0))->Point() ,
                     face.myvertex(FaceTopo::dune2aluVertex(1))->Point() ,
                     face.myvertex(FaceTopo::dune2aluVertex(2))->Point() );

      this->generatedGlobal_ = true ;
    }
  }

  template< class Comm >
  inline FieldVector<alu3d_ctype, 3> &
  ALU3dGridGeometricFaceInfoTetra< Comm >::
  outerNormal(const FieldVector<alu3d_ctype, 2>& local) const
  {
    // if geomInfo was not reseted then normal is still correct
    if(!normalUp2Date_)
    {
      // calculate the normal
      const GEOFaceType & face = this->connector_.face();
      const alu3d_ctype (&_p0)[3] = face.myvertex(0)->Point();
      const alu3d_ctype (&_p1)[3] = face.myvertex(1)->Point();
      const alu3d_ctype (&_p2)[3] = face.myvertex(2)->Point();

      // change sign if face normal points into inner element
      // factor is 1.0 to get integration outer normal and not volume outer normal
      const double factor = (this->connector_.innerTwist() < 0) ? 1.0 : -1.0;

      // see mapp_tetra_3d.h for this piece of code
      outerNormal_[0] = factor * ((_p1[1]-_p0[1]) *(_p2[2]-_p1[2]) - (_p2[1]-_p1[1]) *(_p1[2]-_p0[2]));
      outerNormal_[1] = factor * ((_p1[2]-_p0[2]) *(_p2[0]-_p1[0]) - (_p2[2]-_p1[2]) *(_p1[0]-_p0[0]));
      outerNormal_[2] = factor * ((_p1[0]-_p0[0]) *(_p2[1]-_p1[1]) - (_p2[0]-_p1[0]) *(_p1[1]-_p0[1]));

      normalUp2Date_ = true;
    } // end if mapp ...

    return outerNormal_;
  }

  //-sepcialisation for and hexa
  template< class Comm >
  inline ALU3dGridGeometricFaceInfoHexa< Comm >::
  ALU3dGridGeometricFaceInfoHexa(const ConnectorType& connector)
    : Base( connector )
      , mappingGlobal_()
      , mappingGlobalUp2Date_(false)
  {}

  template< class Comm >
  inline void ALU3dGridGeometricFaceInfoHexa< Comm >::
  resetFaceGeom()
  {
    Base::resetFaceGeom();
    mappingGlobalUp2Date_ = false;
  }

  template< class Comm >
  inline ALU3dGridGeometricFaceInfoHexa< Comm >::
  ALU3dGridGeometricFaceInfoHexa(const ALU3dGridGeometricFaceInfoHexa& orig)
    : Base( orig )
      , mappingGlobal_(orig.mappingGlobal_)
      , mappingGlobalUp2Date_(orig.mappingGlobalUp2Date_)
  {}

  template< class Comm >
  template <class GeometryImp>
  inline void
  ALU3dGridGeometricFaceInfoHexa< Comm >::
  buildGlobalGeom(GeometryImp& geo) const
  {
    if (! this->generatedGlobal_)
    {
      // calculate the normal
      const GEOFaceType & face = this->connector_.face();

      geo.buildGeom( face.myvertex(FaceTopo::dune2aluVertex(0))->Point() ,
                     face.myvertex(FaceTopo::dune2aluVertex(1))->Point() ,
                     face.myvertex(FaceTopo::dune2aluVertex(2))->Point() ,
                     face.myvertex(FaceTopo::dune2aluVertex(3))->Point() );
      this->generatedGlobal_ = true ;
    }
  }

  template< class Comm >
  inline FieldVector<alu3d_ctype, 3> &
  ALU3dGridGeometricFaceInfoHexa< Comm >::
  outerNormal(const FieldVector<alu3d_ctype, 2>& local) const
  {
    // if mapping calculated and affine, nothing more to do
    if ( mappingGlobal_.affine () && mappingGlobalUp2Date_ )
      return outerNormal_ ;

    // update surface mapping
    if(! mappingGlobalUp2Date_ )
    {
      const GEOFaceType & face = connector_.face();
      // update mapping to actual face
      mappingGlobal_.buildMapping(
        face.myvertex( FaceTopo::dune2aluVertex(0) )->Point(),
        face.myvertex( FaceTopo::dune2aluVertex(1) )->Point(),
        face.myvertex( FaceTopo::dune2aluVertex(2) )->Point(),
        face.myvertex( FaceTopo::dune2aluVertex(3) )->Point()
        );
      mappingGlobalUp2Date_ = true;
    }

    // calculate the normal
    // has to be calculated every time normal called, because
    // depends on local
    if (connector_.innerTwist() < 0)
      mappingGlobal_.negativeNormal(local,outerNormal_);
    else
      mappingGlobal_.normal(local,outerNormal_);

    // end if
    return outerNormal_;
  }

  template< ALU3dGridElementType type, class Comm >
  inline void ALU3dGridGeometricFaceInfoBase< type, Comm >::
  generateLocalGeometries() const
  {
    if (!generatedLocal_) {
      // Get the coordinates of the face in the reference element of the
      // adjoining inner and outer elements and initialise the respective
      // geometries
      switch (connector_.conformanceState())
      {
      case (ConnectorType::CONFORMING) :
        referenceElementCoordinatesRefined(INNER, coordsSelfLocal_);
        // generate outer local geometry only when not at boundary
        // * in the parallel case, this needs to be altered for the ghost cells
        if (!connector_.outerBoundary()) {
          referenceElementCoordinatesRefined(OUTER, coordsNeighborLocal_);
        } // end if
        break;
      case (ConnectorType::REFINED_INNER) :
        referenceElementCoordinatesRefined(INNER, coordsSelfLocal_);
        referenceElementCoordinatesUnrefined(OUTER, coordsNeighborLocal_);
        break;
      case (ConnectorType::REFINED_OUTER) :
        referenceElementCoordinatesUnrefined(INNER, coordsSelfLocal_);
        referenceElementCoordinatesRefined(OUTER, coordsNeighborLocal_);
        break;
      default :
        std::cerr << "ERROR: Wrong conformanceState in generateLocalGeometries! in: " << __FILE__ << " line: " << __LINE__<< std::endl;
        assert(false);
        exit(1);
      } // end switch

      generatedLocal_ = true;
    } // end if
  }

  template< ALU3dGridElementType type, class Comm >
  inline int ALU3dGridGeometricFaceInfoBase< type, Comm >::
  globalVertexIndex(const int duneFaceIndex,
                    const int aluFaceTwist,
                    const int duneFaceVertexIndex) const
  {
    const int localALUIndex =
      FaceTopo::dune2aluVertex(duneFaceVertexIndex,
                               aluFaceTwist);

    // get local ALU vertex number on the element's face
    const int localDuneIndex = ElementTopo::
                               alu2duneFaceVertex(ElementTopo::dune2aluFace(duneFaceIndex),
                                                  localALUIndex);

    return getReferenceElement().subEntity(duneFaceIndex, 1, localDuneIndex, 3);
  }


  template< ALU3dGridElementType type, class Comm >
  inline void ALU3dGridGeometricFaceInfoBase< type, Comm >::
  referenceElementCoordinatesRefined(SideIdentifier side,
                                     CoordinateType& result) const
  {
    // this is a dune face index
    const int faceIndex =
      (side == INNER ?
       ElementTopo::alu2duneFace(connector_.innerALUFaceIndex()) :
       ElementTopo::alu2duneFace(connector_.outerALUFaceIndex()));
    const int faceTwist =
      (side == INNER ?
       connector_.innerTwist() :
       connector_.outerTwist());

    const ReferenceElementType& refElem = getReferenceElement();

    for (int i = 0; i < numVerticesPerFace; ++i)
    {
      int duneVertexIndex = globalVertexIndex(faceIndex, faceTwist, i);
      result[i] = refElem.position(duneVertexIndex, 3);
    }
  }
} //end namespace Dune
#endif
