#!/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.

# snmp_scan_function
# .1.3.6.1.2.1.1.1.0 = "AirLaser IP1000"  < matches airlaser
# .1.3.6.1.4.1.2800.2.1.1.0 3             < Version of management agent ( exists )
# snmp_info
# .1.3.6.1.4.1.2800.2.1.3                 < AirLaser Status

# Migrate to factory settings?
airlaser_default_levels = {
    "opttxTempValue": (60, 80),
    "chassisTempValue": (60, 70),
    "chassisFrontScreenTempValue": (40, 55),
    "optrxTempValue": (50, 60),
    "apmodTempValue": (60, 70),
}


def parse_cbl_airlaser(info):

    airlaser_status_names = {
        0: "undefined",
        1: "active",
        2: "standby",
        3: "warning",
        4: "failure",
        5: "not_installed",
    }

    # I have my own little MIB right here, their MIB is
    # just a long list, not structured.
    airlaser_sensors = {
        "chassis": {
            # Name of OID,    Value,    specific OID (not used), Position in SNMP data
            "chassisFrontScreenTempStatus": (None, "2.1.1.0", 0),
            "chassisFrontScreenTempValue": (None, "2.1.2.0", 1),
            "chassisHeatingStatus": (None, "2.1.7.0", 6),
            "chassisTempStatus": (None, "2.1.8.0", 7),
            "chassisTempValue": (None, "2.1.9.0", 8),
            "chassisFan1Status": (None, "2.1.10.0", 9),
            "chassisFan2Status": (None, "2.1.12.0", 11),
        },
        "power": {
            "psStatus48V": (None, "2.2.2.0", 1),
            "psStatus230V": (None, "2.2.3.0", 2),
            "psStatus5V": (None, "2.2.4.0", 3),
            "psStatus3V3": (None, "2.2.8.0", 7),
            "psStatus2V5": (None, "2.2.12.0", 11),
        },
        "module": {
            "apmodTempStatus": (None, "2.3.6.0", 5),
            "apmodTempValue": (None, "2.3.7.0", 6),
        },
        "opttx": {
            "opttxTempValue": (None, "2.4.3.0", 2),
            "opttxStatusTemp": (None, "2.4.4.0", 3),
        },
        "optrx": {
            "optrxStatusTemp": (None, "2.5.3.0", 2),
            # this is mislabeled "optrxValueTemp"
            "optrxTempValue": (None, "2.5.4.0", 3),
            # "optrxOptValue"
            # .1.3.6.1.4.1.2800.2.2.5.8.0  -10
            # "optrxOptMargin"
            # .1.3.6.1.4.1.2800.2.2.5.9.0  22
        },
    }

    # load the info into a dict separated by the different MIB regions
    # Selfest (info[0] is not handled here.
    data = {
        "chassis": info[1],
        "power": info[2],
        "module": info[3],
        "opttx": info[4],
        "optrx": info[5],
    }

    # update values from one dict into the other by picking the "offsetted" values
    # (optimize at will, if we can make it one-dict-for-all then we 100% sanitized their MIB)
    for hwclass, sensors in airlaser_sensors.items():
        for sensor in sensors:
            # we could remove the offset hack by parsing our OID
            sub_oid = sensors[sensor][1]
            offset = sensors[sensor][2]

            if "Status" in sensor:
                value = airlaser_status_names[int(data[hwclass][offset][0])]
            else:
                value = saveint(data[hwclass][offset][0])
            sensors[sensor] = (value, sub_oid, offset)

    return airlaser_sensors


def check_cbl_airlaser_hw(item, params, info):

    airlaser_info = parse_cbl_airlaser(info)

    state = 0
    msgtxt = ""
    perfdata = []

    for sensors in airlaser_info.values():
        for sensor, s in sensors.items():
            val = s[0]
            if sensor.lower().endswith("value"):
                val = saveint(val)
                if sensor in params:
                    warn, crit = params[sensor]
                    perfdata.append(("%s" % sensor, "%d" % val, warn, crit, 0, 90))
                    if val > crit:
                        state = max(state, 2)
                    elif val > warn:
                        state = max(state, 1)
                else:
                    # if this sensor wasn't in the params, then we don't alert on it.
                    perfdata.append(("%s" % sensor, "%d" % val, "", "", 0, 90))

            # HACK: for the main PSUs the status 3 is not "warning" but
            # not_detected  (3)
            if sensor in ["psStatus48V", "psStatus230V"] and val == "warning":
                state = max(state, 0)

            else:
                if val == "failure":
                    state = 2
                elif val == "warning":
                    state = max(state, 1)
                # go here if no explicit error occured,
                # no handling undefined and not_installed
                else:
                    continue
            if state > 0:
                msgtxt = msgtxt + "Sensor %s %s" % (sensor, val) + state * "!" + " "

    if state == 0:
        msgtxt = "All sensors OK"

    return (state, msgtxt, perfdata)


def inventory_cbl_airlaser(info):
    # start passing parameters, but since we might also need some for optics
    # this may change to using factory settings.
    # Or we just hardcode the margins we got from the vendor.
    return [(None, "airlaser_default_levels")]


def check_cbl_airlaser_status(item, _no_params, info):
    if len(info) == 0:
        return (3, "no information sent by agent")

    selftest, _chassis, _power, _module, _optrx, _opttx = info
    status = selftest[0][0]

    if status == "1":
        return (0, "Airlaser: normal operation")
    elif status == "2":
        return (1, "Airlaser: testing mode")
    elif status == "3":
        return (1, "Airlaser: warning condition")
    elif status == "4":
        return (2, "Airlaser: a component has failed self-tests")

    return (3, "Unknown data from agent")


check_info["cbl_airlaser.status"] = {
    "check_function": check_cbl_airlaser_status,
    "inventory_function": inventory_cbl_airlaser,
    "service_description": "CBL Airlaser Status",
    "snmp_scan_function": lambda oid: "airlaser" in oid(".1.3.6.1.2.1.1.1.0").lower()
    and oid(".1.3.6.1.4.1.2800.2.1.1.0"),
    "snmp_info": [
        (".1.3.6.1.4.1.2800.2", ["1.3"]),
        (".1.3.6.1.4.1.2800.2.2", ["1"]),
        (".1.3.6.1.4.1.2800.2.2", ["2"]),
        (".1.3.6.1.4.1.2800.2.2", ["3"]),
        (".1.3.6.1.4.1.2800.2.2", ["4"]),
        (".1.3.6.1.4.1.2800.2.2", ["5"]),
    ],
}

check_info["cbl_airlaser.hardware"] = {
    "check_function": check_cbl_airlaser_hw,
    "inventory_function": inventory_cbl_airlaser,
    "service_description": "CBL Airlaser Hardware",
    "has_perfdata": True,
}
