#!/usr/bin/python

import exceptions
import platform
import getopt
import sys
from os.path import exists
import logging
import logging.handlers

from storm.monitoring.sensor.api import converter
from storm.monitoring.sensor.api import publisher
from storm.monitoring.sensor.api import measures
from storm.monitoring.sensor.api import units
from storm.monitoring.sensor.api import metrics
from storm.monitoring.sensor.api import services
from storm.monitoring.sensor.api import sensor
from storm.monitoring.sensor.api import built_sensors

from storm.monitoring.sensor.host.mem import mem_sensor
from storm.monitoring.sensor.host.mem import mem_check
from storm.monitoring.sensor.host.cpu import cpu_sensor
from storm.monitoring.sensor.host.cpu import cpu_check

from storm.monitoring.sensor.service.logsize import logsize_sensor
from storm.monitoring.sensor.service.logsize import file_check
from storm.monitoring.sensor.service.procmem import procmem_sensor
from storm.monitoring.sensor.service.procmem import procmem_check

from storm.monitoring.sensor.common import string_converter
from storm.monitoring.sensor.common import file_publisher
from storm.monitoring.sensor.common import usage
from storm.monitoring.sensor.common import configuration_parser
from storm.monitoring.sensor.common import file_compressor

class ParsingError(exceptions.Exception):
    pass

class InputError(exceptions.Exception):
    pass

class Parser(object):

    def __init__(self):
        self.parameters = {}
        self.parameters['monitoring_version'] = '1.0.0'
        self.parameters['publish_file'] = '/var/log/monitoring/'
        self.parameters['default_conf'] = '/etc/storm/monitoring/sensor-common/services.ini'
        self.parameters['hostname'] = platform.node()
        self.parameters['metric'] = ''
        self.parameters['services'] = []

    def do_parsing(self):
        try:
            opts, args = getopt.getopt(sys.argv[1:],
                "hVc:m:",
                ["help", "version", "config=", "metric="])
                #"hvVs:m:",
                #["help", "verbose", "version", "service=", "metric="])
        except getopt.GetoptError, err:
            print str(err)
            usage.get_usage()
            sys.exit(2)

        for opt, value in opts:
            if opt in ("-h", "--help"):
                usage.get_usage()
                sys.exit(0)
            elif opt in ("-V", "--version"):
                print self.parameters['monitoring_version']
                sys.exit(0)
            elif opt in ("-c", "--config"):
                self.parameters['default_conf'] = value
            elif opt in ("-m", "--metric"):
                get_metrics = metrics.Metrics().get_string_metrics()
                if value not in get_metrics.values():
                    msg = 'The specified metric %s does not exist' % value
                    raise InputError(msg)
                for metric_key in get_metrics:
                    if value == get_metrics[metric_key]:
                        self.parameters['metric'] = int(metric_key)
            else:
                msg = 'The specified %s option is not recognized' % str(opt)
                raise ParsingError(msg)

        if not exists(self.parameters['default_conf']):
            msg='Configuration file does not exist'
            raise InputError(msg)

        node_services = configuration_parser.NodeServices(
            conf=self.parameters['default_conf']).get_node_services()

        if 'storm_nodes' not in node_services:
            msg='Configuration file is not well formed'
            usage.usage()
            raise InputError(msg)

        for key in node_services['storm_nodes']:
            if node_services['storm_nodes'][key].lower() == 'true':
                get_services = services.Services().get_string_services()
                if key.upper() not in get_services.values():
                    msg = 'The specified service node %s is not supported' % key.upper()
                    raise InputError(msg)
                for service_key in get_services:
                    if key.upper() == get_services[service_key]:
                        self.parameters['services'].append(int(service_key))

        if len(self.parameters['services']) == 0:
            msg = 'In the configuration file set to true the StoRM services that are installed in the node'
            raise InputError(msg)

    def check_parameters(self):
        if self.parameters['metric'] == '':
            raise InputError('Metric parameter is not provided')
        if self.parameters['services'] == []:
            raise InputError('Service parameter is not provided')

    def get_parameters(self):
        self.do_parsing()
        self.check_parameters()
        return self.parameters



if __name__ == '__main__':
    logger = logging.getLogger('storm_sensor')
    log_name = '/var/log/monitoring/storm_sensor.log'
    logger.setLevel(logging.DEBUG)
    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

    file_rotating = file_compressor.CompressedRotatingFileHandler(log_name, maxBytes=1000000000, backupCount=5)
    file_rotating.setFormatter(formatter)
    file_rotating.setLevel(logging.DEBUG)
    logger.addHandler(file_rotating)
        
    try:
        logger.info("Get parameters")
        parameters = Parser().get_parameters()

        build_monitoring = built_sensors.BuiltSensors()

        if metrics.Metrics().is_host_metric(parameters['metric']):
            logger.info("Set host metric")
            if parameters['metric'] == metrics.Metrics.mem:
                build_monitoring.add_sensor(mem_sensor.MemSensor(parameters['hostname'], parameters['services']))
                logger.info("Set mem sensor")
            elif parameters['metric'] == metrics.Metrics.cpu:
                build_monitoring.add_sensor(cpu_sensor.CpuSensor(parameters['hostname'], parameters['services']))
                logger.info("Set cpu sensor")
            else:
                raise sensor.SensorError('Not implemented yet')
            publish = file_publisher.FilePublisher(parameters['publish_file'] + '/host/')
        elif metrics.Metrics().is_service_metric(parameters['metric']):
            logger.info("Set service metric")
            for service_type in parameters['services']:
                if parameters['metric'] == metrics.Metrics.log_size:
                    build_monitoring.add_sensor(logsize_sensor.LogSizeSensor(parameters['hostname'], service_type))
                    logger.info("Set log_size sensor")      
                elif parameters['metric'] == metrics.Metrics.proc_mem:
                    build_monitoring.add_sensor(procmem_sensor.ProcMemSensor(parameters['hostname'], service_type))
                    logger.info("Set proc_mem sensor")
                else:
                    raise sensor.SensorError('Not implemented yet')
            publish = file_publisher.FilePublisher(parameters['publish_file'] + '/service/')
        else:
            raise sensor.SensorError('Not implemented yet')

        for sen in build_monitoring.get_sensors():
            logger.info("Run sensor")
            sen.run()
            logger.info("of the type %s" % metrics.Metrics().get_string_metric(sen.get_metric_type()))
            conver = string_converter.StringConverter()

            if metrics.Metrics().is_host_metric(parameters['metric']):
                tmp_services = sen.get_storm_service_types()
            elif metrics.Metrics().is_service_metric(parameters['metric']):
                convert_int_in_list = []
                convert_int_in_list.append(sen.get_storm_service_types())
                tmp_services = convert_int_in_list
            logger.info("for the services %s" % ','.join([services.Services().get_string_service(service) for service in tmp_services]))
            for produced_measure in sen.get_measures().get_measures():
                output = conver.do_conversion(produced_measure, sen.get_timestamp())
                publish.do_publish(tmp_services, sen.get_metric_type(), output)

    except converter.ConversionError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except publisher.PublisherError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except sensor.SensorError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except file_check.FileSizeError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except procmem_check.PsError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except units.UnitsError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except services.ServicesError, err:
        logger.error(err)
        print '\n\nExecution: ', err
    except ParsingError,err:
        logger.error(err)
        print '\n\nExecution: ', err
        usage.get_usage()
    except InputError,err:
        logger.error(err)
        print '\n\nExecution: ', err
        usage.get_usage()
    except KeyboardInterrupt:
        logger.error(err)
        print '\n\nExecution n!'
        sys.exit(1)


