/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_CTL_REVERSE_ITERATOR_H
#define ECXX_CTL_REVERSE_ITERATOR_H


#include <eCxx/CTL/Types.h>


namespace eCxx {


//
// ReverseIterator<>
//
template <typename IteratorT>
class ReverseIterator {
    public:
        using IteratorType = IteratorT;
        using ValueType    = typename eCxx::removePointer<IteratorT>::Type;

    public:
        inline ReverseIterator()
        : _it()
        {}

        inline explicit ReverseIterator(IteratorType it)
        : _it(it)
        {}

        inline ReverseIterator(const ReverseIterator& it)
        : _it(it._it)
        {}

        template <typename OtherIteratorT>
        inline ReverseIterator(const ReverseIterator<OtherIteratorT>& it)
        : _it( it.base() )
        {}

        inline ReverseIterator& operator=(const ReverseIterator& it)
        {
            _it = it._it;
            return *this;
        }

        template <typename OtherIteratorT>
        inline ReverseIterator& operator=(const ReverseIterator<OtherIteratorT>& it)
        {
            _it = it.base();
            return *this;
        }

        inline IteratorType base() const
        { return _it; }

        inline ValueType* operator->() const
        {
            IteratorType tmp = _it;
            --tmp;
            return tmp;
        }

        inline ValueType& operator*() const
        { return *operator->(); }

        inline ValueType& operator[](size_t n) const
        { return *(*this + n); }

        inline ReverseIterator& operator++()
        {
            --_it;
            return *this;
        }

        inline ReverseIterator operator++(int)
        {
            ReverseIterator tmp = *this;
            --_it;
            return tmp;
        }

        inline ReverseIterator& operator+=(size_t n)
        {
            _it -= n;
            return *this;
        }

        inline ReverseIterator operator+(size_t n) const
        { return ReverseIterator(_it - n); }

        inline ReverseIterator& operator--()
        {
            ++_it;
            return *this;
        }

        inline ReverseIterator operator--(int)
        {
            ReverseIterator tmp = *this;
            ++_it;
            return tmp;
        }

        inline ReverseIterator& operator-=(size_t n)
        {
            _it += n;
            return *this;
        }

        inline ReverseIterator operator-(size_t n) const
        { return ReverseIterator(_it + n); }

        inline bool operator==(const ReverseIterator& it)
        { return _it == it._it; }

        inline bool operator!=(const ReverseIterator& it)
        { return _it != it._it; }

    private:
        IteratorType _it;
};


//
// makeReverseIterator<>()
//
template <typename IteratorT>
constexpr eCxx::ReverseIterator<IteratorT> makeReverseIterator(IteratorT it)
{ return eCxx::ReverseIterator<IteratorT>(it); }


} // namespace eCxx


#endif
