import sys
import traceback
import string
import re
import copy

from flask import current_app

# We don't support python 2, but attempt to make it work.
if sys.version_info[0] < 3:
    from urlparse import urlparse,urlunparse
    print( "DANGER WILL ROBINSON: You are running python 2, which is unsupported. YMMV." )
else:
    from urllib.parse import urlparse,urlunparse
    from functools import reduce

#from threading import Thread
import threading
from io import StringIO
import logging
import requests
requests.adapters.DEFAULT_RETRIES = 20

from .errors import error, log_errors_without_request_context

fwding_log = logging.getLogger('Flask-HTTP-Forwarding.forwarding')

forwarding_timeout = 120
required_forwarding_headers = {
    'fixed': [
        "X-Forward-Id",
        "X-Forward-Referer",
        "X-Forward-Errors-To"
        ],
    'to-forward': [
        "X-Forward-To",
        "X-Forward-Query-Params",
        "X-Forward-Method"
        ]
    }

def headers(header_dict):
    default_headers = current_app.config.get('DEFAULT_HEADERS') or {}
    return dict(list(default_headers.items()) + list(header_dict.items()))

class Unforwardable(Exception): pass
class MissingHeaders(Exception): pass
class ResponseError(Exception): pass

def h_list(header):
    """ Convert a comma-separated HTTP header into a Python list. """
    if header.__class__ in (list, tuple):
        return list(header)

    obj = re.split(r",\s*", header)
    new_obj = []
    for item in obj:
        new_obj.append(str(item))
    return new_obj

def list_header(obj):
    """ Convert a Python list into a comma-separated HTTP header. """
    if obj.__class__ not in (list, tuple):
        return str(obj)

    new_obj = []
    for item in obj:
        new_obj.append(str(item))
    return ",".join(new_obj)

def encode_headers(out_headers):
    """ Convert a dictionary with Python lists into comma-separated HTTP header values. """
    headers = {}
    for header, value in out_headers.items():
        if value.__class__ in (list, tuple):
            headers[header] = list_header(value)
        else:
            headers[header] = value

        if len(headers[header]) is 0:
            del headers[header]
    return headers

def parse_headers(in_headers):
    missing_headers = []
    headers = {}
    for header in reduce( lambda a,b: a+b, required_forwarding_headers.values() ):
        if header in in_headers:
            headers[header] = h_list(in_headers[header])
        else:
            missing_headers.append(header)
    # no headers, so we assume it isn't forwardable
    if set(missing_headers)==set(required_forwarding_headers['to-forward']):
        raise Unforwardable()
    elif len(missing_headers) is 0:
        return headers
    else:
        raise MissingHeaders(missing_headers)

def concat_headers(old, new):
    retval = dict(old.items())
    for k in new.keys():