# -*- coding: iso-8859-1 -*-
# Copyright (C) 2004-2012 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Define http test support classes for LinkChecker tests.
"""

import SimpleHTTPServer
import BaseHTTPServer
import httplib
import time
import threading
from . import LinkCheckTest


class StoppableHttpRequestHandler (SimpleHTTPServer.SimpleHTTPRequestHandler, object):
    """
    HTTP request handler with QUIT stopping the server.
    """

    def do_QUIT (self):
        """
        Send 200 OK response, and set server.stop to True.
        """
        self.send_response(200)
        self.end_headers()
        self.server.stop = True

    def log_message (self, format, *args):
        """
        Logging is disabled.
        """
        pass

# serve .xhtml files as application/xhtml+xml
StoppableHttpRequestHandler.extensions_map.update({
        '.xhtml': 'application/xhtml+xml',
})


class StoppableHttpServer (BaseHTTPServer.HTTPServer, object):
    """
    HTTP server that reacts to self.stop flag.
    """

    def serve_forever (self):
        """
        Handle one request at a time until stopped.
        """
        self.stop = False
        while not self.stop:
            self.handle_request()


class NoQueryHttpRequestHandler (StoppableHttpRequestHandler):
    """
    Handler ignoring the query part of requests.
    """

    def remove_path_query (self):
        """
        Remove everything after a question mark.
        """
        i = self.path.find('?')
        if i != -1:
            self.path = self.path[:i]

    def do_GET (self):
        """
        Removes query part of GET request.
        """
        self.remove_path_query()
        super(NoQueryHttpRequestHandler, self).do_GET()

    def do_HEAD (self):
        """
        Removes query part of HEAD request.
        """
        self.remove_path_query()
        super(NoQueryHttpRequestHandler, self).do_HEAD()


class HttpServerTest (LinkCheckTest):
    """
    Start/stop an HTTP server that can be used for testing.
    """

    def __init__ (self, methodName='runTest'):
        """
        Init test class and store default http server port.
        """
        super(HttpServerTest, self).__init__(methodName=methodName)
        self.port = None

    def start_server (self, handler=NoQueryHttpRequestHandler):
        """Start a new HTTP server in a new thread."""
        self.port = start_server(handler)
        assert self.port is not None

    def stop_server (self):
        """Send QUIT request to http server."""
        stop_server(self.port)


def start_server (handler):
    """Start an HTTP server thread and return its port number."""
    server_address = ('localhost', 0)
    handler.protocol_version = "HTTP/1.0"
    httpd = StoppableHttpServer(server_address, handler)
    port = httpd.server_port
    t = threading.Thread(None, httpd.serve_forever)
    t.start()
    # wait for server to start up
    while True:
        try:
            conn = httplib.HTTPConnection("localhost:%d" % port)
            conn.request("GET", "/")
            conn.getresponse()
            break
        except:
            time.sleep(0.5)
    return port


def stop_server (port):
    """Stop an HTTP server thread."""
    conn = httplib.HTTPConnection("localhost:%d" % port)
    conn.request("QUIT", "/")
    conn.getresponse()


def get_cookie (maxage=2000):
    data = (
        ("Comment", "justatest"),
        ("Max-Age", "%d" % maxage),
        ("Path", "/"),
        ("Version", "1"),
        ("Foo", "Bar"),
    )
    return "; ".join('%s="%s"' % (key, value) for key, value in data)


class CookieRedirectHttpRequestHandler (NoQueryHttpRequestHandler):
    """Handler redirecting certain requests, and setting cookies."""

    def end_headers (self):
        """Send cookie before ending headers."""
        self.send_header("Set-Cookie", get_cookie())
        self.send_header("Set-Cookie", get_cookie(maxage=0))
        super(CookieRedirectHttpRequestHandler, self).end_headers()

    def redirect (self):
        """Redirect request."""
        path = self.path.replace("redirect", "newurl")
        self.send_response(302)
        self.send_header("Location", path)
        self.end_headers()

    def redirect_newhost (self):
        """Redirect request to a new host."""
        path = "http://www.example.com/"
        self.send_response(302)
        self.send_header("Location", path)
        self.end_headers()

    def redirect_newscheme (self):
        """Redirect request to a new scheme."""
        if "file" in self.path:
            path = "file:README"
        else:
            path = "ftp://example.com/"
        self.send_response(302)
        self.send_header("Location", path)
        self.end_headers()

    def do_GET (self):
        """Handle redirections for GET."""
        if "redirect_newscheme" in self.path:
            self.redirect_newscheme()
        elif "redirect_newhost" in self.path:
            self.redirect_newhost()
        elif "redirect" in self.path:
            self.redirect()
        else:
            super(CookieRedirectHttpRequestHandler, self).do_GET()

    def do_HEAD (self):
        """Handle redirections for HEAD."""
        if "redirect_newscheme" in self.path:
            self.redirect_newscheme()
        elif "redirect_newhost" in self.path:
            self.redirect_newhost()
        elif "redirect" in self.path:
            self.redirect()
        else:
            super(CookieRedirectHttpRequestHandler, self).do_HEAD()
