/**
 * @file avltree_iterator_imp.hpp
 *
 * CopyRight F. J. Madrid-Cuevas <fjmadrid@uco.es>
 *
 * Sólo se permite el uso de este código en la docencia de las asignaturas sobre
 * Estructuras de Datos de la Universidad de Córdoba.
 *
 * Está prohibido su uso para cualquier otro objetivo.
 */
#pragma once
#include <cassert>
#include <avltree_iterator.hpp>

template <class T>
bool AVLTreeIterator<T>::is_valid() const
{
    return (node_!=nullptr);
}

template <class T>
AVLTreeIterator<T>::AVLTreeIterator(typename AVLTNode<T>::Ref const &node)
{
    node_=node;
}

template <class T>
bool AVLTreeIterator<T>::operator==(AVLTreeIterator<T> const &other) const
{
    return (node_==other.node_);
}

template <class T>
bool AVLTreeIterator<T>::operator!=(AVLTreeIterator<T> const &other) const
{
    return !(node_==other.node_);
}

template <class T>
typename AVLTreeIterator<T>::reference AVLTreeIterator<T>::operator*() const
{
    assert(is_valid());
    return node_->item();
}

template <class T>
typename AVLTreeIterator<T>::pointer AVLTreeIterator<T>::operator->() const
{
    assert(is_valid());
    return &(node_->item());
}

template <class T>
AVLTreeIterator<T> &AVLTreeIterator<T>::operator++()
{
    if (node_->right() != nullptr){
        node_ = node_->right();
        while (node_->left() != nullptr)
            node_ = node_->left();
    }else{
        auto parent = node_->parent();
        while (parent != nullptr && node_ == parent->right()){
            node_ = parent;
            parent = parent->parent();
        }
        node_ = parent;
    }
    return *this;
}


template <class T>
AVLTreeIterator<T> AVLTreeIterator<T>::operator++(int)
{
    AVLTreeIterator<T> old = *this;
    ++(*this);
    return old;
}

template <class T>
AVLTreeIterator<T> &AVLTreeIterator<T>::operator--()
{
    assert(is_valid());
    if (node_->left() != nullptr){
        node_ = node_->left();
        while (node_->right() != nullptr)
            node_ = node_->right();
    }else{
        auto parent = node_->parent();
        while (parent != nullptr && node_ == parent->left()){
            node_ = parent;
            parent = parent->parent();
        }
        node_ = parent;
    }
    return *this;
}

template <class T>
AVLTreeIterator<T> AVLTreeIterator<T>::operator--(int)
{
    AVLTreeIterator<T> old = *this;
    --(*this);
    return old;
}
