//  Copyright (c) 2001, Daniel C. Nuffer
//  Copyright (c) 2001-2011 Hartmut Kaiser
//  http://spirit.sourceforge.net/
//
//  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_ITERATOR_MULTI_PASS_MAR_16_2007_1124AM)
#define BOOST_SPIRIT_ITERATOR_MULTI_PASS_MAR_16_2007_1124AM

#include <boost/config.hpp>
#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/combine_policies.hpp>
#include <boost/limits.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/utility/base_from_member.hpp>

namespace boost {
namespace spirit {
///////////////////////////////////////////////////////////////////////////
// The default multi_pass instantiation uses a ref-counted std_deque scheme.
///////////////////////////////////////////////////////////////////////////
template<typename T, typename Policies>
class multi_pass
    : private boost::base_from_member<
      typename Policies::BOOST_NESTED_TEMPLATE shared<T>*>
    , public Policies::BOOST_NESTED_TEMPLATE unique<T>
{
  private:
    // unique and shared data types
    typedef typename Policies::BOOST_NESTED_TEMPLATE unique<T>
    policies_base_type;
    typedef typename Policies::BOOST_NESTED_TEMPLATE shared<T>
    shared_data_type;

    typedef boost::base_from_member<shared_data_type*> member_base;

    // define the types the standard embedded iterator typedefs are taken
    // from
    typedef typename policies_base_type::input_policy iterator_type;

  public:
    // standard iterator typedefs
    typedef std::forward_iterator_tag iterator_category;
    typedef typename iterator_type::value_type value_type;
    typedef typename iterator_type::difference_type difference_type;
    typedef typename iterator_type::distance_type distance_type;
    typedef typename iterator_type::reference reference;
    typedef typename iterator_type::pointer pointer;

    multi_pass() : member_base(static_cast<shared_data_type*>(0)) {}

    explicit
    multi_pass(T& input)
        : member_base(new shared_data_type(input)), policies_base_type(input) {}

    explicit
    multi_pass(T const& input)
        : member_base(new shared_data_type(input)), policies_base_type(input) {}

    multi_pass(multi_pass const& x)
        : member_base(x.member), policies_base_type(x)
    {
        policies_base_type::clone(*this);
    }

#if BOOST_WORKAROUND(__GLIBCPP__, == 20020514)
    // The standard library shipped with gcc-3.1 has a bug in
    // bits/basic_string.tcc. It tries to use iter::iter(0) to
    // construct an iterator. Ironically, this  happens in sanity
    // checking code that isn't required by the standard.
    // The workaround is to provide an additional constructor that
    // ignores its int argument and behaves like the default constructor.
    multi_pass(int) : member_base(static_cast<shared_data_type*>(0)) {}
#endif // BOOST_WORKAROUND(__GLIBCPP__, == 20020514)

    ~multi_pass()
    {
        if (policies_base_type::release(*this))
        {
            policies_base_type::destroy(*this);
            delete this->member;
        }
    }

    multi_pass&
    operator=(multi_pass const& x)
    {
        if (this != &x)
        {
            multi_pass temp(x);
            temp.swap(*this);
        }

        return *this;
    }

    void
    swap(multi_pass& x)
    {
        boost::swap(this->member, x.member);
        this->policies_base_type::swap(x);
    }

    reference
    operator*() const
    {
        policies_base_type::docheck(*this);
        return policies_base_type::dereference(*this);
    }
    pointer
    operator->() const
    {
        return &(operator*());
    }

    multi_pass&
    operator++()
    {
        policies_base_type::docheck(*this);
        policies_base_type::increment(*this);
        return *this;
    }
    multi_pass
    operator++(int)
    {
        multi_pass tmp(*this);
        ++*this;
        return tmp;
    }

    void
    clear_queue(BOOST_SCOPED_ENUM(traits::clear_mode) mode =
                    traits::clear_mode::clear_if_enabled)
    {
        if (mode == traits::clear_mode::clear_always || !inhibit_clear_queue())
        {
            policies_base_type::clear_queue(*this);
        }
    }
    bool
    inhibit_clear_queue() const
    {
        return this->member->inhibit_clear_queue_;
    }
    void
    inhibit_clear_queue(bool flag)
    {
        this->member->inhibit_clear_queue_ = flag;
    }

    bool
    operator==(multi_pass const& y) const
    {
        if (is_eof())
        {
            return y.is_eof();
        }

        if (y.is_eof())
        {
            return false;
        }

        return policies_base_type::equal_to(*this, y);
    }
    bool
    operator<(multi_pass const& y) const
    {
        return policies_base_type::less_than(*this, y);
    }

    bool
    operator!=(multi_pass const& y) const
    {
        return !(*this == y);
    }
    bool
    operator>(multi_pass const& y) const
    {
        return y < *this;
    }
    bool
    operator>=(multi_pass const& y) const
    {
        return !(*this < y);
    }
    bool
    operator<=(multi_pass const& y) const
    {
        return !(y < *this);
    }

    // allow access to base member
    shared_data_type*
    shared() const
    {
        return this->member;
    }

  private: // helper functions
    bool
    is_eof() const
    {
        return (0 == this->member) || policies_base_type::is_eof(*this);
    }
};

///////////////////////////////////////////////////////////////////////////
//  Generator function
///////////////////////////////////////////////////////////////////////////
template <typename Policies, typename T>
inline multi_pass<T, Policies>
make_multi_pass(T& i)
{
    return multi_pass<T, Policies>(i);
}
template <typename Policies, typename T>
inline multi_pass<T, Policies>
make_multi_pass(T const& i)
{
    return multi_pass<T, Policies>(i);
}

///////////////////////////////////////////////////////////////////////////
template <typename T>
inline multi_pass<T>
make_default_multi_pass(T& i)
{
    return multi_pass<T>(i);
}
template <typename T>
inline multi_pass<T>
make_default_multi_pass(T const& i)
{
    return multi_pass<T>(i);
}

///////////////////////////////////////////////////////////////////////////
template <typename T, typename Policies>
inline void
swap(multi_pass<T, Policies> &x, multi_pass<T, Policies> &y)
{
    x.swap(y);
}

///////////////////////////////////////////////////////////////////////////
// define special functions allowing to integrate any multi_pass iterator
// with expectation points
namespace traits {
template <typename T, typename Policies>
void
clear_queue(multi_pass<T, Policies>& mp
            , BOOST_SCOPED_ENUM(traits::clear_mode) mode)
{
    mp.clear_queue(mode);
}

template <typename T, typename Policies>
void
inhibit_clear_queue(multi_pass<T, Policies>& mp, bool flag)
{
    mp.inhibit_clear_queue(flag);
}

template <typename T, typename Policies>
bool
inhibit_clear_queue(multi_pass<T, Policies>& mp)
{
    return mp.inhibit_clear_queue();
}
}

}
} // namespace boost::spirit

#endif
