import re, sys, os
try:
    from urllib.parse import unquote, unquote_plus
except ImportError:
    from urlparse import unquote
    from urllib import unquote_plus
import json
from hashlib import md5
import random

####################################################################################
# Utitlities
####################################################################################
REQUEST = re.compile ('([^ ]+) ([^ ]+)(( HTTP/([0-9.]+))$|$)')
CONNECTION = re.compile ('Connection: (.*)', re.IGNORECASE)

def crack_query (r):
    if type (r) is bytes:
        r = r.decode ("utf8")

    if not r: return {}
    if r[0]=='?': r=r[1:]
    arg={}
    q = [x.split('=', 1) for x in r.split('&')]

    for each in q:
        k = unquote_plus (each [0])
        try:
            t, k = k.split (":", 1)
        except ValueError:
            t = "str"

        v = unquote_plus (each [1])
        if len (each) == 2:
            if t == "str":
                pass
            elif t in ("i", "int"):
                v = int (v)
            elif t in ("n", "null"):
                v = None
            elif t in ("f", "float"):
                v = float (v)
            elif t in ("l", "list"):
                v = v.split (",")
            elif t in ("b", "bool"):
                v = v.lower () in ("1", "true", "yes")

        if k in arg:
            if type (arg [k]) is not type ([]):
                arg[k] = [arg[k]]
            arg[k].append (v)

        else:
            arg[k] = v

    return arg

def crack_request (r):
    m = REQUEST.match (r)
    if m.end() == len(r):
        uri=m.group(2)
        if m.group(3):
            version = m.group(5)
        else:
            version = None
        return m.group(1).lower(), uri, version
    else:
        return None, None, None

def join_headers (headers):
    r = []
    for i in range(len(headers)):
        if headers[i][0] in ' \t':
            r[-1] = r[-1] + headers[i][1:]
        else:
            r.append (headers[i])
    return r

def get_header (head_reg, lines, group=1):
    for line in lines:
        m = head_reg.match (line)
        if m and m.end() == len(line):
            return m.group (group)
    return ''

def get_header_match (head_reg, lines):
    for line in lines:
        m = head_reg.match (line)
        if m and m.end() == len(line):
            return m
    return ''

def get_extension (path):
    dirsep = path.rfind ('/')
    dotsep = path.rfind ('.')
    if dotsep > dirsep:
        return path[dotsep+1:]
    else:
        return ''

ALNUM = '0123456789abcdefghijklmnopqrstuvwxyz'
def md5uniqid (length = 13):
    global ALNUM
    _id = ''
    for i in range (0, length):
        _id += random.choice(ALNUM)
    return md5 (_id.encode ("utf8")).hexdigest ()[length:]

def parse_params (header_val):
    d = {}
    header_filed = ""
    last_key = None
    for each in header_val.split (";"):
        if last_key:
            d [last_key] += ";" + each
            if each [-1] == '"':
                last_key = None
            continue

        each = each.strip ()
        if not each: continue

        try:
            a, b = each.split ("=", 1)
        except ValueError:
            if header_filed:
                header_filed += ":" + each
            else:
                header_filed = each
            continue

        key = a.lower ()
        d [key] = b
        if len (b) >= 2 and  b [0] == '"' and b [-1] != '"':
            last_key = key

    return header_filed, d

def parse_range (rg, file_length):
    if rg.startswith ('bytes='):
        s, e = rg [6:].split ("-", 1)
    else:
        return 0, file_length - 1

    s = int (s)
    if e:
        e = int (e)
    else:
        e = min (s + 1048575, file_length - 1)
    assert e < file_length
    assert s <= e
    return s, e

def parse_multi_params (header_val):
    return dict ([parse_params (v) for v in header_val.split (",")])
