#ifndef INCLUDED_BOBCAT_REVERSE_
#define INCLUDED_BOBCAT_REVERSE_

#include <type_traits>
#include <iterator>

namespace FBB
{

template <typename Type, bool isConst>
class Reverse
{
    Type &d_type;

    using reverse_iter =
            std::reverse_iterator<
                typename
                    std::conditional<
                        isConst,
                        typename Type::const_iterator,
                        typename Type::iterator
                    >::type
            >;

    public:
        Reverse(Type &type);

        reverse_iter begin() const;
        reverse_iter end() const;
};

template <typename Type, size_t size>
class ReverseArray
{
    Type (&d_type)[size];

    public:
        ReverseArray(Type (&type)[size]);

        std::reverse_iterator<Type *> begin() const
        {
            return std::reverse_iterator<Type *>{ d_type + size };
        }

        std::reverse_iterator<Type *> end() const
        {
            return std::reverse_iterator<Type *>{ d_type };
        }
};

template <typename Type>
class ReverseSize
{
    Type *d_type;
    size_t d_size;

    public:
        ReverseSize(Type *type, size_t size);

        std::reverse_iterator<Type *> begin() const
        {
            return std::reverse_iterator<Type *>{ d_type + d_size };
        }

        std::reverse_iterator<Type *> end() const
        {
            return std::reverse_iterator<Type *>{ d_type };
        }
};

template <typename Type, bool isConst>
inline Reverse<Type, isConst>::Reverse(Type &type)
:
    d_type(type)
{}

template <typename Type, bool isConst>
inline Reverse<Type, isConst>::reverse_iter
                                    Reverse<Type, isConst>::begin() const
{
    return reverse_iter{ d_type.end() };
}

template <typename Type, bool isConst>
inline Reverse<Type, isConst>::reverse_iter
                                    Reverse<Type, isConst>::end() const
{
    return reverse_iter{ d_type.begin() };
}

template <typename Type>
inline auto reverse(Type &type)
{
    return Reverse<Type, false>{ type };
}

template <typename Type>
inline auto reverse(Type const &type)
{
    return Reverse<Type const, true>{ type };
}

template <typename Type>
inline auto reverse(Type &&type)
{
    return Reverse<Type, false>{ type };
}

template <typename Type, size_t size>
inline ReverseArray<Type, size>::ReverseArray(Type (&type)[size])
:
    d_type(type)
{}

template <typename Type, size_t size>
inline auto reverse(Type (&type)[size])
{
    return ReverseArray<Type, size>{ type };
}

template <typename Type>
inline ReverseSize<Type>::ReverseSize(Type *type, size_t size)
:
    d_type(type),
    d_size(size)
{}

template <typename Type>
inline auto reverse(Type *type, size_t size)
{
    return ReverseSize<Type>{ type, size };
}

} // FBB
#endif
