#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2017             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software;  you can redistribute it and/or modify it
# under the  terms of the  GNU General Public License  as published by
# the Free Software Foundation in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.

# very odd and confusing example outputs:

# version 3.0.0
# .1.3.6.1.4.1.21239.5.1.1.2.0 3.0.0
# .1.3.6.1.4.1.21239.5.1.1.7.0 1
# .1.3.6.1.4.1.21239.5.1.2.1.3.1 Data Center 1
# .1.3.6.1.4.1.21239.5.1.2.1.5.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.4.1 "91 54 06 9D C9 54 06 9D E9 C9 06 9D BD 9B 06 9D "
# .1.3.6.1.4.1.21239.5.1.2.1.6.1 199
# .1.3.6.1.4.1.21239.5.1.2.1.7.1 36
# .1.3.6.1.4.1.21239.5.1.2.1.8.1 44
#
# version 3.2.0
# .1.3.6.1.4.1.21239.5.1.1.2.0 3.2.0
# .1.3.6.1.4.1.21239.5.1.1.7.0 1
# .1.3.6.1.4.1.21239.5.1.2.1.1.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.2.1 41D88039003580C3
# .1.3.6.1.4.1.21239.5.1.2.1.3.1 RSGLDN Watchdog 15
# .1.3.6.1.4.1.21239.5.1.2.1.4.1 1
# .1.3.6.1.4.1.21239.5.1.2.1.5.1 173
# .1.3.6.1.4.1.21239.5.1.2.1.6.1 46
# .1.3.6.1.4.1.21239.5.1.2.1.7.1 56


def _translate_availability(availability):
    return {
        '0': (2, 'unavailable'),
        '1': (0, 'available'),
        '2': (1, 'partially unavailable'),
    }[availability]


def _parse_legacy_line(line, temp_unit):
    '''
    >>> [i for i in _parse_legacy_line(['1', 'blah', '2CD', '1', '30', '20', '8'], 'C')]
    [('general', {'Watchdog 1': {'descr': 'blah', 'availability': (0, 'available')}}), ('temp', {'Temperature 1': ('30', 'C')}), ('humidity', {'Humidity 1': '20'}), ('dew', {'Dew point 1': ('8', 'C')})]
    '''
    sensor_id = line[0]
    yield 'general', {
        'Watchdog %s' % sensor_id: {
            'descr': line[1],
            'availability': _translate_availability(line[3])
        },
    }
    yield 'temp', {'Temperature %s' % sensor_id: (line[4], temp_unit)}
    yield 'humidity', {'Humidity %s' % sensor_id: line[5]}
    yield 'dew', {'Dew point %s' % sensor_id: (line[6], temp_unit)}


def _parse_line(line, temp_unit):
    '''
    >>> [i for i in _parse_line(['1', 'blah', '1', '30', '20', '8'], 'C')]
    [('general', {'Watchdog 1': {'descr': 'blah', 'availability': (0, 'available')}}), ('temp', {'Temperature 1': ('30', 'C')}), ('humidity', {'Humidity 1': '20'}), ('dew', {'Dew point 1': ('8', 'C')})]
    '''
    sensor_id = line[0]
    yield 'general', {
        'Watchdog %s' % sensor_id: {
            'descr': line[1],
            'availability': _translate_availability(line[2])
        },
    }
    yield 'temp', {'Temperature %s' % sensor_id: (line[3], temp_unit)}
    yield 'humidity', {'Humidity %s' % sensor_id: line[4]}
    yield 'dew', {'Dew point %s' % sensor_id: (line[5], temp_unit)}


def parse_watchdog_sensors(info):

    parsed = {}

    general, data = info
    if not general:
        return parsed

    temp_unit = {
        '1': 'C',
        '0': 'F',
        '': 'C',
    }[general[0][1]]

    version = int(general[0][0].replace('.', ''))

    if version <= 300:
        line_parser = _parse_legacy_line
    else:
        line_parser = _parse_line

    for line in data:
        for check_type, parsed_line in line_parser(line, temp_unit):
            parsed.setdefault(check_type, {}).update(parsed_line)

    return parsed


#.
#   .--general-------------------------------------------------------------.
#   |                                                  _                   |
#   |                   __ _  ___ _ __   ___ _ __ __ _| |                  |
#   |                  / _` |/ _ \ '_ \ / _ \ '__/ _` | |                  |
#   |                 | (_| |  __/ | | |  __/ | | (_| | |                  |
#   |                  \__, |\___|_| |_|\___|_|  \__,_|_|                  |
#   |                  |___/                                               |
#   +----------------------------------------------------------------------+
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_watchdog_sensors(parsed):
    for key in parsed.get('general', {}):
        yield (key, {})


def check_watchdog_sensors(item, params, parsed):

    data = parsed.get('general', {}).get(item)

    if not data:
        return

    descr = data['descr']
    state, state_readable = data['availability']

    yield state, state_readable

    if not descr == '':
        yield 0, "Location: %s" % descr


check_info['watchdog_sensors'] = {
    'parse_function': parse_watchdog_sensors,
    'inventory_function': inventory_watchdog_sensors,
    'check_function': check_watchdog_sensors,
    'service_description': '%s',
    'snmp_info': [
        (
            '.1.3.6.1.4.1.21239.5.1.1',
            [
                '2',  #GEIST-V4-MIB::productVersion
                '7',  #GEIST-V4-MIB::temperatureUnits
            ]),
        (
            '.1.3.6.1.4.1.21239.5.1.2.1',
            [
                OID_END,
                '3',  #GEIST-V4-MIB::internalName
                '4',  #GEIST-V4-MIB::internalLabel    but internalAvail    if version 3.2.0
                '5',  #GEIST-V4-MIB::internalAvail    but internalTemp     if version 3.2.0
                '6',  #GEIST-V4-MIB::internalTemp     but internalHumidity if version 3.2.0
                '7',  #GEIST-V4-MIB::internalHumidity but internalDewPoint if version 3.2.0
                '8',  #GEIST-V4-MIB::internalDewPoint but empty            if version 3.2.0
            ])
    ],
    'snmp_scan_function': lambda oid: oid('.1.3.6.1.2.1.1.2.0').startswith('.1.3.6.1.4.1.21239.5.1')
                          or oid('.1.3.6.1.2.1.1.2.0').startswith('.1.3.6.1.4.1.21239.42.1'
                                                                 ),  # firmware upgrade
    'includes': ['temperature.include']
}

#.
#   .--temp----------------------------------------------------------------.
#   |                       _                                              |
#   |                      | |_ ___ _ __ ___  _ __                         |
#   |                      | __/ _ \ '_ ` _ \| '_ \                        |
#   |                      | ||  __/ | | | | | |_) |                       |
#   |                       \__\___|_| |_| |_| .__/                        |
#   |                                        |_|                           |
#   +----------------------------------------------------------------------+
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_watchdog_sensors_temp(parsed):
    for key in parsed.get('temp', {}):
        yield (key, {})


def check_watchdog_sensors_temp(item, params, parsed):

    data = parsed.get('temp', {}).get(item)

    if not data:
        return

    temperature_str, unit = data
    return check_temperature(float(temperature_str) / 10.0,
                             params,
                             "check_watchdog_sensors.%s" % item,
                             dev_unit=unit.lower())


check_info['watchdog_sensors.temp'] = {
    'inventory_function': inventory_watchdog_sensors_temp,
    'check_function': check_watchdog_sensors_temp,
    'service_description': '%s ',
    'has_perfdata': True,
    'group': 'temperature',
}

#.
#   .--humidity------------------------------------------------------------.
#   |              _                     _     _ _ _                       |
#   |             | |__  _   _ _ __ ___ (_) __| (_) |_ _   _               |
#   |             | '_ \| | | | '_ ` _ \| |/ _` | | __| | | |              |
#   |             | | | | |_| | | | | | | | (_| | | |_| |_| |              |
#   |             |_| |_|\__,_|_| |_| |_|_|\__,_|_|\__|\__, |              |
#   |                                                  |___/               |
#   +----------------------------------------------------------------------+
#   |                                                                      |
#   '----------------------------------------------------------------------'

factory_settings['watchdog_sensors_humidity_default_levels'] = {
    'levels': (50, 55),
    'levels_lower': (10, 15),
}


def inventory_watchdog_sensors_humidity(parsed):
    for key in parsed.get('humidity', {}):
        yield (key, {})


def check_watchdog_sensors_humidity(item, params, parsed):

    data = parsed.get('humidity', {}).get(item)

    if not data:
        return

    humidity = int(data)
    warn, crit = params['levels']
    warn_lower, crit_lower = params['levels_lower']

    yield 0, "%.1f%%" % humidity, [('humidity', humidity, warn, crit)]

    if humidity >= crit:
        yield 2, "warn/crit at %s/%s" % (warn, crit)
    elif humidity <= crit_lower:
        yield 2, "warn/crit at %s/%s" % (warn, crit)
    elif humidity >= warn:
        yield 1, "warn/crit below %s/%s" % (warn, crit)
    elif humidity <= warn_lower:
        yield 1, "warn/crit below %s/%s" % (warn, crit)


check_info['watchdog_sensors.humidity'] = {
    'inventory_function': inventory_watchdog_sensors_humidity,
    'check_function': check_watchdog_sensors_humidity,
    'service_description': '%s',
    'has_perfdata': True,
    'group': 'humidity',
    'default_levels_variable': 'watchdog_sensors_humidity_default_levels',
}

#.
#   .--dew-----------------------------------------------------------------.
#   |                             _                                        |
#   |                          __| | _____      __                         |
#   |                         / _` |/ _ \ \ /\ / /                         |
#   |                        | (_| |  __/\ V  V /                          |
#   |                         \__,_|\___| \_/\_/                           |
#   |                                                                      |
#   +----------------------------------------------------------------------+
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_watchdog_sensors_dew(parsed):
    for key in parsed.get('dew', {}):
        yield (key, {})


def check_watchdog_sensors_dew(item, params, parsed):

    data = parsed.get('dew', {}).get(item)

    if not data:
        return

    dew = float(data[0]) / 10.0
    unit = data[1]
    if unit == "F":
        dew = 5.0 / 9.0 * (dew - 32)
    yield check_temperature(dew, params, "check_watchdog_sensors.%s" % item)


check_info['watchdog_sensors.dew'] = {
    'inventory_function': inventory_watchdog_sensors_dew,
    'check_function': check_watchdog_sensors_dew,
    'service_description': '%s',
    'has_perfdata': True,
    'group': 'temperature',
}
