#pragma once

namespace Framework
{
    template<typename T> class BasicIterator
    {
    public:
        virtual ~BasicIterator() {}

        virtual operator bool() = 0;

        virtual T val() = 0;

        virtual void plusPlus() = 0;
    };

    /**
     * Iterator interface
     * \tparam T type of the value that is iterated
     * \tparam I type of the iterator subclass
     */
    template<typename T, typename I> class Iterator : public BasicIterator<T>
    {
    public:
        virtual ~Iterator()
        {
            static_assert(std::is_base_of<Iterator, I>::value,
                "Type Argument I must be an implementation of Iterator");
        }

        virtual bool hasNext()
        {
            return (bool)next();
        }

        virtual I next() = 0;

        virtual void plusPlus() override
        {
            *(I*)this = next();
        }

        virtual I& operator++() //! prefix
        {
            *(I*)this = next();
            return *(I*)this;
        }

        virtual I operator++(int) //! postfix
        {
            I tmp(*(I*)this);
            operator++();
            return tmp;
        }

        virtual void set(T val) = 0;

        virtual void remove() = 0;

        operator T()
        {
            return this->val();
        }

        virtual T operator->()
        {
            return this->val();
        }

        virtual T operator*()
        {
            return this->val();
        }
    };
} // namespace Framework