""" Utility functions for dealing with URLs in pyramid """

import os
import warnings

from repoze.lru import lru_cache

from pyramid.interfaces import (
    IResourceURL,
    IRoutesMapper,
    IStaticURLInfo,
    )

from pyramid.compat import (
    bytes_,
    string_types,
    )
from pyramid.encode import (
    url_quote,
    urlencode,
)
from pyramid.path import caller_package
from pyramid.threadlocal import get_current_registry

from pyramid.traversal import (
    ResourceURL,
    quote_path_segment,
    )

PATH_SAFE = '/:@&+$,' # from webob
QUERY_SAFE = '/?:@!$&\'()*+,;=' # RFC 3986
ANCHOR_SAFE = QUERY_SAFE

def parse_url_overrides(kw):
    """Parse special arguments passed when generating urls.

    The supplied dictionary is mutated, popping arguments as necessary.
    Returns a 6-tuple of the format ``(app_url, scheme, host, port,
    qs, anchor)``.
    """
    anchor = ''
    qs = ''
    app_url = None
    host = None
    scheme = None
    port = None

    if '_query' in kw:
        query = kw.pop('_query')
        if isinstance(query, string_types):
            qs = '?' + url_quote(query, QUERY_SAFE)
        elif query:
            qs = '?' + urlencode(query, doseq=True)

    if '_anchor' in kw:
        anchor = kw.pop('_anchor')
        anchor = url_quote(anchor, ANCHOR_SAFE)
        anchor = '#' + anchor

    if '_app_url' in kw:
        app_url = kw.pop('_app_url')

    if '_host' in kw:
        host = kw.pop('_host')

    if '_scheme' in kw:
        scheme = kw.pop('_scheme')

    if '_port' in kw:
        port = kw.pop('_port')

    return app_url, scheme, host, port, qs, anchor

class URLMethodsMixin(object):
    """ Request methods mixin for BaseRequest having to do with URL
    generation """

    def _partial_application_url(self, scheme=None, host=None, port=None):
        """
        Construct the URL defined by request.application_url, replacing any
        of the default scheme, host, or port portions with user-supplied
        variants.

        If ``scheme`` is passed as ``https``, and the ``port`` is *not*
        passed, the ``port`` value is assumed to ``443``.  Likewise, if
        ``scheme`` is passed as ``http`` and ``port`` is not passed, the
        ``port`` value is assumed to be ``80``.
        """
        e = self.environ
        if scheme is None:
            scheme = e['wsgi.url_scheme']
        else:
            if scheme == 'https':
                if port is None:
                    port = '443'
            if scheme == 'http':
                if port is None:
                    port = '80'
        url = scheme + '://'
        if port is not None:
            port = str(port)
        if host is None:
            host = e.get('HTTP_HOST')
        if host is None: