namespace X3DTK {
namespace X3D {

template<class MData, class VData, class EData, class FData, bool RW>
TemplateMeshBuilderShapeVisitor<MData, VData, EData, FData, RW>::TemplateMeshBuilderShapeVisitor()
: ShapeVisitor()
{
  define(Recorder<Shape>::getEnterFunction(&TemplateMeshBuilderShapeVisitor::enterShape));
  define(Recorder<X3DAppearanceNode>::getEnterFunction(&TemplateMeshBuilderShapeVisitor::enterX3DAppearanceNode));
  define(Recorder<X3DAppearanceNode>::getWalkOnFunction(&TemplateMeshBuilderShapeVisitor::walkOnX3DAppearanceNode));
  define(Recorder<Shape>::getLeaveFunction(&TemplateMeshBuilderShapeVisitor::leaveShape));
  define(Recorder<X3DAppearanceNode>::getLeaveFunction(&TemplateMeshBuilderShapeVisitor::leaveX3DAppearanceNode));
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderShapeVisitor<MData, VData, EData, FData, RW>::enterShape(Shape *S) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();

  if (dynamic_cast<IndexedFaceSet *>(S->getGeometry()) != 0)
  {
    // If Shape has an IndexedFaceSet as a child, then we build the Mesh.
    MESH::X3DNode *MS = stateVariables->getNode(S);
    if (MS == 0)
    {
      MS = new MESH::Shape();
      MS->setName(S->getName());
      
      stateVariables->addCoupleNode(S, MS);
    }
    stateVariables->pushNode(MS);
  }
  else
  {
    // Shape has not an IndexedFaceSet as a child, but a Cylinder, Sphere...
    stateVariables->disableChildrenVisit();
    X3DNode *NS = static_cast<X3DNode *>(stateVariables->clone(S));
  
    MESH::X3DGroupingNode *G = dynamic_cast<MESH::X3DGroupingNode *>(stateVariables->getTop());
    if (G != 0)
      G->setChild(NS);
  }  
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderShapeVisitor<MData, VData, EData, FData, RW>::enterX3DAppearanceNode(X3DAppearanceNode *N) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  X3DAppearanceNode *NN = static_cast<X3DAppearanceNode *>(stateVariables->clone(N));
  
  MESH::Shape *S = dynamic_cast<MESH::Shape *>(stateVariables->getTop());
  if (S != 0)
    S->setChild(NN);
}

template<class MData, class VData, class EData, class FData, bool RW>
bool TemplateMeshBuilderShapeVisitor<MData, VData, EData, FData, RW>::walkOnX3DAppearanceNode(X3DAppearanceNode *, SFNode) 
{
  return false;
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderShapeVisitor<MData, VData, EData, FData, RW>::leaveShape(Shape *S) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();

  if (dynamic_cast<IndexedFaceSet *>(S->getGeometry()) != 0)
    stateVariables->popNode();
  else
    stateVariables->enableChildrenVisit();  
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderShapeVisitor<MData, VData, EData, FData, RW>::leaveX3DAppearanceNode(X3DAppearanceNode *) 
{
}
  
}
}
