#!/usr/bin/python

# Copyright (C) 2004-2016 CS-SI. All Rights Reserved.
# Author: Nicolas Delon <nicolas.delon@prelude-ids.com>
#
# This file is part of the Prewikka program.
#
# 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, 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.

import sys
import shutil
from optparse import OptionParser
import multiprocessing
import urllib, urlparse
import BaseHTTPServer

from prewikka.web import request
from prewikka import main, siteconfig, localization


class PrewikkaServer(BaseHTTPServer.HTTPServer):
    def __init__(self, *args, **kwargs):
        apply(BaseHTTPServer.HTTPServer.__init__, (self,) + args, kwargs)



class PrewikkaRequestHandler(request.Request, BaseHTTPServer.BaseHTTPRequestHandler):

    def init(self, method):
        request.Request.init(self, self.server.core)

        self._method = method

        if self.headers.get("x-requested-with", "") == "XMLHttpRequest":
            self.is_xhr = True

        if self.headers.get("accept", "") == "text/event-stream":
            self.is_stream = True

    def getCookieString(self):
        return self.headers.get("Cookie")

    def getQueryString(self):
        return self._query_string

    def getReferer(self):
        try:
            return self.input_headers["referer"]
        except KeyError:
            return ""

    def write(self, data):
        self.wfile.write(data)

    def read(self, *args, **kwargs):
        return apply(self.rfile.read, args, kwargs)

    def log_request(self, code):
        pass

    def _processDynamic(self, arguments):
        for name, value in arguments.items():
            self.arguments[name] = (len(value) == 1) and value[0] or value

        self.server.core.process(self)

    def sendHeaders(self, code=200, status_text=None):
        self.send_response(code)
        request.Request.sendHeaders(self)

    def getMethod(self):
        return self._method

    def do_GET(self):

        uri = urlparse.urlparse(self.path)
        self.path = urllib.url2pathname(uri.path)
        self._query_string = uri.query

        self.init("GET")

        path = self.resolveStaticPath(self.path)
        if path:
           return self.processStatic(path, lambda fd: shutil.copyfileobj(fd, self.wfile))

        self._processDynamic(urlparse.parse_qs(uri.query))

    def do_HEAD(self):
        self.do_GET()

    def do_POST(self):
        uri = urlparse.urlparse(self.path)
        self.path = urllib.url2pathname(uri.path)

        self.init("POST")

        if self.headers.get("content-type", "").startswith("multipart/form-data"):
            self._query_string = ""
            arguments = self.handleMultipart(fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD': 'POST'})
        else:
            qs = self.rfile.read(int(self.headers["Content-Length"]))
            if uri.query:
                qs = "&".join((uri.query, qs))

            self._query_string = qs
            arguments = urlparse.parse_qs(qs)

        self._processDynamic(arguments)

    def getClientAddr(self):
        return self.client_address[0]

    def getClientPort(self):
        return self.client_address[1]

    def getHeader(self, name):
        return self.headers[name]


def serve_forever(server, config_file):
    server.core = main.get_core_from_config(config_file)

    try:
        server.serve_forever()
    except KeyboardInterrupt:
        pass

if __name__ == "__main__":
    parser = OptionParser(epilog=" ")

    parser.add_option("-a", "--address", action="store", type="string", dest="addr", default="0.0.0.0", help="IP to bind to (default: %default)")
    parser.add_option("-p", "--port", action="store", type="int", dest="port", default=8000, help="port number to use (default: %default)")
    parser.add_option("-c", "--config", action="store", type="string", dest="config", default="%s/prewikka.conf" % siteconfig.conf_dir, help="configuration file to use (default: %default)")
    parser.add_option("-m", "--multiprocess", action="store", type="int", dest="num_process", default=multiprocessing.cpu_count(),
                      help="number of processes to use. Default value matches the number of available CPUs (i.e. %d)" % multiprocessing.cpu_count())

    (options, args) = parser.parse_args()

    server = PrewikkaServer((options.addr, options.port), PrewikkaRequestHandler)
    for i in range(options.num_process - 1):
        multiprocessing.Process(target=serve_forever, args=(server, options.config)).start()

    serve_forever(server, options.config)
