#!/usr/bin/env python

#   Copyright (C) 2012 STFC
#
#   Licensed 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.

'''
Script to run a sending SSM.
@author: Will Rogers
'''

import sys

# Prepend module path
sys.path.insert(0,SSMDIR)

from __init__ import __version__, set_up_logging, LOG_BREAK
from ssm2 import Ssm2, Ssm2Exception
from crypto import CryptoException
from brokers import StompBrokerGetter, STOMP_SERVICE, STOMP_SSL_SERVICE

import logging.config
import ldap
import os
from optparse import OptionParser
import ConfigParser


def main(_host, _port, _topic, _key, _cert, _cadir, _message_path, _use_ssl):
    '''
    Set up connection, send all messages and quit.
    '''
    ver = "SSM %s.%s.%s" % __version__
    op = OptionParser(description=__doc__, version=ver)
    op.add_option('-c', '--config', help='location of config file', 
                          default="%s/sender.cfg" % SSMDIR)
    op.add_option('-l', '--log_config', 
                        help='location of logging config file (optional)', 
                        default='/etc/apel/logging.cfg')
    (options, unused_args) = op.parse_args()
    
    cp = ConfigParser.ConfigParser()
    cp.read(options.config)
    
    # set up logging
    try:
        if os.path.exists(options.log_config):
            logging.config.fileConfig(options.log_config)
        else:
            set_up_logging(cp.get('logging', 'logfile'), 
                           cp.get('logging', 'level'),
                           cp.getboolean('logging', 'console'))
    except (ConfigParser.Error, ValueError, IOError), err:
        print 'Error configuring logging: %s' % str(err)
        print 'The system will exit.'
        sys.exit(1)
    
    log = logging.getLogger('ssmsend')
    
    log.info(LOG_BREAK)
    log.info('Starting sending SSM version %s.%s.%s.' % __version__)
    # If we can't get a broker to connect to, we have to give up.
    try:
        bdii_url = cp.get('broker','bdii')
        log.info('Retrieving broker details from %s ...' % bdii_url)
        bg = StompBrokerGetter(bdii_url)
        use_ssl = _use_ssl
        if use_ssl:
            service = STOMP_SSL_SERVICE
        else:
            service = STOMP_SERVICE
        brokers = bg.get_broker_hosts_and_ports(service, cp.get('broker','network'))
        log.info('Found %s brokers.' % len(brokers))
    except ConfigParser.NoOptionError, e:
        try:
            host = _host
            port = _port
            brokers = [(host, int(port))]
        except ConfigParser.NoOptionError:
            log.error('Options incorrectly supplied for either single broker or \
                    broker network.  Please check configuration')
            log.error('System will exit.')
            log.info(LOG_BREAK)
            print 'SSM failed to start.  See log file for details.'
            sys.exit(1)
    except ldap.LDAPError, e:
        log.error('Could not connect to LDAP server: %s' % e)
        log.error('System will exit.')
        log.info(LOG_BREAK)
        print 'SSM failed to start.  See log file for details.'
        sys.exit(1)
        
    if len(brokers) == 0:
        log.error('No brokers available.')
        log.error('System will exit.')
        log.info(LOG_BREAK)
        sys.exit(1)
        
    try:
        server_cert = None
        verify_server_cert = True
        try:
            server_cert = cp.get('certificates','server_cert')
            try:
                verify_server_cert = cp.getboolean('certificates', 'verify_server_cert')
            except ConfigParser.NoOptionError:
                pass
        except ConfigParser.NoOptionError:
            log.info('No server certificate supplied.  Will not encrypt messages.')
            
        try:
            destination = cp.get('messaging', 'destination')
            if destination == '':
                raise Ssm2Exception('No destination queue is configured.')
        except ConfigParser.NoOptionError, e:
            raise Ssm2Exception(e)
    
        sender = Ssm2(brokers, 
                   _message_path,
                   cert=_cert,
                   key=_key,
                   dest=_topic,
                   use_ssl=_use_ssl,
                   capath=_cadir,
                   enc_cert=server_cert,
                   verify_enc_cert=verify_server_cert)
        
        if sender.has_msgs():
            sender.handle_connect()
            sender.send_all()
            log.info('SSM run has finished.')
        else:
            log.info('No messages found to send.')
        
    except (Ssm2Exception, CryptoException), e:
        print 'SSM failed to complete successfully.  See log file for details.'
        log.error('SSM failed to complete successfully: %s' % e)
    except Exception, e:
        print 'SSM failed to complete successfully.  See log file for details.'
        log.error('Unexpected exception in SSM: %s' % (str(e)))
        log.error('Exception type: %s' % e.__class__)
        
    try:
        sender.close_connection()
    except UnboundLocalError:
        # SSM not set up.
        pass

    log.info('SSM has shut down.')
    log.info(LOG_BREAK)
        
    
if __name__ == '__main__':
    if (len(sys.argv) != 9):
        print "Usage: python ssmsend <hostname> <port> <topic> <key-path> <cert-path> <cadir-path> <path-to-messages-files> <use_ssl>"
        sys.exit(1)

    main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7], sys.argv[8])
    sys.exit(0)
