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

#include "misc.h"
#include "extern/compose.hpp"

#include <functional>

/** \file Functions
 * プログラミング時に便利な関数オブジェクトを宣言しています。
 */

namespace MiX{
  template <class charT,class char_traits,class xml_traits>
  class NodeTypeChecker
    : public std::unary_function<const Node<charT,char_traits,xml_traits>*,bool>{
  public:
    MiX_Template_Typedef(charT,char_traits,xml_traits);
    typedef const Node<charT,char_traits,xml_traits>* argument_type;
    typedef bool result_type; 
  private:
    NodeType type_;
  public:
    /// コンストラクタ
    NodeTypeChecker(NodeType t) : type_(t){ };
    /// nodeのタイプと構築時のパラメータtが等しければ真
    result_type operator()(argument_type node)const{
      return (node->getType()==type_);
    };
  };

  template <class charT,class char_traits,class xml_traits>
  class NodeNameChecker
    : public std::unary_function<const Node<charT,char_traits,xml_traits>*,bool>{
  public:
    MiX_Template_Typedef(charT,char_traits,xml_traits);
    typedef const node_type* argument_type;
    typedef bool result_type; 
  private:
    string_type name_,ns_;
  public:
    ///コンストラクタ
    NodeNameChecker(const string_type& name,string_type ns = string_type())
      : name_(name), ns_(ns) { };
    ///nodeの名前が構築時に与えられたパラメータnameと等しければ真
    result_type operator()(argument_type node)const;
  };

  template <class nodeT>
  class NamedNodeFinder
    : public std::unary_function<bool,Node<typename nodeT::char_type,
					   typename nodeT::char_traits_type,
					   typename nodeT::xml_traits_type>*> {
  public:
    typedef typename nodeT::char_type charT;
    typedef typename nodeT::char_traits_type char_traits;
    typedef typename nodeT::xml_traits_type xml_traits;

    MiX_Template_Typedef(charT,char_traits,xml_traits);
    typedef const node_type* argument_type;
    typedef bool result_type; 
    bool use_ns_;
    string_type name_,url_;
    
  public:
    /**
     * コンストラクタ
     *
     * \param name 名前
     * \param url 名前空間
     * 名前空間を使ったサーチを行なう
     */
    NamedNodeFinder(const string_type& name,const string_type& ns)
      { name_ = name;   url_ = ns; use_ns_ = true; }
    
    /**
     * コンストラクタ
     *
     * \param name 名前
     * 名前空間を使わないサーチを行なう
     */
    NamedNodeFinder(const string_type& name) { name_ = name; use_ns_ = false; }
    
    /// 実行
    bool operator()(argument_type node){
      if( node->getType()==nodeT::type() ) {
	const namednode_type* named=dynamic_cast<const namednode_type*>(node);
	if( !named ) return false;
	if( use_ns_ ) {
	  if( named->getName()==name_ && named->getURL()==url_ ) return true;
	} else {
	  if( named->getFullName()==name_ ) return true;
	}
      }
      return false;
    }
  };
}

#ifndef MIX_FUNCTIONS_CPP_
#include "Functions.cpp"
#endif

#endif
