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

#ifndef MiX_ELEMENT_H_
#define MiX_ELEMENT_H_

#include "classes.h"
#include "misc.h"
#include "NodeContainer.h"
#include "extern/noncopyable.hpp"

namespace MiX{

  template <class charT,class char_traits,class xml_traits>
  class Element 
    : boost::noncopyable,
      public NodeContainer<charT,char_traits,xml_traits>, 
      public NamedNode<charT,char_traits,xml_traits>{
  public:
    MiX_Template_Typedef(charT,char_traits,xml_traits);
    typedef Element<charT,char_traits,xml_traits> this_type;
    typedef typename nodelist_type::iterator nodelist_iter; 
  private:
    const static typename nodelist_type::iterator dmy_it;
  protected:
    /**
     * コンストラクタ
     *
     *  Elementのコンストラクタは直接呼べません<br>
     *  Element<...>::createで生成してください
     *
     *  Elementの名前空間URLは子アトリビュートまでパージングした後
     *  設定しなければならないので、コンストラクタは名前空間に触れない。
     */
    Element(const string_type& name)
      : NodeContainer<charT,char_traits,xml_traits>(),
	NamedNode<charT,char_traits,xml_traits>(name){ };
  public:
    /// デストラクタ
    virtual ~Element()throw(){ };
    /// このノードのタイプを得ます
    virtual NodeType getType()const{ return Node_Element; };
    /**
     * 静的にクラスからNodeTypeを得ます
     *
     * 常にNode_Elementを返します
     */
    static NodeType type(){ return Node_Element; };
    /**
     * 子Elementにアクセスします
     *
     * szNameで与えられた名前を持つiIndex番目のElementへの参照を返します
     * 見つからなかった場合はDomException<...>を投げます
     */
    this_type& operator() (const string_type& name,int index=0){
      return getElement(name,index);
    };
    this_type& operator() (const string_type& name,const string_type& ns,int index=0){
      return getElement(name,ns,index);
    };
    /**
     * 子Attributeにアクセスします
     *
     * szNameで与えられた名前のAttributeへの参照を返します
     * 見つからなかった場合はDomException<...>を投げます
     */
    attribute_type& operator[] (const string_type& name){
      return getAttribute(name);
    };
    attribute_type& operator[] (std::pair<string_type,string_type> p){
      return getAttribute(p.first,p.second);
    };
    /**
     * このElementの文字列表現を得ます
     *
     *  bIndentが真の時、インデントを追加します
     */
    virtual string_type toString(bool is_indent=false,int indent_off=0)const;

    ///子Textの値を連結して返します
    string_type getText()const;

    ///子Textを全て消した後、sの値を持つ子Textを生成します。
    void setText(const XMLString<charT,char_traits,xml_traits>& s);

    string_type getFullName() const;
    /**
     * このElementを複製します
     *
     *  \param parent 複製先の親ノード
     *  \param it 挿入する場所(parent.getChilds()内の要素を示すイテレータでなくてはなりません)
     */
    node_type& clone(nodecontainer_type& parent,const nodelist_iter& it = dmy_it) const;
    /**
     * Elementを生成します
     *
     * \param name 生成するElementの名前
     * \param parent 生成するElementの親ノード
     * \param it 挿入する場所(parent.getChilds()内の要素を示すイテレータでなくてはなりません)
     */
    static this_type& create(const string_type& name,this_type& parent,const typename nodelist_type::iterator& it = dmy_it)
      { return this_type::create(name,string_type(),parent,it); }
    /**
     * Elementを生成します
     *
     * \param name 生成するElementの名前
     * \param ns 生成するElementの名前空間のURL
     * \param parent 生成するElementの親ノード
     * \param it 挿入する場所(parent.getChilds()内の要素を示すイテレータでなくてはなりません)
     */
    static this_type& create(const string_type& name,const string_type& ns,this_type& parent,const typename nodelist_type::iterator& it = dmy_it);

    friend class DOM_Parser<charT,char_traits,xml_traits>;
    friend class Document<charT,char_traits,xml_traits>;
  };
}

#ifndef MiX_ELEMENT_CPP_
#include "Element.cpp"
#endif

#endif
