
import os
import servicemanager
import socket
import sys
import winerror
import win32event
import win32service
import win32serviceutil
import logging
from logging.handlers import NTEventLogHandler

#import agent, reactor
from agent import main as agent_main
from twisted.internet import reactor

logger = logging.getLogger()
fh = NTEventLogHandler("CIRCLE Agent")
formatter = logging.Formatter(
    "%(asctime)s - %(name)s [%(levelname)s] %(message)s")
fh.setFormatter(formatter)
logger.addHandler(fh)
#logger.propagate = False
#logger.setLevel('INFO')
logger.info("%s loaded", __file__)


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "circle-agent"
    _svc_display_name_ = "CIRCLE Agent"
    _svc_description_ = "CIRCLE cloud contextualization agent"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(120)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        try:
            reactor.stop()
            reactor.callFromThread(reactor.stop)
#            reactor.callLater(0, reactor.stop)
        except Exception:
            logger.exception("reactor.stop failed")
        logger.info("%s stopped", __file__)

    def SvcDoRun(self):
        logger.info("%s starting", __file__)
        cnt = 3
        while cnt > 0:
            try:
                servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                servicemanager.PYS_SERVICE_STARTED,
                                (self._svc_name_, ''))
                break
            except Exception:
                logger.exception("Servicemanager busy?") 
                cnt -= 1
        if cnt:
            logger.info("Starting agent_main")
            ret = agent_main()
            logger.error("agent_main returned ret=%r type=%s", ret, type(ret).__name__)
            logger.info("agent_main finished")
            if ret != 0: 
                # “Service-specific error”
                self.ReportServiceStatus(
                    win32service.SERVICE_STOPPED,
                    win32ExitCode=winerror.ERROR_SERVICE_SPECIFIC_ERROR,  # 1066
                    svcExitCode=int(ret)
                )
                return
                
        # normal stop
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)


def main():
    logger.info("Started: %s", sys.argv)
    if len(sys.argv) == 1:
        # service must be starting...
        # for the sake of debugging etc, we use win32traceutil to see
        # any unhandled exceptions and print statements.
        import win32traceutil  # noqa
        logger.info("service is starting...")

        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(AppServerSvc)
        # Now ask the service manager to fire things up for us...
        servicemanager.StartServiceCtrlDispatcher()
        logger.info("service done!")
    else:
        win32serviceutil.HandleCommandLine(AppServerSvc)


if __name__ == '__main__':
    try:
        main()
    except (SystemExit, KeyboardInterrupt):
        raise
    except Exception:
        logger.exception("Exception:")
