"""a WSGI application filter for CherryPy"""
__version__ = "0.3"
__license__ = "MIT"
__author__ = "Christian Wyglendowski <christian@dowski.com>"

import sys

import cherrypy
from cherrypy.filters.basefilter import BaseFilter
from cherrypy._cputil import get_object_trail

if 'debug' in sys.argv:
    from pprint import pprint

def start_response(status, response_headers, exc_info=None):
    cherrypy.response.status = status
    headers_dict = dict(response_headers)
    cherrypy.response.headers.update(headers_dict)

def get_path_components(path):
    """returns (script_name, path_info)

    determines what part of the path belongs to cp (script_name)
    and what part belongs to the wsgi application (path_info)
    """
    no_parts = ['']
    object_trail = get_object_trail(path)
    root = object_trail.pop(0)
    if not path.endswith('/index'):
        object_trail.pop()
    script_name_parts = [""]
    path_info_parts = [""]
    for (pc,obj) in object_trail:
        if obj:
            script_name_parts.append(pc)
        else:
            path_info_parts.append(pc)
    script_name = "/".join(script_name_parts)
    path_info = "/".join(path_info_parts)
    if len(script_name) > 1 and path.endswith('/'):
        path_info = path_info + '/'
    
    if script_name and not script_name.startswith('/'):
        script_name = '/' + script_name
    if path_info and not path_info.startswith('/'):
        path_info = '/' + path_info
    
    return script_name, path_info

def make_environ():
    """grabbed some of below from _cpwsgiserver.py"""

    script_name, path_info = get_path_components(cherrypy.request.path)
    
    # create and populate the wsgi environment
    environ = dict()
    environ["wsgi.version"] = (1,0)
    environ["wsgi.url_scheme"] = cherrypy.request.scheme
    environ["wsgi.input"] = cherrypy.request.rfile
    environ["wsgi.errors"] = sys.stderr
    environ["wsgi.multithread"] = True
    environ["wsgi.multiprocess"] = False
    environ["wsgi.run_once"] = False
    environ["REQUEST_METHOD"] = cherrypy.request.method
    environ["SCRIPT_NAME"] = script_name
    environ["PATH_INFO"] = path_info
    environ["QUERY_STRING"] = cherrypy.request.queryString
    environ["SERVER_PROTOCOL"] = cherrypy.request.version
    environ["SERVER_NAME"] = cherrypy.server.httpserver.server_name
    environ["SERVER_PORT"] = cherrypy.config.get('server.socketPort')
    environ["REMOTE_HOST"] = cherrypy.request.remoteHost
    environ["REMOTE_ADDR"] = cherrypy.request.remoteAddr
    environ["REMOTE_PORT"] = cherrypy.request.remotePort
    # then all the http headers
    headers = cherrypy.request.headers
    environ["CONTENT_TYPE"] = headers.get("Content-type", "")
    environ["CONTENT_LENGTH"] = headers.get("Content-length", "")
    for (k, v) in headers.iteritems():
        envname = "HTTP_" + k.upper().replace("-","_")
        environ[envname] = v
    return environ

class WSGIAppFilter(BaseFilter):
    def __init__(self, wsgi_app):
        self.app = wsgi_app
   
    def before_request_body(self):
        cherrypy.request.processRequestBody = False

    def before_main(self):
        """run the wsgi_app and set response.body to its output
        """
        try:
            environ = cherrypy.request.wsgi_environ
            sn, pi = get_path_components(cherrypy.request.path)
            environ['SCRIPT_NAME'] = sn
            environ['PATH_INFO'] = pi
        except AttributeError:
            environ = make_environ()

        
        cherrypy.response.body = self.app(environ, start_response)
        cherrypy.request.execute_main = False
        if 'debug' in sys.argv:
            pprint(environ)


class WSGIApp(object):
    """a convenience class used to easily mount a wsgi app.

    example:
    cherrypy.root = SomeRoot()
    cherrypy.root.otherapp = WSGIApp(other_wsgi_app)
    """
    def __init__(self, app):
        self._cpFilterList = [WSGIAppFilter(app)]


if __name__ == '__main__':

    def my_app(environ, start_reponse):
        status = '200 OK'
        response_headers = [('Content-type', 'text/plain')]
        start_response(status, response_headers)
        yield 'Hello, world!\n'
        for (k,v) in environ.iteritems():
            yield '%s: %s\n' % (k,v)

    class Root(object):
        @cherrypy.expose
        def index(self):
            yield "<h1>Hi, from CherryPy!</h1>"
            yield "<a href='app'>A non-CP WSGI app</a><br>"

    # mount standard CherryPy app
    cherrypy.root = Root()
    # mount the WSGI app
    cherrypy.root.app = WSGIApp(my_app)


    cherrypy.server.start()
        

