namespace X3DTK {
namespace MESH {

template<class MData, class VData, class EData, class FData, bool RW>
TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::TemplateFacesDrawerStateVariables()
: StateVariables(), _selectionMode(false), _drawingSelected(false), _mode(IFS)
{
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::init()
{
  GLfloat diffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
  GLfloat ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
  GLfloat emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
  GLfloat shininess = 0.0f;
  GLfloat specular[] = {0.0f, 0.0f, 0.0f, 1.0f};

  glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
  glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
  glMaterialfv(GL_FRONT, GL_EMISSION, emission);
  glMaterialfv(GL_FRONT, GL_SHININESS, &shininess); 
  glMaterialfv(GL_FRONT, GL_SPECULAR, specular);

  _matrixStack.push_front(SFMatrix34f::identity);
  _matrixVector.clear();
  _meshVector.clear();
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::initSelected()
{
  GLfloat diffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
  GLfloat ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
  GLfloat emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
  GLfloat shininess = 0.0f;
  GLfloat specular[] = {0.0f, 0.0f, 0.0f, 1.0f};

  glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
  glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
  glMaterialfv(GL_FRONT, GL_EMISSION, emission);
  glMaterialfv(GL_FRONT, GL_SHININESS, &shininess); 
  glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::finish()
{
  _matrixStack.pop_front();
  if (_matrixStack.size() != 0)
  {
    cx3d << "TemplateFacesDrawerStateVariables::finish: Non empty matrix stack at the end of TemplateFacesDrawer traversal" << std::endl;
    _matrixStack.clear();
  }
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::pushMatrix(const SFMatrix34f &transformation)
{
  _matrixStack.push_front(_matrixStack.front()*transformation);
}  

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::popMatrix()
{
  _matrixStack.pop_front(); 
}

template<class MData, class VData, class EData, class FData, bool RW>
int TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getCurrentMeshId()
{
  return _matrixVector.size() - 1;
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::storeMesh(TemplateMesh<MData, VData, EData, FData, RW> *mesh)
{
  _matrixVector.push_back(_matrixStack.front());
  _meshVector.push_back(mesh);
}

template<class MData, class VData, class EData, class FData, bool RW>
TemplateMesh<MData, VData, EData, FData, RW> *TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getMesh(int i) const 
{
  return _meshVector[i];
}

template<class MData, class VData, class EData, class FData, bool RW>
const SFMatrix34f &TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getMatrix(int i) const 
{
  return _matrixVector[i];
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::buildGLNode(X3D::X3DNode *node)
{
  GL::X3DNode *glNode = Singleton<X3D::GLBuilder>::getInstance()->build(node);
  _coupleMap[node] = glNode;
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::renderGLNode(X3D::X3DNode *node)
{
  Singleton<GL::Renderer>::getInstance()->render(_coupleMap[node]);
}

template<class MData, class VData, class EData, class FData, bool RW>
bool TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getNode(X3D::X3DNode *node)
{
  return (_coupleMap.find(node) != _coupleMap.end());
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::clearGLNodes()
{
  MemReleaser *releaser = Singleton<MemReleaser>::getInstance();
  for (std::map<X3D::X3DNode *, GL::X3DNode *>::iterator it = _coupleMap.begin(); it != _coupleMap.end(); ++it)
    releaser->release((*it).second);

  _coupleMap.clear();
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::setSelectionMode(bool selectionMode) 
{
  _selectionMode = selectionMode;
}

template<class MData, class VData, class EData, class FData, bool RW>
bool TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getSelectionMode() const 
{
  return _selectionMode;
}
 
template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::setDrawingSelected(bool drawingSelected) 
{
  _drawingSelected = drawingSelected;
}

template<class MData, class VData, class EData, class FData, bool RW>
bool TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getDrawingSelected() const 
{
  return _drawingSelected;
}
  
template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::setRenderingMode(FaceMode mode)
{
  _mode =  mode;
}

template<class MData, class VData, class EData, class FData, bool RW>
FaceMode TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getRenderingMode() const 
{
  return _mode;
}

template<class MData, class VData, class EData, class FData, bool RW>
void TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::setSelectedNodes(const MFNode &selectedNodes)
{
  _selectedNodes = selectedNodes;
}

template<class MData, class VData, class EData, class FData, bool RW>
MFNode TemplateFacesDrawerStateVariables<MData, VData, EData, FData, RW>::getSelectedNodes() const
{
  return _selectedNodes;
}

}
}
