/// This file is part of the X3DToolKit library
/// Copyright (C) 2002-2004  Yannick Le Goc (legoc@imag.fr)

/// http://artis.imag.fr/Members/Yannick.Legoc/X3D/

/// 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 2.1 of the License, or (at your option) any later version.

/// This library 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 library; if not, write to the Free Software
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#ifndef X3DTK_SFTYPE_H
#define X3DTK_SFTYPE_H

#include <map>
#include <vector>

#include "X3DTypes.h"
#include "SFSceneGraph.h"
#include "SFComponent.h"
#include "Singleton.h"
#include "X3DNodeCloner.h"
#include "X3DMemberFunctor.h"
#include "X3DSFNodeFunctor.h"
#include "X3DMFNodeFunctor.h"

namespace X3DTK {

class Visitor;
class BaseRecorder;

namespace X3D {
  class Creator;
  class X3DComponentCreator;
}

struct FieldManager
{
  X3DMemberFunctor *memberFunctor;
  X3DFieldLoader *loader;
  X3DFieldWriter *writer;
  SFString init;
};

/*! \brief Class declared in <b><X3DTK/kernel.h></b> storing the informations relative 
 *  to the nodes of the inheritance tree. 
 *
 *  It is based upon one singleton per tag. It means that it 
 *  exists only one instance of SFType of tag name "Cylinder" for the component "Geometry3D"
 *  of the "GL" scene graph.
 *
 *  \ingroup abstractNode
 */

class SFType
{
  friend class X3D::Creator;
  friend class Walker;
  friend class Visitor;
  friend class BaseRecorder;
  friend class X3D::X3DComponentCreator;
  friend class X3DComponentWalker;
  friend class X3DComponentVisitor;
  friend class X3DAbstractNode;
  friend class X3DRoute;

public:
  /// Gets the SFType by its name.
  static SFType *getTypeOfName(const SFString &sceneGraph, const SFString &component, const SFString &name);
  /// Gets the SFType by its id.
  static SFType *getTypeOfId(int id);
  /// Recomputes the id and changes all the nodeProxy array. (Not yet implemented)
  static void recomputeIds();
  
  /// Returns the name of the type.
  inline const SFString &getName() const {return _name;};
  /// Returns the name of the component of the type.
  inline const SFString &getComponentName() const {return _component->getName();};
  /// Returns the name of the scene graph of the type.
  inline const SFString &getSceneGraphName() const {return _component->getSceneGraph()->getName();};
  /// Returns the id of the type.
  inline int getId() const {return _id;};
  /// Gets the superclass SFType.
  inline SFType *getParent() const {return _parent;};
  /// Gets the list of children.
  inline const MFType &getChildren() const {return _childList;};
  /// Gets the component.
  inline SFComponent *getComponent() const {return _component;};
  /// Gets the scene graph.
  inline SFSceneGraph *getSceneGraph() const {return _component->getSceneGraph();};
  /// Prints the current inheritance tree.
  static void printInheritanceTree();

  /// Computes the key from the sceneGraph, SFComponent and SFType strings.
  static SFString encodeKey(const SFString &sceneGraph, const SFString &component, const SFString &SFType);
  /// Returns the encoded name of the node
  inline SFString getEncodedName() const {return encodeKey(getSceneGraphName(), getComponentName(), getName());};
  
  /// Returns the real string name of the attribute in case of event in.
  SFString getEventIn(const SFString &name) const;
  /// Returns the real string name of the attribute in case of event out.
  SFString getEventOut(const SFString &name) const;
  
  /// Returns the attribute map.
  std::map<SFString, FieldManager> &attributesMap() {return _attributesMap;};
  /// Returns the node map.
  std::vector<std::pair<SFString, X3DSFNodeFunctor *> > &nodeMap() {return _nodeMap;};
  /// Returns the nodes map.
  std::vector<std::pair<SFString, X3DMFNodeFunctor *> > &nodesMap() {return _nodesMap;};
  
private:
  /// Constructor.
  SFType(const SFString &name, const SFString &component, const SFString &sceneGraph, X3DNodeCloner *cloner);
  ~SFType();

  /// Sets the parent of the inheritance hierarchy.
  void setParent(SFType *parent);
  /// Adds one instance of the SFType.
  void addOneReference();
  /// Adds one instance of the SFType and of the parent SFTypes.
  void addOneReferenceRecursive();
  /// Removes one instance of the SFType.
  static void removeOneReference(SFType *type);
  /// Defines a new Tag name. Only X3DNode is able to call this method.
  static void defineTypeName(SFType **type, const SFString &name, const SFString &component, const SFString &sceneGraph, X3DNodeCloner *cloner);
  /// Gets the X3DMemberFunctor for the name attribute.
  X3DMemberFunctor *getMemberFunctor(const SFString &name) const;
  /// Gets the X3DFieldLoader for the name attribute.
  X3DFieldLoader *getFieldLoader(const SFString &name) const;
  /// Gets the X3DFieldLoader for the name attribute.
  X3DFieldWriter *getFieldWriter(const SFString &name) const;
  
  /// Adds a new proxy. Only X3DNodeProxy is able to call this method.
  static void addVisitor(Visitor *visitor);
  /// Removes proxy from the list. Only X3DNodeProxy is able to call this method.
  static void removeVisitor(Visitor *visitor);

  /// Specifies to SFType that the next new Nodes are necessary to get their name and 
  /// will not be used then.
  static void beginFunctionDefinition();
  /// Specifies to SFType that the function definition is terminated.
  static void endFunctionDefinition();
  
  /// attributes
  SFString _name;
  int _id;
  int _refCount;
  SFType *_parent;
  MFType _childList;
  SFComponent *_component;
  X3DNodeCloner *_cloner;
  std::map<SFString, FieldManager> _attributesMap;
  std::vector<std::pair<SFString, X3DSFNodeFunctor *> > _nodeMap;
  std::vector<std::pair<SFString, X3DMFNodeFunctor *> > _nodesMap;
  
  /// static attributes
  static int count;
  static MFType _typeList;  
  static std::list<Visitor *> _actorList;
  static bool _functionDefinition;
 
  void printInheritanceTree(SFString tab) const;
};

}

#endif
