/*=============================================================================
    Copyright (c) 2001-2014 Joel de Guzman
    Copyright (c) 2011 Jan Frederick Eick

    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_X3_EXTRACT_INT_APRIL_17_2006_0830AM)
#define BOOST_SPIRIT_X3_EXTRACT_INT_APRIL_17_2006_0830AM

#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/numeric_utils/detail/extract_int.hpp>
#include <boost/assert.hpp>

namespace boost {
namespace spirit {
namespace x3 {
///////////////////////////////////////////////////////////////////////////
//  Extract the prefix sign (- or +), return true if a '-' was found
///////////////////////////////////////////////////////////////////////////
template <typename Iterator>
inline bool
extract_sign(Iterator& first, Iterator const& last)
{
    (void)last;                  // silence unused warnings
    BOOST_ASSERT(first != last); // precondition

    // Extract the sign
    bool neg = *first == '-';

    if (neg || (*first == '+'))
    {
        ++first;
        return neg;
    }

    return false;
}

///////////////////////////////////////////////////////////////////////////
// Low level unsigned integer parser
///////////////////////////////////////////////////////////////////////////
template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
          , bool Accumulate = false>
struct extract_uint
{
    // check template parameter 'Radix' for validity
    static_assert(
        (Radix >= 2 && Radix <= 36),
        "Error Unsupported Radix");

    template <typename Iterator>
    inline static bool
    call(Iterator& first, Iterator const& last, T& attr)
    {
        if (first == last)
        {
            return false;
        }

        typedef detail::extract_int<
        T
        , Radix
        , MinDigits
        , MaxDigits
        , detail::positive_accumulator<Radix>
        , Accumulate>
        extract_type;

        Iterator save = first;

        if (!extract_type::parse(first, last, attr))
        {
            first = save;
            return false;
        }

        return true;
    }

    template <typename Iterator, typename Attribute>
    inline static bool
    call(Iterator& first, Iterator const& last, Attribute& attr_)
    {
        // this case is called when Attribute is not T
        T attr;

        if (call(first, last, attr))
        {
            traits::move_to(attr, attr_);
            return true;
        }

        return false;
    }
};

///////////////////////////////////////////////////////////////////////////
// Low level signed integer parser
///////////////////////////////////////////////////////////////////////////
template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits>
struct extract_int
{
    // check template parameter 'Radix' for validity
    static_assert(
        (Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16),
        "Error Unsupported Radix");

    template <typename Iterator>
    inline static bool
    call(Iterator& first, Iterator const& last, T& attr)
    {
        if (first == last)
        {
            return false;
        }

        typedef detail::extract_int<
        T, Radix, MinDigits, MaxDigits>
        extract_pos_type;

        typedef detail::extract_int<
        T, Radix, MinDigits, MaxDigits, detail::negative_accumulator<Radix> >
        extract_neg_type;

        Iterator save = first;
        bool hit = extract_sign(first, last);

        if (hit)
        {
            hit = extract_neg_type::parse(first, last, attr);
        }

        else
        {
            hit = extract_pos_type::parse(first, last, attr);
        }

        if (!hit)
        {
            first = save;
            return false;
        }

        return true;
    }

    template <typename Iterator, typename Attribute>
    inline static bool
    call(Iterator& first, Iterator const& last, Attribute& attr_)
    {
        // this case is called when Attribute is not T
        T attr;

        if (call(first, last, attr))
        {
            traits::move_to(attr, attr_);
            return true;
        }

        return false;
    }
};
}
}
}

#endif
