#!/usr/bin/env python
# encoding: utf-8
import logging, urlparse

class Server(object):
    def __init__(self):
        self.dfuncs = dict()
        self.modules = dict()
    def serve(self, req):
        result = -1
        req_path = urlparse.urlsplit(req)[2]
        if req_path in self.dfuncs: dfunc = self.dfuncs[req_path] # in cache
        else: dfunc = self.load(req_path)  # handler function not in cache
        if dfunc: result = dfunc(req)
        return(result)
    def load(self, req_path):
        logging.debug("load() called for '%s'" % req_path)
        m = dfunc = None
        mpath = 'modules.%s' % '.'.join(filter(None, req_path.split('/')[:-1]))
        # already have the module needed?
        if mpath in self.modules: m = self.modules[mpath] # yes!
        else:   # no, try import
            try: m = __import__(mpath, globals(), locals(), ['ReqH'])
            except ImportError, e: logging.error(str(e))
            else: self.modules[m.__name__] = m  # cache it
        if m:
            # got the module, does it have a 'ReqH' class?
            if hasattr(m, 'ReqH'):
                # yes, does the 'ReqH' class have a dispatch function?
                if hasattr(m.ReqH, 'dispatch') and callable(m.ReqH.dispatch):
                    self.dfuncs[req_path] = dfunc = m.ReqH.dispatch
                else: logging.error("no dispatch function in '%s'" % mpath)
            else: logging.error("no request handler class in '%s'" % mpath)
        return dfunc
if __name__ == '__main__':
    logf = logging.Formatter('** %(asctime)s %(levelname)s - %(message)s')
    lcon = logging.StreamHandler()
    lcon.setFormatter(logf)
    logging.getLogger('').addHandler(lcon)
    logging.getLogger('').setLevel(logging.INFO)
    logging.info('starting server..')
    server = Server()
    while 1:
        req = raw_input("!! please type in a req in HTTP-GET format " \
                        "(or 'q' to quit)\n>>> ")
        if req == 'q': break
        result = server.serve(req)
        if result == 0: logging.info('S: %s' % req)
        else: logging.info('F: %s' % req)
    logging.info('server terminated')
