#ifndef YASLI_FILL_ITERATOR_H_
#define YASLI_FILL_ITERATOR_H_

#include <iterator>
#include <cstddef>

namespace yasli_nstd
{
    template <class T>
	class fill_iterator_base
        : public std::iterator<
            std::random_access_iterator_tag,
		    T,
		    ptrdiff_t,
		    T*,
		    T&>
    {
    };

    template <class T>
	class fill_iterator_base<T&>
        : public std::iterator<
            std::random_access_iterator_tag,
		    T,
		    ptrdiff_t,
		    T*,
		    T&>
    {
    };

    template <class T>
    class fill_iterator : public fill_iterator_base<T>
	{
        T value_;
        /*difference_type*/ ptrdiff_t count_;//////////////////////////////////
    
    public:
        typedef std::ptrdiff_t difference_type;
        typedef typename fill_iterator_base<T>::pointer pointer;
	    typedef typename fill_iterator_base<T>::reference reference;
	    //typedef iterator_type;

	    fill_iterator()
		{	
		}

	    explicit fill_iterator(reference value, difference_type count = 0)
		: value_(value), count_(count)
		{	
		}

	    template<class U>
		fill_iterator(const fill_iterator<U>& rhs)
		: value_(rhs.value_), count_(rhs.count_)
		{
		}

	    reference operator*() const
		{
		    return value_;
		}

	    pointer operator->() const
        {
		    return &**this;
		}

	    fill_iterator& operator++()
		{	
            ++count_;
		    return *this;
		}

	    fill_iterator operator++(int)
        {
		    fill_iterator it(*this);
            ++*this;
		    return it;
        }

	    fill_iterator& operator--()
		{	
            --count_;
		    return *this;
		}

	    fill_iterator operator--(int)
        {
		    fill_iterator it(*this);
            --*this;
		    return it;
        }

	    fill_iterator& operator+=(difference_type d)
		{
		    count_ += d;
		    return *this;
		}

	    fill_iterator operator+(difference_type d) const
		{
		    return fill_iterator(*this) += d;
		}

	    fill_iterator& operator-=(difference_type d)
		{
		    count_ -= d;
		    return *this;
		}

	    fill_iterator operator-(difference_type d) const
		{
		    return fill_iterator(*this) -= d;
		}

        difference_type operator-(const fill_iterator<T>& rhs) const
        {
	        return count_ - rhs.count_;
        }

	    reference operator[](difference_type) const
		{
		    return **this;
		}

        template <class T2> 
        bool operator==(const fill_iterator<T2>& rhs) const
	    {
	        return count_ == rhs.count_;
        }

    };

    template <class T, class D> 
    inline fill_iterator<T> operator+(D lhs, const fill_iterator<T>& rhs)
    {
	    return rhs + lhs;
	}

    template <class T> 
    inline bool operator!=(
        const fill_iterator<T>& lhs,
		const fill_iterator<T>& rhs)
    {	// test for fill_iterator inequality
        return !(lhs == rhs);
    }

    template <class T> 
    inline bool operator<(
        const fill_iterator<T>& lhs,
		const fill_iterator<T>& rhs)
    {
        return lhs.count_ < rhs.count_;
    }

    template <class T> 
    inline bool operator>(
        const fill_iterator<T>& lhs,
	    const fill_iterator<T>& rhs)
    {
        return rhs < lhs;
    }

    template <class T> 
    inline bool operator<=(
        const fill_iterator<T>& lhs,
	    const fill_iterator<T>& rhs)
    {
        return !(rhs < lhs);
    }

    template <class T> 
    inline bool operator>=(
        const fill_iterator<T>& lhs,
        const fill_iterator<T>& rhs)
    {
        return !(lhs < rhs);
    }
} // namespace yasli_nstd

#endif
