#ifndef XDKWRL_PROTO_H
#define XDKWRL_PROTO_H

#include <xdkwrl/config.h>
#include <xdkwrl/node.h>
#include <xdkwrl/fieldtypes/mfnode.h>
#include <xdkwrl/fieldtypes/mfstring.h>
#include <list>
#include <map>

namespace wrl
{
  class ProtoInstance;
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Interface of DeclaredNodeWithBindings
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  class XDKWRL_API DeclaredNodeWithBindings : public DeclaredNode
  {
  public:
    DeclaredNodeWithBindings(const char* name="");
    typedef std::pair<std::string,std::string> Binding;
    typedef std::map<Node*,std::list<Binding> > BindingMap;
    void bindFields(Node* n,const char* to, const char* from);
    void bindEventsIn(Node* n,const char* to, const char* from);
    void bindEventsOut(Node* n,const char* to, const char* from);
    inline const BindingMap& fieldBindings() const;
    inline const BindingMap& eventInBindings() const;
    inline const BindingMap& eventOutBindings() const;
    virtual void setField(const FieldHandle& f,const SFBool&);
    virtual void setField(const FieldHandle& f,const SFColor&);
    virtual void setField(const FieldHandle& f,const SFFloat&);
    virtual void setField(const FieldHandle& f,const SFImage&);
    virtual void setField(const FieldHandle& f,const SFInt32&);
    virtual void setField(const FieldHandle& f,const SFNode&);
    virtual void setField(const FieldHandle& f,const SFRotation&);
    virtual void setField(const FieldHandle& f,const SFString&);
    virtual void setField(const FieldHandle& f,const SFTime&);
    virtual void setField(const FieldHandle& f,const SFVec2f&);
    virtual void setField(const FieldHandle& f,const SFVec3f&);
    virtual void setField(const FieldHandle& f,const MFColor&);
    virtual void setField(const FieldHandle& f,const MFFloat&);
    virtual void setField(const FieldHandle& f,const MFInt32&);
    virtual void setField(const FieldHandle& f,const MFNode&);
    virtual void setField(const FieldHandle& f,const MFRotation&);
    virtual void setField(const FieldHandle& f,const MFString&);
    virtual void setField(const FieldHandle& f,const MFTime&);
    virtual void setField(const FieldHandle& f,const MFVec2f&);
    virtual void setField(const FieldHandle& f,const MFVec3f&);    
  protected:    
    void propagateBindings();
    BindingMap fieldBindings_;
    BindingMap eventInBindings_;
    BindingMap eventOutBindings_;
  };
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Interface of ProtoDeclaration
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  class XDKWRL_API ProtoDeclaration : public DeclaredNodeWithBindings
  {
  public:
    ProtoDeclaration(const char* nodeTypeId,const char* name="");
    virtual bool isSetToDefaultValue(unsigned int i) const;
    inline const char* typeName() const;
    void setNodes(const MFNode&);
    inline const MFNode& nodes() const;
    virtual Node* duplicate() const;
    virtual Node* duplicate(std::map<const Node*,Node*>&) const;    

    virtual inline bool isExtern() const;
    virtual inline bool hasNodes() const;
  private:
    friend class ProtoInstance;
    std::string        nodeTypeId_;
    MFNode             nodes_;
  };
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Interface of ExternProtoDeclaration
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  class XDKWRL_API ExternProtoDeclaration : public ProtoDeclaration
  {
  public:
    ExternProtoDeclaration(const char* nodeTypeId,const char* name="");
    MFString urls;
    virtual inline bool isExtern() const;
    virtual inline bool hasNodes() const;
    bool getExternalDeclaration();
  private:
    bool loaded_;
  };
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Interface of ProtoInstance
  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  class XDKWRL_API ProtoInstance : public DeclaredNodeWithBindings
  {
  public:
    ProtoInstance(const ProtoDeclaration* d,const char* name="");
    inline const char* typeName() const;
    virtual bool isSetToDefaultValue(unsigned int i) const;
    inline const ProtoDeclaration* declaration() const;
    virtual Node* duplicate() const;
    virtual Node* duplicate(std::map<const Node*,Node*>&) const;    
    inline const MFNode& nodes() const;
  private:
    ProtoInstance(const char* name="");
    const ProtoDeclaration* declaration_;
    MFNode                  nodes_;
  };
  //************************************************************
  // Implementation of DeclaredNodeWithBindings
  //************************************************************
  inline const DeclaredNodeWithBindings::BindingMap&
  DeclaredNodeWithBindings::fieldBindings() const
  {
    return fieldBindings_;
  }
  inline const DeclaredNodeWithBindings::BindingMap&
  DeclaredNodeWithBindings::eventInBindings() const
  {
    return eventInBindings_;
  }
  inline const DeclaredNodeWithBindings::BindingMap&
  DeclaredNodeWithBindings::eventOutBindings() const
  {
    return eventOutBindings_;
  }
  //************************************************************
  // Implementation of ProtoDeclaration
  //************************************************************
  inline const char*
  ProtoDeclaration::typeName() const
  {
    return nodeTypeId_.c_str();
  }
  inline const MFNode&
  ProtoDeclaration::nodes() const
  {
    return nodes_;
  }
  inline bool
  ProtoDeclaration::isExtern() const
  {
    return false;
  }
  /*!
   * Return true if the Proto declaration is loaded. The only case where it
   * returns false is for an extern proto not loaded.
   */
  inline bool
  ProtoDeclaration::hasNodes() const
  {
    return true;
  }
  //************************************************************
  // Implementation of ExternProtoDeclaration
  //************************************************************
  inline bool
  ExternProtoDeclaration::isExtern() const
  {
    return true;
  }
  inline bool
  ExternProtoDeclaration::hasNodes() const
  {
    return loaded_;
  }
  //************************************************************
  // Implementation of ProtoInstance
  //************************************************************
  inline const ProtoDeclaration*
  ProtoInstance::declaration() const
  {
    return declaration_;
  }
  inline const char*
  ProtoInstance::typeName() const
  {
    return declaration_->typeName();
  }
  inline const MFNode&
  ProtoInstance::nodes() const
  {
    return nodes_;
  }
};

#endif // XDKWRL_PROTO_H

// Local variables section.
// This is only used by emacs!
// Local Variables:
// ff-search-directories: ("." "../../src/xdkwrl/")
// End:
