#!/usr/bin/env python
"""
    Taken from public domain.
    Author: Lucio <lucio@movilogic.com>
    License: "Use it freely, get rich, whatever."
    ref: Quixote-users list, 5/22/03
"""

__version__ = "0.4"

__all__ = ["QuizoteHTTPRequestHandler"]

import BaseHTTPServer
import getopt
import os
import sys
import urllib
import urlparse

from quixote import enable_ptl, Publisher
#from quixote.publish import SessionPublisher
#from quixote.session import SessionManager


class CGIParser:
    def __init__(self, req, outfile):
        self.outfile = outfile
        self.buffer = ""
        self.req = req
        
    def write(self, data):
        self.buffer += data
        has = data.find("\n")
        if has != -1:
            line, rest = self.buffer.split("\n")
            nline = line.replace("Status:", "HTTP/1.0")
            self.req.log_request(code=nline.split(" ")[1])
            self.outfile.write(nline)
            self.outfile.write("\n")
            self.outfile.write(rest)
            self.write = self.outfile.write
        

class QuixoteHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    root = '/'
    # Make rfile unbuffered -- we need to read one line and then pass
    # the rest to a subprocess, so we can't use buffered input.
    rbufsize = 0

    def __init__(self, request, client_address, server, publisher):
        self.publisher = publisher
        BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, request, client_address, server)

    def do_POST(self):
        self.run_quixote()
    
    def do_GET(self):
        self.run_quixote()

    def run_quixote(self):
        l = len(self.root)
        scheme, location, path, parameters, \
                query, fragment = urlparse.urlparse(self.path)
        # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
        # XXX Much of the following could be prepared ahead of time!
        env = {}
        env['SERVER_SOFTWARE'] = self.version_string()
        env['SERVER_NAME'] = self.server.server_name
        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
        env['SERVER_PROTOCOL'] = self.protocol_version
        env['SERVER_PORT'] = str(self.server.server_port)
        env['REQUEST_METHOD'] = self.command
        #uqrest = urllib.unquote(rest)
        env['PATH_INFO'] =  path
        #env['PATH_TRANSLATED'] = self.translate_path(uqrest)
        env['SCRIPT_NAME'] = path.split("/")[-1]
        if query:
            env['QUERY_STRING'] = query
        host = self.address_string()
        if host != self.client_address[0]:
            env['REMOTE_HOST'] = host
        env['REMOTE_ADDR'] = self.client_address[0]
        # XXX AUTH_TYPE
        # XXX REMOTE_USER
        # XXX REMOTE_IDENT

        if self.headers.typeheader is None:
            env['CONTENT_TYPE'] = self.headers.type
        else:
            env['CONTENT_TYPE'] = self.headers.typeheader
        length = self.headers.getheader('content-length')
        if length:
            env['CONTENT_LENGTH'] = length
        accept = []
        for line in self.headers.getallmatchingheaders('accept'):
            if line[:1] in "\t\n\r ":
                accept.append(line.strip())
            else:
                accept = accept + line[7:].split(',')
        env['HTTP_ACCEPT'] = ','.join(accept)
        ua = self.headers.getheader('user-agent')
        if ua:
            env['HTTP_USER_AGENT'] = ua
        co = filter(None, self.headers.getheaders('cookie'))
        if co:
            env['HTTP_COOKIE'] = ', '.join(co)
        # XXX Other HTTP_* headers
        p = CGIParser(self, self.wfile)
        self.publisher.publish(self.rfile, p, p, env)
        

class QuixoteHTTPServer(BaseHTTPServer.HTTPServer):
    def __init__(self, saddr, handler, namespace, configfile = None):
        BaseHTTPServer.HTTPServer.__init__(self, saddr, handler)
        self.root_namespace = namespace
        enable_ptl()
        #from web.session import PlySession
        #smg = SessionManager(session_class=PlySession)
        #self.publisher=SessionPublisher(self.root_namespace,session_mgr=smg)
        #if conf:
        #    self.publisher.read_config(conf)
        self.publisher = Publisher(self.root_namespace)
        if configfile: self.publisher.read_config(configfile)
        self.publisher.setup_logs()

    def finish_request(self, request, client_address):
        """Finish one request by instantiating RequestHandlerClass.
           At this stage we have already created the new thread.
        """
        self.RequestHandlerClass(request, client_address, self, self.publisher)


def usage():
    print sys.argv[0],": [-f config_file] [-p port] namespace"
    print "Defaults: port = 8000, config_file = None"

def Run_Quixote():

    configfile = None
    port = 8000

    optlist, args = getopt.getopt(sys.argv[1:], "p:f:")
    if len(args) != 1:
        namespace = 'quixote.demo'
        
        # look for quixote/demo/demo.conf in sys.path entries
        for path in sys.path:
            test = os.path.join(path, 'quixote', 'demo', 'demo.conf')
            if os.path.exists(test):
                configfile = os.path.abspath(test)

        if not configfile:
            raise 'Could not find quixote/demo/demo.conf in sys.path: %s' \
                    % sys.path

    else:
        namespace = args[0]
        for key, val in optlist:
            if key == "-p":
                try:
                    port = int(val)
                except ValueError:
                    usage()
                    return
            elif key == "-f":
                configfile = val
            else:
                usage()
                return

        # If no config file specified, look for a file that ends in "conf" in
        # the namespace directory.  If there is only one, then use that.
        if not configfile:
            for path in sys.path:
                ns_path = [path]
                ns_path += namespace.split('.')
                ns_path = reduce(os.path.join, ns_path)
                print ns_path
                if os.path.exists(ns_path):
                    import glob
                    candidates = glob.glob(os.path.join(ns_path,'*.conf'))
                    if len(candidates) == 1: configfile = candidates[0]

    server_address = ('', port)

    print 'Using configuration file', configfile

    httpd = QuixoteHTTPServer(server_address, QuixoteHTTPRequestHandler,
            namespace, configfile)

    sa = httpd.socket.getsockname()
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
    httpd.serve_forever()

if __name__ == '__main__':
    Run_Quixote()

