#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
# problems because it might remove variables from the check-context which are necessary for
# resolving legacy discovery results such as [("SUMMARY", "diskstat_default_levels")]. Furthermore,
# it might also remove variables needed for accessing discovery rulesets.
from cmk.base.check_legacy_includes.temperature import *  # pylint: disable=wildcard-import,unused-wildcard-import

# OIDs for name and type of the sensors (type 8 = temperature sensor)
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21594 = STRING: "module-1 Crossbar(s5)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21601 = STRING: "module-1 QEng1Sn1(s12)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21602 = STRING: "module-1 QEng1Sn2(s13)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21603 = STRING: "module-1 QEng1Sn3(s14)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21604 = STRING: "module-1 QEng1Sn4(s15)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21605 = STRING: "module-1 QEng2Sn1(s16)"
# SNMPv2-SMI::mib-2.47.1.1.1.1.2.21606 = STRING: "module-1 QEng2Sn2(s17)"
# [...]
# Types of sensors:
#        other(1):        a measure other than those listed below
#        unknown(2):      unknown measurement, or arbitrary, relative numbers
#        voltsAC(3):      electric potential
#        voltsDC(4):      electric potential
#        amperes(5):      electric current
#        watts(6):        power
#        hertz(7):        frequency
#        celsius(8):      temperature
#        percentRH(9):    percent relative humidity
#        rpm(10):         shaft revolutions per minute
#        cmm(11),:        cubic meters per minute (airflow)
#        truthvalue(12):  value takes { true(1), false(2) }
#        specialEnum(13): value takes user defined enumerated values
#        dBm(14):         dB relative to 1mW of power
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21594 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21601 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21602 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21603 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21604 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21605 = INTEGER: 8
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.1.21606 = INTEGER: 8
# [...]

# Current value of the sensor
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21594 = INTEGER: 62
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21601 = INTEGER: 102
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21602 = INTEGER: 99
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21603 = INTEGER: 98
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21604 = INTEGER: 99
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21605 = INTEGER: 101
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.4.21606 = INTEGER: 99
# [...]

# State of the sensor itself
#        ok(1) means the agent can read the sensor
#        value.
#
#        unavailable(2) means that the agent presently
#        can not report the sensor value.
#
#        nonoperational(3) means that the agent believes
#        the sensor is broken.  The sensor could have a
#        hard failure (disconnected wire), or a soft failure
#        such as out-of-range, jittery, or wildly fluctuating
#        readings.
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21594 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21601 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21602 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21603 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21604 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21605 = INTEGER: 1
# SNMPv2-SMI::enterprises.9.9.91.1.1.1.1.5.21606 = INTEGER: 1

# Thresholds
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21594.9 = INTEGER: 95
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21594.10 = INTEGER: 105
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21601.23 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21601.24 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21602.25 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21602.26 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21603.27 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21603.28 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21604.29 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21604.30 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21605.31 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21605.32 = INTEGER: 115
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21606.33 = INTEGER: 110
# SNMPv2-SMI::enterprises.9.9.91.1.2.1.1.4.21606.34 = INTEGER: 115


# Create a dictionary with the information about each
# sensor. The key into the dict is the end OID of the
# sensor.
def parse_cisco_temp_sensor(info):
    description_info, state_info, levels_info = info

    # Create dict of sensor descriptions
    descriptions = dict(description_info)

    # Create dict with thresholds
    thresholds = {}
    for id_, sensortype, scale, precision, value, sensorstate in state_info:
        thresholds.setdefault(id_, [])

    for endoid, level in levels_info:
        # endoid is e.g. 21549.9 or 21459.10
        id_, _subid = endoid.split(".")
        thresholds.setdefault(id_, []).append(float(level))

    # Create main dictionary (only of temperature sensors)
    sensors = []
    for id_, sensortype, scale, precision, value, sensorstate in state_info:
        value = float(value) / (10 ** int(precision))
        threshold = thresholds[id_] / (10 ** int(precision))  # fixed: true-division

        sensors.append(
            (id_, descriptions.get(id_), sensortype, scale, value, sensorstate, threshold)
        )
    return sensors


def inventory_cisco_temp_sensor(info):
    #    sensors = parse_cisco_temp_sensor(info)
    inventory = []
    #    for id, descr, sensortype, scale, value, sensorstate, levels in sensors:
    #        # Use all temperature sensors with a non-empty description and valid threshold
    #        if descr is not None and sensortype == '8' and len(levels) in [ 2, 4 ]:
    #            warn, crit = saveint(levels[0]), saveint(levels[1])
    #            inventory.append(( descr, (warn, crit) ))
    return inventory


def check_cisco_temp_sensor(item, params, info):
    sensors = parse_cisco_temp_sensor(info)
    for _id, descr, _sensortype, _scale, _temp, _sensorstate, _levels in sensors:
        if item == descr:
            #            # Use built in levels if no levels are configured
            #            if params:
            #                warn, crit = params
            #            else:
            #                warn, crit = levels[0:2]
            #                # convert threshold milli values to native unit
            #                if scale == "8":
            #                    temp = temp/1000
            #                    warn = warn/1000
            #
            #            # convert milli temperature to native unit
            #            if scale == "8":
            #                crit = crit/1000
            #
            #            if sensorstate == "2":
            #                return (3, "Data from sensor currently not available")
            #            elif sensorstate == "3":
            #                return (3, "Sensor is broken")
            #
            #            return check_temperature(temp, (warn, crit))
            return 3, "This check is obsolete, please re-inventorize this host"


check_info["cisco_temp_sensor"] = {
    "check_function": check_cisco_temp_sensor,
    "inventory_function": inventory_cisco_temp_sensor,
    "service_description": "Temperature %s",
    "has_perfdata": True,
    "snmp_scan_function": lambda oid: "cisco" in oid(".1.3.6.1.2.1.1.1.0").lower()
    and oid(".1.3.6.1.4.1.9.9.91.1.1.1.1.*") is not None,
    "snmp_info": [
        (
            ".1.3.6.1.2.1.47.1.1.1.1",
            [
                OID_END,
                CACHED_OID(2),  # entPhysicalDescription
            ],
        ),
        # Type and current state
        (
            ".1.3.6.1.4.1.9.9.91.1.1.1.1",
            [
                OID_END,
                1,  # Type (see above), 8 = Celsius, 12 = truth value
                2,  # Scale, 8 == milli
                3,  # Precision
                4,  # Most recent measurement
                5,  # Status of the sensor 1 == ok, 2 == cannot report, 3 == broken
            ],
        ),
        # Threshold
        (
            ".1.3.6.1.4.1.9.9.91.1.2.1.1",
            [
                OID_END,
                4,  # Thresholds
            ],
        ),
    ],
}
