#ifndef PHYCPP_TREE_ITERATOR_HPP
#define PHYCPP_TREE_ITERATOR_HPP

#include "../utility/selectif.hpp"

namespace PhyCpp {
 
namespace Detail {

// Element iterators
 
  template <typename NodeOrEdge, typename Node, bool IsConst, bool IsReverse>
  class BasicTreeIterator {

	  template <typename, typename, bool, bool> friend class BasicTreeIterator;
  
    public:

	  typedef NodeOrEdge Edge;

      typedef typename Detail::SelectIf<IsConst, const Node *, Node *>::type node_pointer;
      typedef typename Detail::SelectIf<IsConst, const NodeOrEdge *, NodeOrEdge *>::type element_pointer;

      BasicTreeIterator(element_pointer n = 0) {pos = (n == 0) ? 0 : n->parentEdge();}

      template <typename Elem, bool C> BasicTreeIterator(const BasicTreeIterator<Elem, Node, C, IsReverse> & other) {pos = other.pos;}

      ~BasicTreeIterator() {}

      template <typename Elem, bool C>
      bool operator !=(const BasicTreeIterator<Elem, Node, C, IsReverse> & other) const {return pos != other.pos;}

      BasicTreeIterator & operator ++() {pos = (IsReverse) ? pos->postorderNext() : pos->preorderNext(); return *this;}
      BasicTreeIterator & operator --() {pos = (IsReverse) ? pos->preorderNext() : pos->postorderNext(); return *this;}

      element_pointer operator->() const {return pos->parentEdge();}
      element_pointer operator*() const {return pos->parentEdge();}

    private:

      node_pointer pos;
  };
  
    template <typename NodeT, bool IsConst, bool IsReverse>
    class BasicTreeIterator <NodeT, NodeT, IsConst, IsReverse> {

    	template <typename, typename, bool, bool> friend class BasicTreeIterator;
  
    public:

      typedef NodeT Node;
      typedef typename Detail::SelectIf<IsConst, const Node *, Node *>::type node_pointer;
      typedef typename Detail::SelectIf<IsConst, const Node *, Node *>::type element_pointer;

      BasicTreeIterator(element_pointer n = 0) : pos(n) {}
      ~BasicTreeIterator() {}

      template <typename Elem, bool C> BasicTreeIterator(const BasicTreeIterator<Elem, Node, C, IsReverse> & other) {pos = other.pos;}

      template <typename Elem, bool C>
      bool operator !=(const BasicTreeIterator<Elem, Node, C, IsReverse> & other) const {return pos != other.pos;}

      BasicTreeIterator & operator ++() {pos = (IsReverse) ? pos->postorderNext() : pos->preorderNext(); return *this;}
      BasicTreeIterator & operator --() {pos = (IsReverse) ? pos->preorderNext() : pos->postorderNext(); return *this;}

      element_pointer operator->() const {return pos;}
      element_pointer operator*() const {return pos;}

    private:

      node_pointer pos;
  };

} // namespace Detail
  
} // namespace PhyCpp

#endif // PHYCPP_TREE_ITERATOR_HPP
