#!/usr/bin/env python
# -*- coding: utf-8 -*-
# $Id: spoolerctl 1634 2013-04-12 15:36:36Z amelung $
#
# Copyright (c) 2007-2013 Otto-von-Guericke-Universität, Magdeburg
#
# This file is part of ECSpooler.
#
"""
This module contains functions to start/stop ECSpooler or get status 
information from it.  __main__ reads the command line arguments and processes 
them.
"""

import os, sys, time, signal, xmlrpclib 
#import socket
#import atexit
#import traceback
#import logging
from getopt import getopt
from getopt import GetoptError
from getpass import getpass

# add parent directory to the system path
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir))

# Spooler
from lib.Spooler import Spooler
from lib.util.servicecontrol import ServiceControl

# SoapWrapper
try:
    from suds.client import Client
    from spyne.util.simple import wsgi_soap11_application
    from wsgiref.simple_server import make_server
    
    from lib.soapwrapper import set_spooler_host, set_spooler_port
    from lib.soapwrapper import SoapWrapper
    from lib.data.dto import TARGET_NAMESPACE
except ImportError, e: 
    print >> sys.stdout, ("%s. %s" % (e, "SOAP Wrapper for ECSpooler will not be available."))
    soap_libs_available = False
else:
    soap_libs_available = True
    

from lib.util import settings

# Logging initialisieren
settings.init_logging('spooler')


class SpoolerControl(ServiceControl):
    """
    """
    
    @staticmethod
    def usage():
        """
        """
        print """
Usage: spoolerctl [OPTION ...] {start|stop|restart|status}

OPTIONs are:
  -P port         Port to connect/bind ECSpooler to.  Default: 5050
  -u username     Name of user required for authentication when executing 
                  start|stop|restart|status command
  -p password     Password of user required for authentication when
                  executing start|stop|restart|status command
  --soap          Starts SOAP Wrapper for ECSpooler which allows 

"""
    
    def _process_child_start(self):
        """
        """
        # child process
        spooler = Spooler(self.host, int(self.port))
        
        # blocks 'til shutdown
        err_msg = spooler.start() 
        if err_msg:
            print >> sys.stderr, err_msg
            
    def _process_parent_start(self):
        """
        """
        # parent process
        time.sleep(1)

    def _process_stop(self):
        """
        We will get the PID from the status information and then send  
        os.kill to that process.
        """
        service = xmlrpclib.ServerProxy(self._get_uri())
        pid = service.getPID(self._get_auth())
        
        try:
            # stops the spooler sending <code>kill -15 process-id<code>
            os.kill(pid, signal.SIGTERM)
        except AttributeError:
            print >> sys.stderr, ("os.kill and/or signal.SIGTERM not defined." 
                                  "Try stopping %s elsewhere." % self.name)

    def _process_status(self):
        """
        Returns status information from a running spooler
        """
        service = xmlrpclib.ServerProxy(self._get_uri())
        return service.getStatus(self._get_auth())

class SoapWrapperControl(ServiceControl):
    """
    """
    
    def __init__(self, name, port, spooler_port, username=None, password=None):
        """
        """
        ServiceControl.__init__(self, name, port, username=username, password=password)
        
        self.spooler_host = self.host
        self.spooler_port = spooler_port
    
    def _process_child_start(self):
        """
        """
        # child process
        set_spooler_host(self.spooler_host)
        set_spooler_port(self.spooler_port)
        
        #logging.basicConfig(level=logging.DEBUG)
        #logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
        
        #print "Listening to %s" % self._get_uri()
        #print "WSDL is at: http://%s:%d/?wsdl" % (host, port)
        #print "Connecting to ECSpooler http://%s:%i" % (self.spooler_host, self.spooler_port) 
        
        wsgi_app = wsgi_soap11_application([SoapWrapper], TARGET_NAMESPACE)
        server = make_server(self.host, self.port, wsgi_app)
        
        server.serve_forever()
            
    def _process_parent_start(self):
        # parent process
        time.sleep(1)

    def _process_stop(self):
        """
        """
        c = Client('http://%s:%i/?wsdl' % (self.host, self.port), cache=None)
        state = c.service.getPID(self.username, self.password)
        
        try:
            # stops the SOAP Wrapper sending kill -15 process-id
            os.kill(state.pid, signal.SIGTERM)
        except AttributeError:
            print >> sys.stdout, ("os.kill and/or signal.SIGTERM not " 
                "defined. Try stopping %s elsewhere." % self.name)

    def _process_status(self):
        """
        """
        return ''

# -----------------------------------------------------------------------------
def main():    
    """
    """
    try:
        opts, args = getopt(sys.argv[1:], "P:u:p:h", 
                            ["port=", "username=", "password=", "help", "soap"])
    except GetoptError:
        # print usage information and exit:
        SpoolerControl.usage()
        sys.exit(2)

    if len(args) == 0:
        SpoolerControl.usage()
        sys.exit(2)

    else:
        port = 5050
        user = None
        password = None
        with_soap = False
        
        for o, a in opts:
            if o in ("-h", "--help"):
                SpoolerControl.usage()
                sys.exit()
    
            if o in ("-P", "--port"):
                try:
                    port = int(a)
                except ValueError:
                    SpoolerControl.usage()
                    sys.exit(2)
                    
            if o in ("-u", "--username"):
                user = a
    
            if o in ("-p", "--password"):
                password = a
            
            if o in ("--soap"):
                with_soap = True;

        cmd = args[0]
    
        if not user:
            user = raw_input("Username: ")
        
        if not password:
            password = getpass("Password: ")
            
        if not user or not password:
            print "%s requires username and password." % cmd
            SpoolerControl.usage()
            sys.exit(2)

        # start spooler as XMLRPC service
        spoolerctl = SpoolerControl("ECSpooler", port, user, password)
        spoolerctl.process(cmd)
        
        # start SOAP wrapper for ECSpooler
        if (soap_libs_available and with_soap):
            soapwrapperctl = SoapWrapperControl("Soap Wrapper for ECSpooler", port + 1, port, user, password)
            soapwrapperctl.process(cmd)


# -- Main ---------------------------------------------------------------------
if __name__ == "__main__":
    main()
            
