// -*- mode: c++ -*-

#ifndef MiX_NODECONTAINER_H_
#define MiX_NODECONTAINER_H_

#include "NodeList.h"
#include "Node.h"

namespace MiX{

  template <class charT,class char_traits,class xml_traits>
  class NodeContainer : virtual public Node<charT,char_traits,xml_traits>{
  public:
    MiX_Template_Typedef(charT,char_traits,xml_traits);
    typedef NodeContainer<charT,char_traits,xml_traits> this_type;
  protected:
    nodelist_type children_;
    void addChild(node_type* node);

    std::map<string_type,string_type> name_to_url_;

    void cloneChildren(this_type& dest) const{
      typename nodelist_type::const_iterator it = getChildren().begin();
      typename nodelist_type::const_iterator last = getChildren().end();
      for( ; it!=last ; ++it ){
	(*it)->clone(dest,dest.getChildren().end());
      }
    }

  protected:
    ///コンストラクタ
    NodeContainer() : node_type(),children_() { };
    /**
     * コピーコンストラクタ
     *
     * クライアントはこれを呼び出せない。つまりコピーできない。
     */
    NodeContainer(const this_type& src){ };
    /// 
    template <class Pred>
    typename nodelist_type::iterator search(Pred pred,int index){
      int i = 0;
      typename nodelist_type::iterator it,first,last=getChildren().end();
      for ( first=getChildren().begin(); it!=last ; first=++it,++i ){
	it = std::find_if(first,last,pred);
	if( i==index ) break;
      }
      return it;
    }
  public:
    ///デストラクタ
    virtual ~NodeContainer() throw();
    ///子ノードのリストへの参照を得ます
    nodelist_type& getChildren(){ return children_; };
    ///子ノードのリストへの参照を得ます(const版)
    const nodelist_type& getChildren() const { return children_; };

    ///アトリビュートが存在するかどうか
    bool hasAttribute(const string_type& nm);
    ///アトリビュートが存在するかどうか
    bool hasAttribute(const string_type& nm,const string_type& ns);
    ///子アトリビュートを得ます
    attribute_type& getAttribute(const string_type& nm,const string_type& ns);
    ///子アトリビュートを得ます
   attribute_type& getAttribute(const string_type& nm);
    ///子エレメントを得ます
    element_type& getElement(const string_type& name,int index);
    ///子エレメントを得ます
    element_type& getElement(const string_type& name,const string_type& ns,int index);
    
    /**
     * 指定した名前を持つ子エレメントを検索し、リストを返します
     *
     * \param tagname タグ名
     */
    nodelist_type getElementsByTagName(const string_type& tagname,const string_type& ns = string_type() );

    /// 名前空間URLに名前を設定します
    void addNSName(const string_type& name,const string_type& url) {
      name_to_url_.insert(make_pair(name,url));
    }
    /// 名前からURLを得ます。
    string_type queryURL(const string_type& name) const;
    /// URLから名前を得ます。
    string_type queryNSName(const string_type& url) const;
    
    friend class DOM_Parser<charT,char_traits,xml_traits>;
  };
}

#ifndef MiX_NODECONTAINER_CPP_
#include "NodeContainer.cpp"
#endif

#endif
