/*=============================================================================
    Copyright (c) 2002-2003 Joel de Guzman
    Copyright (c) 2002-2003 Martin Wille
    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)
=============================================================================*/
#ifndef BOOST_SPIRIT_WHILE_HPP
#define BOOST_SPIRIT_WHILE_HPP

#include <boost/spirit/core/parser.hpp>
#include <boost/spirit/core/composite/composite.hpp>
#include <boost/spirit/dynamic/impl/conditions.ipp>

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

    namespace impl {

    //////////////////////////////////
    // while parser
    // object are created by while_parser_gen and do_parser_gen
    template <typename ParsableT, typename CondT, bool is_do_parser>
    struct while_parser
        : public condition_evaluator< typename as_parser<CondT>::type >
        , public unary // the parent stores a copy of the body parser
        <
            typename as_parser<ParsableT>::type,
            parser<while_parser<ParsableT, CondT, is_do_parser> >
        >
    {
        typedef while_parser<ParsableT, CondT, is_do_parser> self_t;

        typedef as_parser<ParsableT>            as_parser_t;
        typedef typename as_parser_t::type      parser_t;
        typedef as_parser<CondT>                cond_as_parser_t;
        typedef typename cond_as_parser_t::type condition_t;

        typedef unary<parser_t, parser<self_t> > base_t;
        typedef condition_evaluator<condition_t> eval_t;


        //////////////////////////////
        // constructor, saves condition and body parser
        while_parser(ParsableT const &body, CondT const &cond)
            : eval_t(cond_as_parser_t::convert(cond))
            , base_t(as_parser_t::convert(body))
        {}

        //////////////////////////////
        // result type computer.
        template <typename ScannerT>
        struct result
        {
            typedef typename match_result
                <ScannerT, nil_t>::type type;
        };

        //////////////////////////////
        // parse member function
        template <typename ScannerT>
        typename parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename parser_result<parser_t, ScannerT>::type sresult_t;
            typedef typename ScannerT::iterator_t                    iterator_t;

            iterator_t save(scan.first);
            std::size_t length = 0;
            int eval_length = 0;

            bool dont_check_condition = is_do_parser;

            while (dont_check_condition || (eval_length=this->evaluate(scan))>=0)
            {
                dont_check_condition = false;
                length += eval_length;
                sresult_t tmp(this->subject().parse(scan));
                if (tmp)
                {
                    length+=tmp.length();
                }
                else
                {
                    return scan.no_match();
                }
            }
            return scan.create_match(length, nil_t(), save, scan.first);
        }
    };

    //////////////////////////////////
    // while-parser generator, takes the body-parser in brackets
    // and returns the actual while-parser.
    template <typename CondT>
    struct while_parser_gen
    {
        //////////////////////////////
        // constructor, saves the condition for use by operator[]
        while_parser_gen(CondT const& cond_) : cond(cond_) {}

        //////////////////////////////
        // operator[] returns the actual while-parser object
        template <typename ParsableT>
        while_parser<ParsableT, CondT, false>
        operator[](ParsableT const &subject) const
        {
            return while_parser<ParsableT, CondT, false>(subject, cond);
        }
    private:

        //////////////////////////////
        // the condition is stored by reference here.
        // this should not cause any harm since object of type
        // while_parser_gen<> are only used as temporaries
        // the while-parser object constructed by the operator[]
        // stores a copy of the condition.
        CondT const &cond;
    };

    //////////////////////////////////
    // do-while-parser generator, takes the condition as
    // parameter to while_p member function and returns the
    // actual do-while-parser.
    template <typename ParsableT>
    struct do_while_parser_gen
    {
        //////////////////////////////
        // constructor. saves the body parser for use by while_p.
        explicit do_while_parser_gen(ParsableT const &body_parser)
            : body(body_parser)
        {}

        //////////////////////////////
        // while_p returns the actual while-parser object
        template <typename CondT>
        while_parser<ParsableT, CondT, true>
        while_p(CondT cond) const
        {
            return while_parser<ParsableT, CondT, true>(body, cond);
        }
    private:

        //////////////////////////////
        // the body is stored by reference here
        // this should not cause any harm since object of type
        // do_while_parser_gen<> are only used as temporaries
        // the while-parser object constructed by the while_p
        // member function stores a copy of the body parser.
        ParsableT const &body;
    };

    struct do_parser_gen
    {
        inline do_parser_gen() {}

        template <typename ParsableT>
        impl::do_while_parser_gen<ParsableT>
        operator[](ParsableT const& body) const
        {
            return impl::do_while_parser_gen<ParsableT>(body);
        }
    };
} // namespace impl

//////////////////////////////////
// while_p function, while-parser generator
// Usage: spirit::while_p(Condition)[Body]
template <typename CondT>
impl::while_parser_gen<CondT>
while_p(CondT const& cond)
{
    return impl::while_parser_gen<CondT>(cond);
}

//////////////////////////////////
// do_p functor, do-while-parser generator
// Usage: spirit::do_p[Body].while_p(Condition)
impl::do_parser_gen const do_p = impl::do_parser_gen();

}} // namespace boost::spirit

#endif // BOOST_SPIRIT_WHILE_HPP
