#define MiX_DOCUMENT_CPP_

#include <iostream>
#include <sstream>
#include <functional>

#include "classes.h"
#include "config.h"
#include "Document.h"
#include "Comment.h"
#include "DOM_Exception.h"
#include "NodeList.h"

namespace MiX{
  //dmy_itはcreateで第三引数を省略するためのトリック
  template <class charT,class char_traits,class xml_traits>
  const typename NodeList<charT,char_traits,xml_traits>::iterator 
  Document<charT,char_traits,xml_traits>::dmy_it=NodeList<charT,char_traits,xml_traits>::iterator();

  template <class charT,class char_traits,class xml_traits>
  Element<charT,char_traits,xml_traits>& Document<charT,char_traits,xml_traits>::getRoot()const{
    typename nodelist_type::const_iterator it;
    NodeTypeChecker<charT,char_traits,xml_traits> pred(Node_Element);
    it = std::find_if(getChildren().begin(),getChildren().end(),pred);
    if(it!=getChildren().end()) return dynamic_cast<element_type&>(**it);
    std::ostringstream ss;
    ss << "DOM_Exception" << std::endl
       << __FILE__ << ':' << __LINE__ << std::endl
       << "RootNode not found" << std::endl << std::ends;
    throw DOM_Exception<charT,char_traits,xml_traits>(this,NodeNotFound,ss.str());
  }
  
  template <class charT,class char_traits,class xml_traits>
  XMLString<charT,char_traits,xml_traits> Document<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 += xml_traits::question(); 
    s += xml_traits::xml();
    //子アトリビュートの文字列化
    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();
      }
    }
    s += xml_traits::question(); s += xml_traits::gt();
    if(is_indent) s += xml_traits::crlf();
    it = getChildren().begin();
    for( ;it!=last;++it){
      if((*it)->getType()!=Node_Attribute){
	s += (*it)->toString(is_indent,indent_off);
      }
    }
    return s;
  };

  template <class charT,class char_traits,class xml_traits>
  Node<charT,char_traits,xml_traits>& Document<charT,char_traits,xml_traits>::clone()const{
    document_type* ret = new document_type();
    cloneChildren(*ret);
    return *ret;
  }

  template <class charT,class char_traits,class xml_traits>
  Document<charT,char_traits,xml_traits>& Document<charT,char_traits,xml_traits>::create(const XMLString<charT,char_traits,xml_traits>& rootname){
    document_type* newdoc = new document_type();
    element_type* newel = new element_type(rootname);
    newel->setParent(*newdoc);
    newdoc->getChildren().push_back(newel);
    return *newdoc;
  }
}
