"""HTTP Server

This module contains a HTTP server
"""

import threading
import socket

from composer import ResponseComposer
from parser import RequestParser
import weblogging as logging
from config import config

class ConnectionHandler(threading.Thread):
    """Connection Handler for HTTP Server"""

    def __init__(self, conn_socket, addr, timeout):
        """Initialize the HTTP Connection Handler
        
        Args:
            conn_socket (socket): socket used for connection with client
            addr (str): ip address of client
            timeout (int): seconds until timeout
        """
        super(ConnectionHandler, self).__init__()
        self.daemon = True
        self.conn_socket = conn_socket
        self.addr = addr
        self.timeout = timeout
    
    def handle_connection(self):
        """Handle a new connection"""
        self.rp = RequestParser()
        self.rc = ResponseComposer(timeout=self.timeout)

        self.conn_socket.settimeout(self.timeout)

        # TODO: should not be persistent when client sends Connection: close
        # or can we safely assume that in this case the client will close the
        # transport channel, so that recv() returns something empty?
        try:
            while True:
                data = self.conn_socket.recv(4096)
                if len(data) == 0:
                    break
                self.handle_data(data)
        except socket.timeout:
            logging.debug('Connection to %s timed out.' % self.addr[0])
        finally:
            self.conn_socket.close()
            logging.debug('Connection to %s closed.' % self.addr[0])

    def handle_data(self, data):
        for req in self.rp.parse_requests(data):
            logging.info("<-- (%s) %s" % (self.addr[0], req.startline()))
            resp = self.rc.compose_response(req)
            logging.info("--> (%s) %s" % (self.addr[0], resp.startline()))
            self.send(resp)

    def send(self, data):
        sent = self.conn_socket.send(str(data))
        if sent == 0:
            raise RuntimeError('Socket broken')
        
    def run(self):
        """Run the thread of the connection handler"""
        try:
            self.handle_connection()
        except socket.error, e:
            logging.error('Error in handling connection with %s: %s' % 
                    (self.addr[0], str(e)))


class Server:
    """HTTP Server"""

    def __init__(self, configfile, **kwargs):
        """Initialize the HTTP server
        
        Args:
            hostname (str): hostname of the server
            server_port (int): port that the server is listening on
            timeout (int): seconds until timeout
        """
        self.read_config(configfile, **kwargs)
        self.done = False

    def read_config(self, configfile, **kwargs):
        config().read(configfile)
        
        if not config().has_section('webhttp'):
            config().add_section('webhttp')
        
        for name, val in kwargs.items():
            if val != None:
                config().set('webhttp', name, str(val))
    
    def run(self):
        """Run the HTTP Server and start listening"""
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.bind((config('hostname'), config('port', type=int)))
        self.socket.listen(config('max_connections', type=int))
        while not self.done:
            (csocket, addr) = self.socket.accept()
            ch = ConnectionHandler(csocket, addr, config('timeout', type=int))
            ch.start()
    
    def shutdown(self):
        """Safely shut down the HTTP server"""
        self.socket.shutdown(socket.SHUT_RDWR)
        self.socket.close()
        self.done = True