#! /usr/bin/env python
# -*- coding: utf-8 -*-

import os
import logging.config
import ConfigParser
import signal
import argparse

from monitoring_agent.configurator import ConfiguratorException
from monitoring_agent.inputs.nagios_plugins import NagiosPlugins
from monitoring_agent.outputs.email import Email
from monitoring_agent.outputs.nsca import Nsca
from monitoring_agent.outputs.ws_shinken import WsShinken, CacheFileException

# Store config objects
CONFIG = {}

LOG = logging.getLogger(__name__)

if __name__ == '__main__':

    # Catch signals to remove the stack trace print when the program is stopped.
    # PID file and caches file are correctly removed and closed by the latest "finally:"
    for signum in [signal.SIGHUP, signal.SIGINT, signal.SIGQUIT, signal.SIGABRT, signal.SIGTERM, ]:
        signal.signal(signum, (lambda signum, frame: None))

    # CLI
    ARGS_PARSER = argparse.ArgumentParser(description='Use nagios-plugins to send monitoring data by NSCA or WS_Shinken.',
                                          epilog='Example: tanto '
        '--config_dir=/etc/tanto --pid=/var/run/tanto.pid')
    ARGS_PARSER.add_argument('--config_dir',
                             default='/etc/tanto',
                             help='Config files directory.')
    ARGS_PARSER.add_argument('--pid',
                             default='/var/run/tanto.pid',
                             help='The pidfile, to avoid multiple instances.')
    ARGS = ARGS_PARSER.parse_args()

    # Logging
    try:
        logging.config.fileConfig(os.path.join(ARGS.config_dir, 'logging.ini'), disable_existing_loggers=False)
    except ConfigParser.NoSectionError:
        print('Your logging file is wrong or is missing, please to provide a correct one.')
    else:

        # PID file management
        if os.path.isfile(ARGS.pid):
            LOG.critical("%s already exists, exiting" % ARGS.pid)
        else:
            try:
                file(ARGS.pid, 'w').write(str(os.getpid()))
            except IOError:
                LOG.critical("Impossible to create the PID file: %s" % ARGS.pid)
            else:
                try:
                    try:
                        CONFIG['nagios_plugins'] = NagiosPlugins(os.path.join(ARGS.config_dir, 'inputs/nagios_plugins.cfg'))
                        CONFIG['email'] = Email(os.path.join(ARGS.config_dir, 'outputs/email.cfg'))
                        CONFIG['nsca'] = Nsca(os.path.join(ARGS.config_dir, 'outputs/nsca.cfg'))
                        CONFIG['ws_shinken'] = WsShinken(os.path.join(ARGS.config_dir, 'outputs/ws_shinken.cfg'))
                    except IOError, e:
                        LOG.critical("Impossible to read a config file: %r", e) # @todo: give more details
                    except CacheFileException, cache_exception:
                        LOG.critical("Impossible to read the cache file: '%s'", cache_exception.cache_file) # @todo: give more details
                    except ConfiguratorException, ce:
                        LOG.critical("The config file '%s' is invalid, errors details below:", ce.config_file)
                        for validation_error in ce.validation_errors:
                            if type(ce.validation_errors[validation_error]) != bool:
                                for item in ce.validation_errors[validation_error]:
                                    if ce.validation_errors[validation_error][item] != True:
                                        LOG.critical("The option '%s' is invalid: %s",
                                                     item,
                                                     ce.validation_errors[validation_error][item])
                    else:
                        for np_result in CONFIG['nagios_plugins'].launch_plugin():
                            CONFIG['email'].aggregate_result(np_result['return_code'],
                                                       np_result['output'],
                                                       np_result['service_description'],
                                                       np_result['specific_servers'])
                            CONFIG['nsca'].send_result(np_result['return_code'],
                                                       np_result['output'],
                                                       np_result['service_description'],
                                                       np_result['specific_servers'])
                            CONFIG['ws_shinken'].send_result(np_result['output'],
                                                             np_result['service_description'],
                                                             np_result['time_stamp'],
                                                             np_result['specific_servers'])
                        CONFIG['email'].send_results()

                except Exception, inst: # to log eventual exceptions
                    LOG.exception(inst)
                finally:
                    if 'ws_shinken' in CONFIG:
                        CONFIG['ws_shinken'].close_cache()
                    try:
                        os.unlink(ARGS.pid)
                    except IOError:
                        LOG.critical("PID file is missing: %s" % ARGS.pid)
