#ifndef INCLUDED_BOBCAT_ITERATOR_
#define INCLUDED_BOBCAT_ITERATOR_

#include <iterator>
#include <limits>
#include <memory>

namespace FBB
{

template <typename Type>
class Iterator;

template <typename Type>
struct ReverseIterator: public std::reverse_iterator<Iterator<Type>>
{
    explicit ReverseIterator(Type const &value);
    explicit ReverseIterator(Iterator<Type> const &iter);

    static ReverseIterator<Type> last(Type const &value);
};

template <typename Type>
bool operator==(Iterator<Type> const &lhs, Iterator<Type> const &rhs);

template <typename Type>
struct Iterator
{
    friend  bool operator==<>(Iterator<Type> const &lhs,
                            Iterator<Type> const &rhs);

    using iterator_category = std::input_iterator_tag;
    using difference_type   = std::ptrdiff_t;
    using value_type        = Type const;
    using pointer           = value_type *;
    using reference         = value_type &;

    private:
        Type d_value;
        std::shared_ptr<Type> d_type;

    public:
        Iterator() = default;
        explicit Iterator(Type const &value);

        Iterator<Type> &operator++();
        Iterator<Type> operator++(int);

        Type const &operator*() const;

        static Iterator<Type> last(Type value);
        static Iterator<Type> min();
        static Iterator<Type> max();

    private:
        friend struct std::reverse_iterator<Iterator<Type>>;

        Iterator<Type> &operator--();
        Iterator<Type> operator--(int);
};


template <typename Type>
inline Iterator<Type>::Iterator(Type const &value)
:
    d_value(value),
    d_type(new Type)
{}
template <typename Type>
inline Iterator<Type> Iterator<Type>::last(Type value)
{
    return Iterator<Type>(++value);
}
template <typename Type>
inline Iterator<Type> Iterator<Type>::max()
{
    return Iterator<Type>(std::numeric_limits<Type>::max());
}
template <typename Type>
inline Iterator<Type> Iterator<Type>::min()
{
    return Iterator<Type>(std::numeric_limits<Type>::min());
}
template <typename Type>
inline Iterator<Type> &Iterator<Type>::operator--()
{
    --d_value;
    return *this;
}
template <typename Type>
inline bool operator==(Iterator<Type> const &lhs, Iterator<Type> const &rhs)
{
    return lhs.d_value == rhs.d_value;
}
template <typename Type>
inline Iterator<Type> &Iterator<Type>::operator++()
{
    ++d_value;
    return *this;
}
template <typename Type>
inline Iterator<Type> Iterator<Type>::operator--(int)
{
    Iterator<Type> tmp(d_value--);
    return tmp;
}
template <typename Type>
inline Iterator<Type> Iterator<Type>::operator++(int)
{
    Iterator<Type> tmp(d_value++);
    return tmp;
}
template <typename Type>
inline Type const &Iterator<Type>::operator*() const
{
    return d_value;
//
//    *d_type = d_value;
//    return *d_type;
}
template <typename Type>
inline bool operator!=(Iterator<Type> const &lhs, Iterator<Type> const &rhs)
{
    return not (lhs == rhs);
}
template <typename Type>
ReverseIterator<Type>::ReverseIterator(Type const &value)
:
    std::reverse_iterator<Iterator<Type>>(Iterator<Type>(value))
{}
template <typename Type>
ReverseIterator<Type>::ReverseIterator(Iterator<Type> const &vi)
:
    std::reverse_iterator<Iterator<Type>>(vi)
{}
template <typename Type>
inline ReverseIterator<Type> ReverseIterator<Type>::last(Type const &value)
{
    return ReverseIterator<Type>(Iterator<Type>::last(value));
}

} // FBB

#endif
