import os
import codecs
from collections import namedtuple
from posixpath import normpath

try:
    from urllib.request import urlopen
    from urllib.parse import quote
    unicode = str
except:
    from urllib import urlopen
    from urllib import quote


__version__ = '0.3.2'

__all__ = ['URL', 'SplitResult', 'parse', 'extract', 'construct', 'normalize',
           'compare', 'normalize_host', 'normalize_path', 'normalize_query',
           'normalize_fragment', 'encode', 'unquote', 'split', 'split_netloc',
           'split_host']


PSL_URL = 'https://publicsuffix.org/list/effective_tld_names.dat'


def _get_public_suffix_list():
    """Return a set containing all Public Suffixes.

    If the env variable PUBLIC_SUFFIX_LIST does not point to a local copy of the
    public suffix list it is downloaded into memory each time urltools is
    imported.
    """
    local_psl = os.environ.get('PUBLIC_SUFFIX_LIST')
    if local_psl:
        with codecs.open(local_psl, 'r', 'utf-8') as f:
            psl_raw = f.readlines()
    else:
        psl_raw = unicode(urlopen(PSL_URL).read(), 'utf-8').split('\n')
    psl = set()
    for line in psl_raw:
        item = line.strip()
        if item != '' and not item.startswith('//'):
            psl.add(item)
    return psl

PSL = _get_public_suffix_list()
assert len(PSL) > 0, 'Public Suffix List is empty!'


SCHEMES = ['http', 'https', 'ftp', 'sftp', 'file', 'gopher', 'imap', 'mms',
           'news', 'nntp', 'telnet', 'prospero', 'rsync', 'rtsp', 'rtspu',
           'svn', 'git', 'ws', 'wss']
SCHEME_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
IP_CHARS = '0123456789.:'
DEFAULT_PORT = {
    'http': '80',
    'https': '443',
    'ws': '80',
    'wss': '443',
    'ftp': '21',
    'sftp': '22',
    'ldap': '389'
}
QUOTE_EXCEPTIONS = {
    'path': ' /?+#',
    'query': ' &=+#',
    'fragment': ' +#'
}


SplitResult = namedtuple('SplitResult', ['scheme', 'netloc', 'path', 'query',
                                         'fragment'])
URL = namedtuple('URL', ['scheme', 'username', 'password', 'subdomain',
                         'domain', 'tld', 'port', 'path', 'query', 'fragment',
                         'url'])


def normalize(url):
    """Normalize a URL.

    >>> normalize('hTtp://ExAMPLe.COM:80')
    'http://example.com/'
    """
    url = url.strip()
    if url == '':
        return ''
    parts = split(url)
    if parts.scheme:
        netloc = parts.netloc
        if parts.scheme in SCHEMES:
            path = normalize_path(parts.path)
        else:
            path = parts.path
    # url is relative, netloc (if present) is part of path
    else:
        netloc = parts.path
        path = ''
        if '/' in netloc:
            netloc, path_raw = netloc.split('/', 1)
            path = normalize_path('/' + path_raw)
    username, password, host, port = split_netloc(netloc)
    host = normalize_host(host)
    port = _normalize_port(parts.scheme, port)
    query = normalize_query(parts.query)
    fragment = normalize_fragment(parts.fragment)
    return construct(URL(parts.scheme, username, password, None, host, None,
                         port, path, query, fragment, None))


def compare(url1, url2):
    """Check if url1 and url2 are the same after normalizing both.

    >>> compare("http://examPLe.com:80/abc?x=&b=1", "http://eXAmple.com/abc?b=1")
    True
    """
    return normalize(url1) == normalize(url2)


def _idna_encode(x):
    return x.encode('idna').decode('utf-8')


def _encode_query(query):
    """Quote all values of a query string."""
    if query == '':
        return query
    query_args = []
    for query_kv in query.split('&'):
        k, v = query_kv.split('=')
        query_args.append(k + "=" + quote(v.encode('utf-8')))
    return '&'.join(query_args)


def encode(url):
    """Encode URL."""