/*=============================================================================
    Copyright (c) 1998-2003 Joel de Guzman
    http://spirit.sourceforge.net/

    Use, modification and distribution is subject to 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_SKIPPER_IPP)
#define BOOST_SPIRIT_SKIPPER_IPP

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

    struct space_parser;
    template <typename BaseT>
    struct no_skipper_iteration_policy;

    namespace impl
    {
        template <typename ST, typename ScannerT, typename BaseT>
        inline void
        skipper_skip(
            ST const& s,
            ScannerT const& scan,
            skipper_iteration_policy<BaseT> const&)
        {
            typedef scanner_policies<
                no_skipper_iteration_policy<
                    BOOST_DEDUCED_TYPENAME ScannerT::iteration_policy_t>,
                BOOST_DEDUCED_TYPENAME ScannerT::match_policy_t,
                BOOST_DEDUCED_TYPENAME ScannerT::action_policy_t
            > policies_t;

            scanner<BOOST_DEDUCED_TYPENAME ScannerT::iterator_t, policies_t>
                scan2(scan.first, scan.last, policies_t(scan));
            typedef typename ScannerT::iterator_t iterator_t;

            for (;;)
            {
                iterator_t save = scan.first;
                if (!s.parse(scan2))
                {
                    scan.first = save;
                    break;
                }
            }
        }

        template <typename ST, typename ScannerT, typename BaseT>
        inline void
        skipper_skip(
            ST const& s,
            ScannerT const& scan,
            no_skipper_iteration_policy<BaseT> const&)
        {
            for (;;)
            {
                typedef typename ScannerT::iterator_t iterator_t;
                iterator_t save = scan.first;
                if (!s.parse(scan))
                {
                    scan.first = save;
                    break;
                }
            }
        }

        template <typename ST, typename ScannerT>
        inline void
        skipper_skip(
            ST const& s,
            ScannerT const& scan,
            iteration_policy const&)
        {
            for (;;)
            {
                typedef typename ScannerT::iterator_t iterator_t;
                iterator_t save = scan.first;
                if (!s.parse(scan))
                {
                    scan.first = save;
                    break;
                }
            }
        }

        template <typename SkipT>
        struct phrase_parser
        {
            template <typename IteratorT, typename ParserT>
            static parse_info<IteratorT>
            parse(
                IteratorT const&    first_,
                IteratorT const&    last,
                ParserT const&      p,
                SkipT const&        skip)
            {
                typedef skip_parser_iteration_policy<SkipT> iter_policy_t;
                typedef scanner_policies<iter_policy_t> scanner_policies_t;
                typedef scanner<IteratorT, scanner_policies_t> scanner_t;

                iter_policy_t iter_policy(skip);
                scanner_policies_t policies(iter_policy);
                IteratorT first = first_;
                scanner_t scan(first, last, policies);
                match<nil_t> hit = p.parse(scan);
                scan.skip(scan);
                return parse_info<IteratorT>(
                    first, hit, hit && (first == last),
                    hit.length());
            }
        };

        template <>
        struct phrase_parser<space_parser>
        {
            template <typename IteratorT, typename ParserT>
            static parse_info<IteratorT>
            parse(
                IteratorT const&    first_,
                IteratorT const&    last,
                ParserT const&      p,
                space_parser const&)
            {
                typedef skipper_iteration_policy<> iter_policy_t;
                typedef scanner_policies<iter_policy_t> scanner_policies_t;
                typedef scanner<IteratorT, scanner_policies_t> scanner_t;

                IteratorT first = first_;
                scanner_t scan(first, last);
                match<nil_t> hit = p.parse(scan);
                scan.skip(scan);
                return parse_info<IteratorT>(
                    first, hit, hit && (first == last),
                    hit.length());
            }
        };
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  Free parse functions using the skippers
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename IteratorT, typename ParserT, typename SkipT>
    inline parse_info<IteratorT>
    parse(
        IteratorT const&        first,
        IteratorT const&        last,
        parser<ParserT> const&  p,
        parser<SkipT> const&    skip)
    {
        return impl::phrase_parser<SkipT>::
            parse(first, last, p.derived(), skip.derived());
    }
    
    ///////////////////////////////////////////////////////////////////////////
    //
    //  Parse function for null terminated strings using the skippers
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename CharT, typename ParserT, typename SkipT>
    inline parse_info<CharT const*>
    parse(
        CharT const*            str,
        parser<ParserT> const&  p,
        parser<SkipT> const&    skip)
    {
        CharT const* last = str;
        while (*last)
            last++;
        return parse(str, last, p, skip);
    }

}} // namespace boost::spirit

#endif

