#!/usr/bin/env python
# -----------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
# -----------------------------------------------------------------------

#
# This scirpt stops the ducc system-test simulator
#
import os
import sys
import time

DUCC_HOME = os.path.abspath(__file__ + '/../../..')
sys.path.append(DUCC_HOME + '/admin')

import getopt

from ducc_util  import DuccUtil
from properties import Properties
from ducc       import Ducc
from ducc_util  import ThreadPool

class StopSim(DuccUtil):

    def signal_process(self, args):
        inst, data_prop, signal = args
        data = data_prop
        (node, pid, pname) = data.split(' ')

        msgs = []
        msgs.append(('Stopping process', inst, 'on', node, pid, pname, 'with signal', signal))
        if ( not (inst in self.default_components )):
            cmp = 'agent'
        else:
            cmp = inst
        self.ssh(node, True, 'kill', signal, pid)

        return msgs

    def usage(self, msg):

        if ( msg != None ):
            print ' '.join(msg)

              
        print "Usage:"
        print "   stop_sim [options]"   
        print "        If no options are given, all ducc processes from sim.pids are stopped using SIGINT"
        print ""
        print "Options:"
        print "   -c --component compenent name"
        print "        The name is one of", self.default_components, "or an ID from sim.pids"
        print ""
        print "   -k --kill"
        print "        Sends SIGKILL to the indicated process"
        print ""
        print "   -p --pause"
        print "        Sends SIGSTOP to the indicated process"
        print ""
        print "   -r --resume"
        print "        Sends SIGCONT to the indicated process"
        print ""
        print "    --nothreading"
        print "        Disable multithreaded operation if it would otherwise be used"
        print ""
        print "   -v, --version"
        print "        Print the current DUCC version"
        print ""
        print "   -?,  -h, --help,"
        print "        Print this"
        print ""
        sys.exit(1) 
            

    def invalid(self, *msg):
        if ( msg[0] != None ):
            print ' '.join(msg)
            
            print "For usage run"
            print "    stop_sim -h"
            print 'or'
            print '    stop_sim --help'
            sys.exit(1)

    def main(self, argv):

        components = []
        instances = []
        signal = '-INT'
        stopbroker = False
        stopdatabase = False

        try:
            opts, args = getopt.getopt(argv, 'c:kprvh?', ['component=', 'kill' 'pause', 'resume', 'nothreading', 'version', 'help'])
        except:
            self.invalid('Invalid arguments', ' '.join(argv))
                  
        for ( o, a ) in opts:
            if o in ( '-c', '--component' ):
                if (a != 'all'):   
                	instances.append(a)
            elif o in ( '-k', '--kill' ):
                signal = '-KILL'
            elif o in ( '-p', '--pause' ):
                signal = '-STOP'
            elif o in ( '-r', '--resume' ):
                signal = '-CONT'
            elif o in ( '--nothreading' ):
                self.disable_threading()
            elif o in ( '-v', '--version' ):
                print self.version()
                sys.exit(0)
            elif o in ( '-h', '--help' ):
                self.usage(None)
            elif ( o == '-?'):
                self.usage(None)
            else:
                self.invalid('bad args: ', ' '.join(argv))

        pids = Properties()
        pids.load('sim.pids')

        self.threadpool = ThreadPool(50)

        try:
            if ( (len(components) + len(instances)) == 0 ):
                for (inst, data) in pids.items():                    
                    self.threadpool.invoke(self.signal_process, inst, pids.get(inst), signal)
                    time.sleep(.1)
                    if ( signal in ('-KILL', '-INT') ):
                        pids.delete(inst)
                        stopbroker = True
                        stopdatabase = True
    
            else:
                for inst in instances:
                    print 'Instance', inst
                    data = pids.get(inst)
                    if ( data == None ):
                        if ( inst == 'broker' and signal in ('-KILL', '-INT') ):
                            stopbroker = True
                        else:
                            print "WARNING - No PID found for instance", inst
                    elif ( inst == 'db' ):
                        stopdatabase = True
                    else:
                        self.threadpool.invoke(self.signal_process, inst, pids.get(inst), signal)
                        time.sleep(.1)
                        if ( signal in ('-KILL', '-INT') ):
                            pids.delete(inst)
        except:
            self.threadpool.quit()
            print sys.exc_info()[0], "Exiting, simulator may not be properly stopped."
            sys.exit(1)
            
        self.threadpool.quit();

        pids.write('sim.pids')

        sleeptime = 5
        print "Waiting " + str(sleeptime) + " seconds to broadcast agent shutdown."
        time.sleep(sleeptime)

        if ( stopdatabase and self.automanage_database ) :
            print 'Stopping database'
            self.db_stop()

        if ( stopbroker and self.automanage_broker ):
            print "Stopping broker"
            self.stop_broker()                

if __name__ == "__main__":
    stopper = StopSim()
    stopper.main(sys.argv[1:])
