#define MiX_NODECONTAINER_CPP_

#include "NodeContainer.h"
#include "NodeList.h"
#include "Functions.h"

#include <algorithm>
#include <functional>

namespace MiX{
  template <class charT,class char_traits,class xml_traits>
  NodeContainer<charT,char_traits,xml_traits>::~NodeContainer()throw(){
    try{
      nodelist_type lst(getChildren());
      for(typename nodelist_type::iterator it=lst.begin();it!=lst.end();++it)
	delete (*it);
    }catch(...){
      //万が一例外が起こってしまった場合は無視する。
    }
  }
  
  template <class charT,class char_traits,class xml_traits>
  void NodeContainer<charT,char_traits,xml_traits>::addChild(node_type* node){
    typename nodelist_type::iterator it = std::find(getChildren().begin(),getChildren().end(),node);
    if(it!=children_.end()){ 
      std::ostringstream ss;
      ss << "DOM_Exception" << std::endl
	 << __FILE__ << ':' << __LINE__
	 << "Pointer duplication"<< std::endl << std::ends;
      throw DOM_Exception<charT,char_traits,xml_traits>(this,NodeDuplication,ss.str());
    }
    children_.push_back(node);
    node->setParent(*this);
  };

  template <class charT,class char_traits,class xml_traits>
  Element<charT,char_traits,xml_traits>& NodeContainer<charT,char_traits,xml_traits>::getElement(const string_type& name,int index) {
    typename nodelist_type::iterator it;
    it = search(NamedNodeFinder<element_type>(name),index);
    if( it==getChildren().end() ) {
      std::ostringstream ss;
      ss << "DOM_Exception" << std::endl
	 << __FILE__ << ':' << __LINE__ << std::endl
	 << "Element not found(" << name << ")" 
	 << std::endl << std::ends;
      throw dom_exception_type(this,NodeNotFound,ss.str());
    }
    return dynamic_cast<element_type&>(**it);
  }
  
  template <class charT,class char_traits,class xml_traits>
  Element<charT,char_traits,xml_traits>& NodeContainer<charT,char_traits,xml_traits>::getElement(const string_type& name,const string_type& ns,int index) {
    typename nodelist_type::iterator it;
    it = search(NamedNodeFinder<element_type>(name,ns),index);
    if( it==getChildren().end() ) {
      std::ostringstream ss;
      ss << "DOM_Exception" << std::endl
	 << __FILE__ << ':' << __LINE__ << std::endl
	 << "Element not found(" << name << '@' << ns << ")" 
	 << std::endl << std::ends;
      throw dom_exception_type(this,NodeNotFound,ss.str());
    }
    return dynamic_cast<element_type&>(**it);
  }

  template <class charT,class char_traits,class xml_traits>
  Attribute<charT,char_traits,xml_traits>& NodeContainer<charT,char_traits,xml_traits>::getAttribute(const string_type& name,const string_type& ns){
    typename nodelist_type::iterator it;
    it = search(NamedNodeFinder<attribute_type>(name,ns),0);
    if( it==getChildren().end() ) {
      std::ostringstream ss;
      ss << "DOM_Exception" << std::endl
	 << __FILE__ << ':' << __LINE__ << std::endl
	 << "Attribute not found(" << name << '@' << ns << ")" 
	 << std::endl << std::ends;
      throw dom_exception_type(this,NodeNotFound,ss.str());
    }
    return dynamic_cast<attribute_type&>(**it);
  }

  template <class charT,class char_traits,class xml_traits>
  Attribute<charT,char_traits,xml_traits>& NodeContainer<charT,char_traits,xml_traits>::getAttribute(const string_type& nm){
    typename nodelist_type::iterator it;
    it = search(NamedNodeFinder<attribute_type>(nm),0);
    if( it==getChildren().end() ) {
      std::ostringstream ss;
      ss << "DOM_Exception" << std::endl
	 << __FILE__ << ':' << __LINE__ << std::endl
	 << "Attribute not found(" << nm << ")" 
	 << std::endl << std::ends;
      throw dom_exception_type(this,NodeNotFound,ss.str());
    }
    return dynamic_cast<attribute_type&>(**it);
  }

  template <class charT,class char_traits,class xml_traits>
  bool NodeContainer<charT,char_traits,xml_traits>::hasAttribute(const string_type& nm,const string_type& ns){
    NamedNodeFinder<attribute_type> pred(nm,ns);
    typename nodelist_type::iterator it;
    it = std::find_if(getChildren().begin(),getChildren().end(),pred);
    return it!=getChildren().end();
  }

  template <class charT,class char_traits,class xml_traits>
  bool NodeContainer<charT,char_traits,xml_traits>::hasAttribute(const string_type& nm){
    NamedNodeFinder<attribute_type> pred(nm);
    typename nodelist_type::iterator it;
    it = std::find_if(getChildren().begin(),getChildren().end(),pred);
    return it!=getChildren().end();
  }
  
  template <class charT,class char_traits,class xml_traits>
  NodeList<charT,char_traits,xml_traits> NodeContainer<charT,char_traits,xml_traits>::getElementsByTagName(const string_type& tagname,const string_type& ns){
    nodelist_type ret;
    typename nodelist_type::iterator it = getChildren().begin();
    typename nodelist_type::iterator last = getChildren().end();
    for( ; it!=last ; ++it ){
      if((*it)->getType()==Node_Element){
	element_type& el = dynamic_cast<element_type&>(**it);
	if(el.getName()==tagname){
	  ret.push_back(&el);
	}
	nodelist_type lst = el.getElementsByTagName(tagname);
	ret.insert(ret.end(),lst.begin(),lst.end());
      }
    }
    return ret;
  }
  
  template <class charT,class char_traits,class xml_traits>
  MiX::XMLString<charT,char_traits,xml_traits> NodeContainer<charT,char_traits,xml_traits>::queryURL(const string_type& name) const {
    typename std::map<string_type,string_type>::const_iterator it;    
    if( (it=name_to_url_.find(name)) == name_to_url_.end() ){
      try { 
	return getParent().queryURL(name);
      } catch( dom_exception_type& e ) {
	if( e.getType()!=NullException ) throw;
	return string_type();
      }
    }
    return it->second;//name_to_url_[name];
  }

  template <class charT,class char_traits,class xml_traits>
  MiX::XMLString<charT,char_traits,xml_traits> NodeContainer<charT,char_traits,xml_traits>::queryNSName(const string_type& url) const {
    typename std::map<string_type,string_type>::const_iterator it,last;
    it = name_to_url_.begin();
    last = name_to_url_.end();

    for( ; it!=last ; ++it ) {
      if( it->second==url ) {
	return it->first;
      }
    }
    return getParent().queryNSName(url);
  }
}
