// -*- mode: C++ -*-
#ifndef __MIX_NODELIST_H_
#define __MIX_NODELIST_H_

#include "classes.h"

#include <list>
 
namespace MiX{

  template <class charT,class char_traits,class xml_traits>
  class NodeList : public std::list<Node<charT,char_traits,xml_traits>* >{
  public:
    typedef Node<charT,char_traits,xml_traits>* value_type;
    typedef NodeList<charT,char_traits,xml_traits> this_type;
    typedef typename std::list<value_type>::iterator iterator;
    typedef typename std::list<value_type>::const_iterator const_iterator;

    /**
     * NodeList用の型指定イテレータ
     *
     * イテレータに型引数を与えることでキャストなしでノードにアクセスできます
     * NodeList\<...\>::Iterator\<Element\<...\> \>
     * はNodeList内のElement要素にだけアクセスするイテレータで、
     * (*it)はNode\<...\>*ではなく、Element\<...\>&を指します
     * これによってダウンキャストの必要がなくなります
     */
    template <class NodeT>
    class Iterator{
      typedef NodeT* pointer;
      typedef NodeT& reference;

      typedef NodeList<charT,char_traits,xml_traits> container_type;
      typedef container_type::iterator basic_iterator;
      typedef Iterator<NodeT> this_type;

      basic_iterator it_;
      container_type* container_;
      
      ///コンストラクタ
      Iterator(container_type* container,basic_iterator it){
	container_ = container;
	it_ = it;
      };
    public:
      /**
       * コンストラクタ
       *
       * 無効なIteratorを生成します
       */
      Iterator(){
	container_ = NULL;
      };
      ///参照外し
      reference operator*(){
	return dynamic_cast<NodeT&>(**it_);
      };
      ///メンバにアクセスします
      pointer operator->(){
	return dynamic_cast<NodeT*>(*it_);
      };
      ///イテレータを一つ進めます(前置インクリメント)
      this_type operator++(){
	basic_iterator itEnd=container_->end();
	++it_;
	while(it_!=itEnd){
	  if((*it_)->getType()==NodeT::type()) break;
	  ++it_;
	}
	return *this;
      };
      ///イテレータを一つ戻します(前置デクリメント)
      this_type operator--(){
	basic_iterator itBegin=container_->begin();
	while(it_!=itBegin){
	  --it_;
	  if((*it_)->getType()==NodeT::type()) break;
	}
	return *this;
      };
      /**
       * イテレータを一つ進めます(後置インクリメント)
       *
       * 後置インクリメントは前置インクリメントによって実装されています
       * ので、戻り値を利用しない場合は前置を利用したほうが効率的です
       */
      this_type operator++(int dmy){
	this_type ret = *this;
	++(*this);
	return ret;
      };
      /**
       * ポインタを一つ戻します(後置デクリメント)
       *
       * 後置デクリメントは前置デクリメントによって実装されています
       * ので、戻り値を利用しない場合は前置を利用したほうが効率的です
       */
      this_type operator--(int dmy){
	this_type ret = *this;
	--(*this);
	return ret;
      };
      //イテレータを比較します
      bool operator==(this_type& r)const{
	return it_==r.it_;
      };
      //イテレータを比較します
      bool operator!=(this_type& r)const{
	return !(*this==r);
      };
     
      friend class NodeList<charT,char_traits,xml_traits>;
    };
    /**
     * NodeList用の型指定イテレータ(const版)
     */
    template <class NodeT>
    class ConstIterator{
      typedef const NodeT* pointer;
      typedef const NodeT& reference;

      typedef NodeList<charT,char_traits,xml_traits> container_type;
      typedef container_type::const_iterator basic_iterator;
      typedef ConstIterator<NodeT> this_type;

      basic_iterator it_;
      container_type* container_;
      
      ///コンストラクタ
      ConstIterator(container_type* container,basic_iterator it){
	container_ = container;
	it_ = it;
      };
    public:
      /**
       * コンストラクタ
       *
       * 無効なIteratorを生成します
       */
      ConstIterator(){ container_ = NULL; };
      ///メンバにアクセスします
      pointer operator->(){return dynamic_cast<pointer>(*it_); };
      ///参照外し
      reference operator*(){return dynamic_cast<reference>(**it_);};
      ///イテレータを一つ進めます(前置インクリメント)
      this_type operator++(){
	basic_iterator itEnd=container_->end();
	++it_;
	while(it_!=itEnd){
	  if((*it_)->getType()==NodeT::type()) break;
	  ++it_;
	}
	return *this;
      };
      ///イテレータを一つ戻します(前置デクリメント)
      this_type operator--(){
	basic_iterator itBegin=container_->begin();
	while(it_!=itBegin){
	  --it_;
	  if((*it_)->getType()==NodeT::type()) break;
	}
	return *this;
      };
      /**
       * イテレータを一つ進めます(後置インクリメント)
       *
       * 後置インクリメントは前置インクリメントによって実装されています
       * ので、戻り値を利用しない場合は前置を利用したほうが効率的です
       */
      this_type operator++(int dmy){
	this_type ret = *this;
	++(*this);
	return ret;
      };
      /**
       * ポインタを一つ戻します(後置デクリメント)
       *
       * 後置デクリメントは前置デクリメントによって実装されています
       * ので、戻り値を利用しない場合は前置を利用したほうが効率的です
       */
      this_type operator--(int dmy){
	this_type ret = *this;
	--(*this);
	return ret;
      };
      //イテレータを比較します
      bool operator==(this_type& r)const{
	return it_==r.it_;
      };
      //イテレータを比較します
      bool operator!=(this_type& r)const{
	return !(*this==r);
      };
     
      friend class NodeList<charT,char_traits,xml_traits>;
    };

  public:
    ///最初の要素を示す型指定イテレータを得ます
    template <class NodeT>
    Iterator<NodeT> Begin(){
      this_type::Iterator<NodeT> ret = this_type::Iterator<NodeT>(this,begin());
      if((*(ret.it_))->getType()!=NodeT::type()) ++ret;
      return ret;
    };
    ///最初の要素を示す型指定イテレータを得ます(const版)
    template <class NodeT>
    ConstIterator<NodeT> Begin()const{
      this_type::ConstIterator<NodeT> ret = this_type::ConstIterator<NodeT>(this,begin());
      if((*(ret.it_))->getType()!=NodeT::type()) ++ret;
      return ret;
    };
    ///最後の要素の一つ後を示す型指定イテレータを得ます
    template <class NodeT>
    Iterator<NodeT> End(){
      return this_type::Iterator<NodeT>(this,end());
    };
    ///最後の要素の一つ後を示す型指定イテレータを得ます(const版)
    template <class NodeT>
    ConstIterator<NodeT> End()const{
      return this_type::ConstIterator<NodeT>(this,end());
    };
  };
}


#endif
