from tornado.httpclient import AsyncHTTPClient, main
from tornado.ioloop import IOLoop
from tornado.iostream import SSLIOStream
from tornado.netutil import ssl_options_to_context
from tornado.simple_httpclient import SimpleAsyncHTTPClient, _HTTPConnection

from tornado_http2.connection import Connection, Params
from tornado_http2 import constants

try:
    import urllib.parse as urlparse
except ImportError:
    import urlparse

try:
    from io import BytesIO
except ImportError:
    from cStringIO import StringIO as BytesIO


class Client(SimpleAsyncHTTPClient):
    def _connection_class(self):
        return _HTTP2ClientConnection

    def _use_http2_cleartext(self):
        return False


class _HTTP2ClientConnection(_HTTPConnection):
    def _get_ssl_options(self, scheme):
        options = super(_HTTP2ClientConnection, self)._get_ssl_options(scheme)
        if options is not None:
            if isinstance(options, dict):
                options = ssl_options_to_context(options)
            options.set_alpn_protocols([constants.HTTP2_TLS])
        return options

    def _create_connection(self, stream):
        can_http2 = False
        if isinstance(stream, SSLIOStream):
            assert stream.socket.cipher() is not None, 'handshake incomplete'
            proto = stream.socket.selected_alpn_protocol()
            if proto == constants.HTTP2_TLS:
                can_http2 = True
        elif self.client._use_http2_cleartext():
            can_http2 = True
        if can_http2:
            conn = Connection(stream, True,
                              Params(decompress=self.request.decompress_response))
            IOLoop.current().add_future(conn.start(None),
                                        lambda f: f.result())
            h2_stream = conn.create_stream(self)
            return h2_stream
        return super(_HTTP2ClientConnection, self)._create_connection(stream)


class ForceHTTP2Client(Client):
    def _use_http2_cleartext(self):
        return True


if __name__ == '__main__':
    AsyncHTTPClient.configure(Client)
    main()