//  Copyright (c) 2001 Daniel C. Nuffer
//  Copyright (c) 2001-2011 Hartmut Kaiser
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#if !defined(BOOST_SPIRIT_BUFFERING_ITERATOR_INPUT_ITERATOR_POLICY_MAR_04_2010_1224AM)
#define BOOST_SPIRIT_BUFFERING_ITERATOR_INPUT_ITERATOR_POLICY_MAR_04_2010_1224AM

#include <boost/spirit/home/support/iterators/multi_pass_fwd.hpp>
#include <boost/spirit/home/support/iterators/detail/multi_pass.hpp>
#include <boost/spirit/home/support/iterators/detail/input_iterator_policy.hpp>
#include <boost/assert.hpp>
#include <iterator> // for std::iterator_traits

namespace boost {
namespace spirit {
namespace iterator_policies {
///////////////////////////////////////////////////////////////////////////
//  class input_iterator
//
//  Implementation of the InputPolicy used by multi_pass, this is different
//  from the input_iterator policy only as it is buffering the last input
//  character to allow returning it by reference. This is needed for
//  wrapping iterators not buffering the last item (such as the
//  std::istreambuf_iterator). Unfortunately there is no way to
//  automatically figure this out at compile time.
//
//  The buffering_input_iterator encapsulates an input iterator of type T
///////////////////////////////////////////////////////////////////////////
struct buffering_input_iterator
{
    ///////////////////////////////////////////////////////////////////////
    template <typename T>
    class unique // : public detail::default_input_policy
    {
        private:
        typedef
        typename std::iterator_traits<T>::value_type
        result_type;

        public:
        typedef
        typename std::iterator_traits<T>::difference_type
        difference_type;
        typedef
        typename std::iterator_traits<T>::difference_type
        distance_type;
        typedef
        typename std::iterator_traits<T>::pointer
        pointer;
        typedef result_type& reference;
        typedef result_type value_type;

        protected:
        unique() {}
        explicit
        unique(T) {}

        void
        swap(unique&) {}

public:
        template <typename MultiPass>
        static void
        destroy(MultiPass&) {}

        template <typename MultiPass>
        static typename MultiPass::reference
        get_input(MultiPass& mp)
        {
            return mp.shared()->get_input();
        }

        template <typename MultiPass>
        static void
        advance_input(MultiPass& mp)
        {
            BOOST_ASSERT(0 != mp.shared());
            mp.shared()->advance_input();
        }

        // test, whether we reached the end of the underlying stream
        template <typename MultiPass>
        static bool
        input_at_eof(MultiPass const& mp)
        {
            static T const end_iter;
            return mp.shared()->input_ == end_iter;
        }

        template <typename MultiPass>
        static bool
        input_is_valid(MultiPass const& mp, value_type const&)
        {
            return mp.shared()->input_is_valid_;
        }

        // no unique data elements
    };

    ///////////////////////////////////////////////////////////////////////
    template <typename T>
    struct shared
    {
        typedef
        typename std::iterator_traits<T>::value_type
        result_type;

        explicit
        shared(T const& input)
            : input_(input), curtok_(0), input_is_valid_(false) {}

        void
        advance_input()
        {
            ++input_;
            input_is_valid_ = false;
        }

        result_type&
        get_input()
        {
            if (!input_is_valid_)
            {
                curtok_ = *input_;
                input_is_valid_ = true;
            }

            return curtok_;
        }

        T input_;
        result_type curtok_;
        bool input_is_valid_;
    };
};

}
}
}

#endif
