#define MiX_ELEMENT_CPP_

#include <iostream>
#include <numeric>
#include <functional>

#include "Element.h"
#include "XMLString.h"
#include "DOM_Exception.h"

namespace MiX{
  //dmy_itはcreateで第三引数を省略するためのトリック
  template <class charT,class char_traits,class xml_traits>
  const typename NodeList<charT,char_traits,xml_traits>::iterator 
  Element<charT,char_traits,xml_traits>::dmy_it=NodeList<charT,char_traits,xml_traits>::iterator();
  
  template <class charT,class char_traits,class xml_traits>
  XMLString<charT,char_traits,xml_traits> Element<charT,char_traits,xml_traits>::getText()const{
    string_type ret;
    typename nodelist_type::const_iterator it = getChildren().begin();
    typename nodelist_type::const_iterator last = getChildren().end();
    for( ;it!=last;++it){
      if((*it)->getType()==Node_Text){
	const text_type& txt =dynamic_cast<const text_type&>(**it);
	ret+=txt.getValue();
      }
    }
    return ret;    
  }
  
  template <class charT,class char_traits,class xml_traits>
  void Element<charT,char_traits,xml_traits>::setText(const XMLString<charT,char_traits,xml_traits>& s){
    nodelist_type lst = getChildren();
    typename nodelist_type::iterator it = lst.begin();
    typename nodelist_type::iterator last = lst.end();
    
    for( ;it!=last;++it){
      if((*it)->getType()==Node_Text){
	(*it)->destroy(); 
      }
    }
    text_type::create(s,*this);
  };
  
  template <class charT,class char_traits,class xml_traits>
  XMLString<charT,char_traits,xml_traits> Element<charT,char_traits,xml_traits>::getFullName() const {
    string_type name;
    if( !getURL().empty() ) {
      string_type nsn = queryNSName( getURL() );
      if( !nsn.empty() ){
	name = nsn + xml_traits::colon();
      }
    }
    name += getName();
    return name;
  }    
  
  template <class charT,class char_traits,class xml_traits>
  XMLString<charT,char_traits,xml_traits> Element<charT,char_traits,xml_traits>::toString(bool is_indent,int indent_off) const {
    string_type s;
    if( is_indent ) insertIndent(indent_off,s,xml_traits::tab());
    s += xml_traits::lt();
    s += getFullName();
    typename std::map<string_type,string_type>::const_iterator mit,mlast;
    mit = name_to_url_.begin();
    mlast = name_to_url_.end();
    for( ; mit!=mlast ; ++mit ) {
      s += xml_traits::sp();
      s += xml_traits::str_xmlns();
      if( !mit->first.empty() ) s += xml_traits::colon() + mit->first;
      s += "=";
      s += xml_traits::dblquote() + mit->second + xml_traits::dblquote();
    }

    typename nodelist_type::const_iterator it = getChildren().begin();
    typename nodelist_type::const_iterator last = getChildren().end();
    for( ; it!=last ; ++it ) {
      if( (*it)->getType()==Node_Attribute){
	s += xml_traits::sp();
	s += (*it)->toString();
      }
    }
    string_type children;
    bool b = false;
    for( it=getChildren().begin() ; it!=last ; ++it ) {
      if((*it)->getType()!=Node_Attribute){
	b=true; 
	children+=(*it)->toString(is_indent,indent_off+1);
      }
    }
    if(b){
      s += xml_traits::gt(); 
      if(is_indent) s+=xml_traits::crlf();
      s += children;
      if(is_indent) insertIndent(indent_off,s,xml_traits::tab());
      s += xml_traits::lt() ; s += xml_traits::slash();
      s += getFullName() + xml_traits::gt();
      if(is_indent) s+=xml_traits::crlf();
    }else{
      s += xml_traits::slash(); s += xml_traits::gt();
      if(is_indent) s+=xml_traits::crlf();
    }
    return s;
  };

  template <class charT,class char_traits,class xml_traits>
  Node<charT,char_traits,xml_traits>& Element<charT,char_traits,xml_traits>::clone(nodecontainer_type& parent,const nodelist_iter& it) const {
    element_type* ret = new this_type(getName());
    ret->setURL(getURL());
    ret->setParent(parent);
    if(&it==&dmy_it)
      parent.getChildren().insert(parent.getChildren().end(),ret);
    else parent.getChildren().insert(it,ret);
    //element_type& ret = create(getName(),getURL(),parent,it);
    cloneChildren(*ret);
    return *ret;
  }

  template <class charT,class char_traits,class xml_traits>
  Element<charT,char_traits,xml_traits>& Element<charT,char_traits,xml_traits>::create(const string_type& name,const string_type& ns,element_type& parent,const typename nodelist_type::iterator& it){
    this_type* newel = new this_type(name);
    newel->setURL(ns);
    newel->setParent(parent);
    if(&it==&dmy_it)
      parent.getChildren().insert(parent.getChildren().end(),newel);
    else parent.getChildren().insert(it,newel);
    return *newel;
  }
  
}
