namespace X3DTK {
namespace X3D {

template<class MData, class VData, class EData, class FData, bool RW>
TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::TemplateMeshBuilderGroupingVisitor()
: GroupingVisitor()
{
  // Enter functions.
  define(Recorder<X3DChildNode>::getEnterFunction(&TemplateMeshBuilderGroupingVisitor::enterX3DChildNode));
  define(Recorder<X3DGroupingNode>::getEnterFunction(&TemplateMeshBuilderGroupingVisitor::enterX3DGroupingNode));
  define(Recorder<StaticGroup>::getEnterFunction(&TemplateMeshBuilderGroupingVisitor::enterStaticGroup));
  define(Recorder<Transform>::getEnterFunction(&TemplateMeshBuilderGroupingVisitor::enterTransform));
  define(Recorder<Switch>::getEnterFunction(&TemplateMeshBuilderGroupingVisitor::enterSwitch));

  define(Recorder<X3DChildNode>::getLeaveFunction(&TemplateMeshBuilderGroupingVisitor::leaveX3DChildNode));
  define(Recorder<X3DGroupingNode>::getLeaveFunction(&TemplateMeshBuilderGroupingVisitor::leaveX3DGroupingNode));
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::enterX3DChildNode(X3DChildNode *N) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  stateVariables->disableChildrenVisit();
  X3DNode *NN = static_cast<X3DNode *>(stateVariables->clone(N));
  
  MESH::X3DGroupingNode *G = dynamic_cast<MESH::X3DGroupingNode *>(stateVariables->getTop());
  if (G != 0)
    G->setChild(NN);
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::enterX3DGroupingNode(X3DGroupingNode *N) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  MESH::X3DNode *MN = stateVariables->getNode(N);
  if (MN == 0)
  {
    MN = new MESH::Transform();
    MN->setName(N->getName());
      
    stateVariables->addCoupleNode(N, MN);
  }
  stateVariables->pushNode(MN);
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::enterStaticGroup(StaticGroup *S) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  MESH::X3DNode *MS = stateVariables->getNode(S);
  if (MS == 0)
  {
    MS = new MESH::Transform();  
    MS->setName(S->getName());
    
    stateVariables->addCoupleNode(S, MS);
  }
  stateVariables->pushNode(MS);
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::enterTransform(Transform *T) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  MESH::Transform *MT = dynamic_cast<MESH::Transform *>(stateVariables->getNode(T));
  if (MT == 0)
  {
    MT = new MESH::Transform();
    MT->setName(T->getName());    
    
    MT->setCenter(T->getCenter());
    MT->setRotation(T->getRotation());
    MT->setScale(T->getScale());
    MT->setScaleOrientation(T->getScaleOrientation());
    MT->setTranslation(T->getTranslation());
      
    stateVariables->addCoupleNode(T, MT);
  }
  stateVariables->pushNode(MT);
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::enterSwitch(Switch *S) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  MESH::X3DNode *MS = stateVariables->getNode(S);
  if (MS == 0)
  {
    MS = new MESH::Switch();  
    MS->setName(S->getName());
        
    stateVariables->addCoupleNode(S, MS);
  }
  stateVariables->pushNode(MS);
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::leaveX3DChildNode(X3DChildNode *) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  stateVariables->enableChildrenVisit();
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateMeshBuilderGroupingVisitor<MData, VData, EData, FData, RW>::leaveX3DGroupingNode(X3DGroupingNode *) 
{
  TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> *stateVariables = Singleton<TemplateMeshBuilderStateVariables<MData, VData, EData, FData, RW> >::getInstance();
  stateVariables->popNode();
}

}
}
