//  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_KARMA_PHOENIX_ATTRIBUTES_OCT_01_2009_1128AM)
#define BOOST_SPIRIT_KARMA_PHOENIX_ATTRIBUTES_OCT_01_2009_1128AM

#if defined(_MSC_VER)
#pragma once
#endif

#include <boost/spirit/include/version.hpp>

// we support Phoenix attributes only starting with V2.2
#if SPIRIT_VERSION >= 0x2020

#include <boost/spirit/home/karma/detail/attributes.hpp>
#include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
#include <boost/spirit/home/support/container.hpp>

#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/utility/result_of.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace traits
{
    ///////////////////////////////////////////////////////////////////////////
    // Provide customization points allowing the use of phoenix expressions as 
    // generator functions in the context of generators expecting a container 
    // attribute (Kleene, plus, list, repeat, etc.)
    ///////////////////////////////////////////////////////////////////////////
    template <typename Eval>
    struct is_container<phoenix::actor<Eval> const>
      : is_container<typename boost::result_of<phoenix::actor<Eval>()>::type>
    {};

    template <typename Eval>
    struct container_iterator<phoenix::actor<Eval> const>
    {
        typedef phoenix::actor<Eval> const& type;
    };

    template <typename Eval>
    struct begin_container<phoenix::actor<Eval> const>
    {
        typedef phoenix::actor<Eval> const& type;
        static type call(phoenix::actor<Eval> const& f)
        {
            return f;
        }
    };

    template <typename Eval>
    struct end_container<phoenix::actor<Eval> const>
    {
        typedef phoenix::actor<Eval> const& type;
        static type call(phoenix::actor<Eval> const& f)
        {
            return f;
        }
    };

    template <typename Eval>
    struct deref_iterator<phoenix::actor<Eval> const>
    {
        typedef typename boost::result_of<phoenix::actor<Eval>()>::type type;
        static type call(phoenix::actor<Eval> const& f)
        {
            return f();
        }
    };

    template <typename Eval>
    struct next_iterator<phoenix::actor<Eval> const>
    {
        typedef phoenix::actor<Eval> const& type;
        static type call(phoenix::actor<Eval> const& f)
        {
            return f;
        }
    };

    template <typename Eval>
    struct compare_iterators<phoenix::actor<Eval> const>
    {
        static bool 
        call(phoenix::actor<Eval> const&, phoenix::actor<Eval> const&)
        {
            return false;
        }
    };

    template <typename Eval>
    struct container_value<phoenix::actor<Eval> >
    {
        typedef phoenix::actor<Eval> const& type;
    };

    template <typename Eval>
    struct make_indirect_iterator<phoenix::actor<Eval> const>
    {
        typedef phoenix::actor<Eval> const& type;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Handle Phoenix actors as attributes, just invoke the function object
    // and deal with the result as the attribute.
    ///////////////////////////////////////////////////////////////////////////
    template <typename Eval, typename Exposed>
    struct extract_from_attribute<phoenix::actor<Eval>, Exposed>
    {
        typedef typename boost::result_of<phoenix::actor<Eval>()>::type type;

        template <typename Context>
        static type call(phoenix::actor<Eval> const& f, Context& context)
        {
            return f(unused, context);
        }
    };
}}}

#endif
#endif
