//            Copyright (c) Glyn Matthews 2011.
// 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)


#ifndef __BOOST_NETWORK_URI_URI_ACCESSORS_INC__
# define __BOOST_NETWORK_URI_URI_ACCESSORS_INC__


# include <boost/network/uri/uri.hpp>
# include <boost/network/uri/encode.hpp>
# include <boost/network/uri/decode.hpp>
# include <boost/spirit/include/qi.hpp>
# include <boost/fusion/include/std_pair.hpp>


namespace boost {
namespace network {
namespace uri {
namespace details {
template <
    typename Map
    >
struct key_value_sequence
    : spirit::qi::grammar<uri::const_iterator, Map()>
{
    typedef typename Map::key_type key_type;
    typedef typename Map::mapped_type mapped_type;
    typedef std::pair<key_type, mapped_type> pair_type;

    key_value_sequence()
        : key_value_sequence::base_type(query)
    {
        query =  pair >> *((spirit::qi::lit(';') | '&') >> pair);
        pair  =  key >> -('=' >> value);
        key   =  spirit::qi::char_("a-zA-Z_") >> *spirit::qi::char_("-+.~a-zA-Z_0-9/%");
        value = +spirit::qi::char_("-+.~a-zA-Z_0-9/%");
    }

    spirit::qi::rule<uri::const_iterator, Map()> query;
    spirit::qi::rule<uri::const_iterator, pair_type()> pair;
    spirit::qi::rule<uri::const_iterator, key_type()> key;
    spirit::qi::rule<uri::const_iterator, mapped_type()> value;
};
} // namespace details

template <
    class Map
    >
inline
Map &query_map(const uri &uri_, Map &map) {
    const uri::string_type range = uri_.query();
    details::key_value_sequence<Map> parser;
    spirit::qi::parse(boost::begin(range), boost::end(range), parser, map);
    return map;
}

inline
uri::string_type username(const uri &uri_) {
    const uri::string_type user_info = uri_.user_info();
    uri::const_iterator it(boost::begin(user_info)), end(boost::end(user_info));
    for (; it != end; ++it) {
        if (*it == ':') {
            break;
        }
    }
    return uri::string_type(boost::begin(user_info), it);
}

inline
uri::string_type password(const uri &uri_) {
    const uri::string_type user_info = uri_.user_info();
    uri::const_iterator it(boost::begin(user_info)), end(boost::end(user_info));
    for (; it != end; ++it) {
        if (*it == ':') {
            ++it;
            break;
        }
    }
    return uri::string_type(it, boost::end(user_info));
}

inline
uri::string_type decoded_path(const uri &uri_) {
    const uri::string_type path = uri_.path();
    uri::string_type decoded_path;
    decode(path, std::back_inserter(decoded_path));
    return decoded_path;
}

inline
uri::string_type decoded_query(const uri &uri_) {
    const uri::string_type query = uri_.query();
    uri::string_type decoded_query;
    decode(query, std::back_inserter(decoded_query));
    return decoded_query;
}

inline
uri::string_type decoded_fragment(const uri &uri_) {
    const uri::string_type fragment = uri_.fragment();
    uri::string_type decoded_fragment;
    decode(fragment, std::back_inserter(decoded_fragment));
    return decoded_fragment;
}
} // namespace uri
} // namespace network
} // namespace boost


#endif // __BOOST_NETWORK_URI_URI_ACCESSORS_INC__
