import SocketServer
import time

from Logging import *


class NetStringError(ValueError): pass

def NetStringDecode(s):
    try:
        length, data = s.split(':')
    except ValueError:
        raise NetStringError, "Separator not found"
    try:
        length = int(length)
    except ValueError:
        raise NetStringError, "Can not read length"
    if len(data) != length+1:
        raise NetStringError, "Data has unexpected length"
    if data[-1] != ',':
        raise NetStringError, "End-delimiter not found"
    return data[:-1]

def NetStringEncode(s):
    return str(len(s)) + ":" + s + ","


class MyPermanentVerifierException(ValueError): pass

class MyTemporaryVerifierException(ValueError): pass

class MyBaseRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        debug("Connected from " + str(self.client_address))
        self.localSetup()
        while 1:
            receivedData = self.request.recv(8192)
            if (receivedData == None) or (len(receivedData) == 0): break
            debug("Data: (%s)" % receivedData)
            self.request.sendall(self.process(receivedData))
        self.request.close();
        self.localFinish()
        debug("Disconnected")

    def process(self, data):
        debug("MyBaseRequestHandler.process")
        return data

    def localSetup(self): pass

    def localfinish(self): pass


class SendmailAdaptor:
    PERM = "PERM "
    OK = "OK "
    NOTFOUND = "NOTFOUND "
    TEMP = "TEMP "

    def preProcess(self, data):
        try:
            data = NetStringDecode(data)
            klass, data = data.split(' ')
            return klass, data
        except NetStringError, arg:
            raise MyPermanentVerifierException, arg
        except ValueError:
            raise MyPermanentVerifierException, "<class> <data> expected, only one found"

    def postProcess(self, data):
        return NetStringEncode(data)

    def process(self, data):
        startTime = time.time()
        try:
            klass, data2 = self.preProcess(data)
            arg = self.execute(klass, data2)
            code = SendmailAdaptor.OK
        except MyPermanentVerifierException, arg:
            code, arg = SendmailAdaptor.PERM, str(arg)
        except MyTemporaryVerifierException, arg:
            code, arg = SendmailAdaptor.TEMP, str(arg)
        endTime = time.time()
        log("Class: %s, Data: %s, Code: %s, Arg: %s, Delay: %f" % (klass, data2, code, arg, endTime-startTime))
        return self.postProcess(code + arg)

    def execute(self, data):
        return data

class NullAdaptor(SendmailAdaptor):
    def preProcess(self, data):
        return re.compile(r'^(.*?)[\r\n]{1,2}$').match(data).group(1)

    def postProcess(self, data):
        return data + "\n"


class SendmailDispatcher(SendmailAdaptor, MyBaseRequestHandler):
    pluginContainerObjects = {}
    

    def registerAll(config):
        for section in config.get('Daemon', 'Plugins').split(','):
            SendmailDispatcher.register(section, config)

    registerAll = staticmethod(registerAll)
    

    def register(section, config):
        cfg = Config(section, config)
        className = cfg.get('ContainerClass')
        moduleName = cfg.get('ContainerModule')
        if className == None:
            className = 'smmapBaseHandlerContainer'
        else:
            if moduleName == None:
                moduleName == className
            m = __import__(moduleName)
        log("Registering %s, %s" % (section, className))
        klass = eval("m.%s" % className)
        containerObject = klass(cfg)
        containerObject.setup()
        SendmailDispatcher.pluginContainerObjects[section] = containerObject

    register = staticmethod(register)


    def localSetup(self):
        self.pluginWorkerObjects = {}

    def localFinish(self):
        for o in self.pluginWorkerObjects.values():
            o.finish()

    def execute(self, klass, data):
        if not self.pluginContainerObjects.has_key(klass):
            raise MyPermanentVerifierException, "Class %s not implemented" % klass
        elif not self.pluginWorkerObjects.has_key(klass):
            debug("Instantiate worker %s" % klass)
            self.pluginWorkerObjects[klass] = self.pluginContainerObjects[klass].getWorker()

        return self.pluginWorkerObjects[klass].execute(data)
    

class Config(object):
    def __init__(self, section, config):
        self.section = section
        self.config = config

    def getSection(self):
        return self.section

    def get(self, item):
        return self.config.get(self.section, item)
    

class smmapBaseHandlerWorker(object):
    def __init__(self, container):
        self.container = container

    def setup(self): pass

    def finish(self): pass

    def execute(self, data):
        raise NotImplementedError

class smmapBaseHandlerContainer(object):
    def __init__(self, cfg):
        self.config = cfg
        workerClassName = cfg.get('WorkerClass')
        workerModuleName = cfg.get('WorkerModule')
        if workerModuleName == None:
            workerModuleName = workerClassName
        m = __import__(workerModuleName)
        self.workerClass = eval("m.%s" % workerClassName)

    def setup(self): pass

    def finish(self): pass

    def getWorker(self):
        worker = self.workerClass(self)
        worker.setup()
        return worker