##!/usr/bin/env python

import socket
import sys
import time
import unittest

import framework

import thor
from thor.events import on
from thor.http import HttpServer


class TestHttpServer(framework.ClientServerTestCase):
    def create_server(self, server_side):
        test_port = self.get_port()
        server = HttpServer(framework.test_host, test_port, loop=self.loop)
        server_side(server)

        def stop():
            server.shutdown()

        return (stop, test_port)

    def create_client(self, test_host, test_port, client_side):
        def run_client(client_side1):
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client.connect((test_host, test_port))
            client_side1(client, test_host, test_port)
            client.close()

        self.move_to_thread(target=run_client, args=(client_side,))

    def check_exchange(self, exchange, expected):
        """
        Given an exchange, check that the status, phrase and body are as
        expected, and verify that it actually happened.
        """
        exchange.test_happened = False

        @on(exchange)
        def error(err_msg):
            exchange.test_happened = True
            self.assertEqual(err_msg, expected.get("error", err_msg))
            self.loop.stop()

        @on(exchange)
        def request_start(method, uri, headers):
            self.assertEqual(method, expected.get("method", method))
            self.assertEqual(uri, expected.get("phrase", uri))

        exchange.tmp_req_body = b""

        @on(exchange)
        def request_body(chunk):
            exchange.tmp_req_body += chunk

        @on(exchange)
        def request_done(trailers):
            exchange.test_happened = True
            self.assertEqual(trailers, expected.get("req_trailers", trailers))
            self.assertEqual(
                exchange.tmp_req_body, expected.get("body", exchange.tmp_req_body)
            )
            self.loop.stop()

        @on(self.loop)
        def stop():
            self.assertTrue(exchange.test_happened)

    def test_basic(self):
        def server_side(server):
            def check(exchange):
                self.check_exchange(exchange, {"method": b"GET", "uri": b"/"})

            server.on("exchange", check)

        def client_side(client_conn, test_host, test_port):
            client_conn.sendall(
                b"""\
GET / HTTP/1.1
Host: %s:%i

"""
                % (test_host, test_port)
            )
            time.sleep(1)
            client_conn.close()

        self.go([server_side], [client_side])

    def test_extraline(self):
        def server_side(server):
            def check(exchange):
                self.check_exchange(exchange, {"method": b"GET", "uri": b"/"})

            server.on("exchange", check)

        def client_side(client_conn, test_host, test_port):
            client_conn.sendall(
                b"""\

GET / HTTP/1.1
Host: %s:%i\r
\r
"""
                % (test_host, test_port)
            )
            time.sleep(1)
            client_conn.close()

        self.go([server_side], [client_side])

    def test_post(self):
        def server_side(server):
            def check(exchange):
                self.check_exchange(exchange, {"method": b"POST", "uri": b"/foo"})

            server.on("exchange", check)

        def client_side(client_conn, test_host, test_port):
            client_conn.sendall(
                b"""\
POST / HTTP/1.1
Host: %s:%i
Content-Type: text/plain
Content-Length: 5

12345"""
                % (test_host, test_port)
            )
            time.sleep(1)
            client_conn.close()

        self.go([server_side], [client_side])

    def test_post_extra_crlf(self):
        def server_side(server):
            def check(exchange):
                self.check_exchange(exchange, {"method": b"POST", "uri": b"/foo"})

            server.on("exchange", check)

        def client_side(client_conn, test_host, test_port):
            client_conn.sendall(
                b"""\
POST / HTTP/1.1
Host: %s:%i
Content-Type: text/plain
Content-Length: 5

12345
"""
                % (test_host, test_port)
            )
            time.sleep(1)
            client_conn.close()

        self.go([server_side], [client_side])


#    def test_pipeline(self):
#        def server_side(server):
#            server.ex_count = 0
#            def check(exchange):
#                self.check_exchange(exchange, {
#                    'method': 'GET',
#                    'uri': '/'
#                })
#                server.ex_count += 1
#            server.on('exchange', check)
#            @on(self.loop)
#            def stop():
#                self.assertEqual(server.ex_count, 2)
#
#        def client_side(client_conn, test_host, test_port):
#            client_conn.sendall("""\
# GET / HTTP/1.1
# Host: %s:%i
#
# GET / HTTP/1.1
# Host: %s:%i
#
# """ % (
#    test_host, test_port,
#    test_host, test_port
# ))
#            time.sleep(1)
#            client_conn.close()
#        self.go([server_side], [client_side])


#    def test_conn_close(self):
#    def test_req_nobody(self):
#    def test_res_nobody(self):
#    def test_bad_http_version(self):
#    def test_pause(self):
#    def test_extra_crlf_after_post(self):
#    def test_absolute_uri(self): # ignore host header
#    def test_host_header(self):#
#    def test_unknown_transfercode(self): # should be 501
#    def test_shutdown(self):
#    def test_alternate_tcp_server(self):
#    def test_startline_encoding(self):


if __name__ == "__main__":
    unittest.main()
