/*=============================================================================
    Copyright (c) 2001-2011 Joel de Guzman
    Copyright (c) 2011 Thomas Bernard

    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(SPIRIT_KEYWORDS_DETAIL_MARCH_13_2007_1145PM)
#define SPIRIT_KEYWORDS_DETAIL_MARCH_13_2007_1145PM

#if defined(_MSC_VER)
#pragma once
#endif

namespace boost { namespace spirit { namespace repository { namespace qi { namespace detail {
        
        // This helper class enables jumping over intermediate directives 
        // down the kwd parser iteration count checking policy
        struct register_successful_parse
        {
            template <typename Subject>
            static bool call(Subject const &subject,bool &flag, int &counter)
            {
                return subject.iter.register_successful_parse(flag,counter);
            }
            template <typename Subject, typename Action>
            static bool call(spirit::qi::action<Subject, Action> const &subject,bool &flag, int &counter)
            {
                return subject.subject.iter.register_successful_parse(flag,counter);
            }
            template <typename Subject>
            static bool call(spirit::qi::hold_directive<Subject> const &subject,bool &flag, int &counter)
            {
                return subject.subject.iter.register_successful_parse(flag,counter);
            }
        };
        // Variant visitor class which handles dispatching the parsing to the selected parser
        // This also handles passing the correct attributes and flags/counters to the subject parsers       
 
        template < typename Elements, typename Iterator ,typename Context ,typename Skipper
                  ,typename Flags ,typename Counters ,typename Attribute, typename NoCasePass>
        class parse_dispatcher
            : public boost::static_visitor<bool>
        {
            typedef typename add_reference<Attribute>::type attr_reference; 
            
            public:
            parse_dispatcher(const Elements &elements,Iterator& first, Iterator const& last
          , Context& context, Skipper const& skipper
          , Flags &flags, Counters &counters, attr_reference attr) : 
                 elements(elements), first(first), last(last)
               , context(context), skipper(skipper)
               , flags(flags),counters(counters), attr(attr)
            {}
            
            template<typename T> bool operator()(T& idx) const
            {    
                return call(idx,typename traits::not_is_unused<Attribute>::type());
            }
            
            template <typename Subject,typename Index> 
            bool call_subject_unused(
                  Subject const &subject, Iterator &first, Iterator const &last
                , Context& context, Skipper const& skipper
                , Index& idx ) const
            {
                Iterator save = first;
                skipper_keyword_marker<Skipper,NoCasePass> marked_skipper(skipper,flags[Index::value],counters[Index::value]);
                
                if(subject.parse(first,last,context,marked_skipper,unused))
                {
                        return true;
                }
                save = save;
                return false;
            }            
 
            
            template <typename Subject,typename Index> 
            bool call_subject(
                  Subject const &subject, Iterator &first, Iterator const &last
                , Context& context, Skipper const& skipper
                , Index& idx ) const
            {
               
                Iterator save = first;
                skipper_keyword_marker<Skipper,NoCasePass> marked_skipper(skipper,flags[Index::value],counters[Index::value]);
                if(subject.parse(first,last,context,marked_skipper,fusion::at_c<Index::value>(attr)))
                {
                        return true;
                }
                save = save;
                return false;
            }

            // Handle unused attributes
            template <typename T> bool call(T &idx, mpl::false_) const{                            
                return call_subject_unused(fusion::at_c<T::value>(elements), first, last, context, skipper, idx );
            }
            // Handle normal attributes
            template <typename T> bool call(T &idx, mpl::true_) const{
                return call_subject(fusion::at_c<T::value>(elements), first, last, context, skipper, idx);
            }
            
            const Elements &elements;
            Iterator &first;
            const Iterator &last;
            Context & context;
            const Skipper &skipper;
            Flags &flags;
            Counters &counters;
            attr_reference attr;
        };
      
}}}}}

#endif
