import inspect

import requests

from .stream import Stream
from .wrappers import StreamIOWrapper
from ..exceptions import StreamError


def normalize_key(keyval):
    key, val = keyval
    key = hasattr(key, "decode") and key.decode("utf8", "ignore") or key

    return key, val


def valid_args(args):
    argspec = inspect.getargspec(requests.Request.__init__)

    return dict(filter(lambda kv: kv[0] in argspec.args, args.items()))


class HTTPStream(Stream):
    """A HTTP stream using the requests library.

    *Attributes:*

    - :attr:`url`  The URL to the stream, prepared by requests.
    - :attr:`args` A :class:`dict` containing keyword arguments passed
                   to :meth:`requests.request`, such as headers and
                   cookies.

    """

    __shortname__ = "http"

    def __init__(self, session, url, **args):
        Stream.__init__(self, session)

        self.args = dict(url=url, method=args.pop("method", "GET"),
                         **args)

    def __repr__(self):
        return "<HTTPStream({0!r})>".format(self.url)

    def __json__(self):
        req = requests.Request(**valid_args(self.args)).prepare()
        headers = dict(map(normalize_key, req.headers.items()))

        return dict(type=type(self).shortname(), url=req.url,
                    method=req.method, headers=headers,
                    body=req.body)

    @property
    def url(self):
        return requests.Request(**valid_args(self.args)).prepare().url

    def open(self):
        try:
            res = requests.request(stream=True, **self.args)
            res.raise_for_status()
        except (requests.exceptions.RequestException, IOError) as err:
            raise StreamError("Unable to open URL: {0} ({1})".format(self.url,
                                                                     err))

        return StreamIOWrapper(res.raw)


@@ -826,16 +826,17 @@
  session
+_
 , url, *
@@ -880,16 +880,17 @@
  session
+_
 )%0A%0A     
@@ -1136,32 +1136,280 @@
 args(self.args))
+%0A        session = self.args.get(%22session%22)%0A%0A        # prepare_request is only available in requests 2.0+%0A        if session and hasattr(session, %22prepare_request%22):%0A            req = session.prepare_request(req)%0A        else:%0A            req = req
 .prepare()%0A     
@@ -1403,16 +1403,17 @@
 epare()%0A
+%0A
         

Handle request sessions in __json__.