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

# Check has been developed using a Emerson Network Power Rack PDU Card
# Agent App Firmware Version  4.840.0
# Agent Boot Firmware Version 4.540.3
# FDM Version 1209
# GDD Version 45585

# Example info:
# [['10.1.1.1', '2'], ['10.1.2.1', '1'], ['10.1.3.1', '3'], ['10.1.3.2', '3'], ['15.1.1.1', 'SNSR: 1-1'], ['15.1.2.1', 'SNSR: 1-2'], ['15.1.3.1', 'SNSR: 1-3'], ['15.1.3.2', 'SNSR: 1-3'], ['20.1.1.1', 'RAD-LUNEPL-SEN7(80000000B080CF26)'], ['20.1.2.1', 'RAD-LUNEPL-SEN5(Rueckseite-oben)'], ['20.1.3.1', 'RAD-LUNEPL-SEN3(TuerRueckseite)'], ['20.1.3.2', 'RAD-LUNEPL-SEN1(TuerFront)'], ['25.1.1.1', ''], ['25.1.2.1', ''], ['25.1.3.1', ''], ['25.1.3.2', ''], ['30.1.1.1', ''], ['30.1.2.1', ''], ['30.1.3.1', ''], ['30.1.3.2', ''], ['35.1.1.1', '80000000B080CF26'], ['35.1.2.1', 'DD0000000DFAEA42'], ['35.1.3.1', 'EC00000013FBD820'], ['35.1.3.2', 'EC00000013FBD820'], ['40.1.2.1', '873'], ['50.1.2.1', '500'], ['55.1.2.1', '878'], ['60.1.2.1', '590'], ['65.1.2.1', '806'], ['70.1.2.1', '307'], ['75.1.2.1', '100'], ['80.1.2.1', '310'], ['85.1.2.1', '150'], ['90.1.2.1', '270'], ['95.1.1.1', '156'], ['100.1.1.1', '150'], ['105.1.1.1', '600'], ['110.1.1.1', '200'], ['115.1.1.1', '560'], ['120.1.3.1', '2'], ['120.1.3.2', '2'], ['125.1.3.1', '1'], ['125.1.3.2', '1']]

# Indexes in lgpPduAuxMeasTable are:
# 1. lgpPduEntryIndex
# 2. lgpPduAuxMeasSensorIndex
# 3. lgpPduAuxMeasSensorMeasurementIndex

#     10, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasType
#     15, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasSensorSysAssignLabel
#     20, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasUsrLabel
#     35, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasSensorSerialNum
#     70, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempDeg
#     75, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldUndrAlmDegC
#     80, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldOvrAlmDegC
#     85, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldUndrWarnDegC
#     90, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTempThrshldOvrWarnDegC
#     95, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHum
#    100, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldUndrAlm
#    105, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldOvrAlm
#    110, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldUndrWarn
#    115, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasHumThrshldOvrWarn
#    120, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasDrClosureState
#    125, # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasDrClosureConfig

lgp_pdu_aux_types = {
    "0": "UNSPEC",
    "1": "TEMP",
    "2": "HUM",
    "3": "DOOR",
    "4": "CONTACT",
}

lgp_pdu_aux_states = [
    "not-specified",
    "open",
    "closed",
]

_lgp_pdu_aux_fields = {
    # Index, Type, Factor, ID
    "10": (str, None, "Type"),
    "15": (str, None, "SystemLabel"),
    "20": (str, None, "UserLabel"),
    "35": (str, None, "SerialNumber"),
    "70": (savefloat, 0.1, "Temp"),
    "75": (savefloat, 0.1, "TempLowCrit"),
    "80": (savefloat, 0.1, "TempHighCrit"),
    "85": (savefloat, 0.1, "TempLowWarn"),
    "90": (savefloat, 0.1, "TempHighWarn"),
    "95": (savefloat, 0.1, "Hum"),
    "100": (savefloat, 0.1, "HumLowCrit"),
    "105": (savefloat, 0.1, "HumHighCrit"),
    "110": (savefloat, 0.1, "HumLowWarn"),
    "115": (savefloat, 0.1, "HumHighWarn"),
    "120": (saveint, None, "DoorState"),
    "125": (saveint, None, "DoorConfig"),
}


def lgp_pdu_aux_fmt(info):
    new_info = {}
    for oid, value in info:
        type_, id_ = oid.split(".", 1)
        if not id_ in new_info:
            new_info[id_] = {"TypeIndex": id_.split(".")[-1]}
        # Skip not handled rows
        if type_ in _lgp_pdu_aux_fields:
            ty, factor, key = _lgp_pdu_aux_fields[type_]

            if key == "Type":
                value = lgp_pdu_aux_types.get(value, "UNHANDLED")
            else:
                if factor:
                    value = ty(value) * factor
                else:
                    value = ty(value)

            new_info[id_][key] = value
    return new_info


def inventory_lgp_pdu_aux(info):
    info = lgp_pdu_aux_fmt(info)
    inv = []
    for pdu in info.values():
        # Using SystemLabel as index. But it is not uniq in all cases.
        # Adding the Type-Index to prevent problems
        inv.append((pdu["Type"] + "-" + pdu["SystemLabel"] + "-" + pdu["TypeIndex"], None))
    return inv


def check_lgp_pdu_aux(item, params, info):
    info = lgp_pdu_aux_fmt(info)
    for pdu in info.values():
        if item == pdu["Type"] + "-" + pdu["SystemLabel"] + "-" + pdu["TypeIndex"]:
            state = 0
            output = []
            perfdata = []

            if pdu["UserLabel"] != "":
                output.append("Label: %s (%s)" % (pdu["UserLabel"], pdu["SystemLabel"]))
            else:
                output.append("Label: " + pdu["SystemLabel"])

            def handle_type(ty, label, uom, pdu=pdu):
                state = 0
                perfdata = (
                    ty.lower(),
                    pdu[ty],
                    "%0.2f:%0.2f" % (pdu[ty + "LowWarn"], pdu[ty + "HighWarn"]),
                    "%0.2f:%0.2f" % (pdu[ty + "LowCrit"], pdu[ty + "HighCrit"]),
                )
                s_out = ""
                if pdu[ty] >= pdu[ty + "HighCrit"]:
                    state = 2
                    s_out = " >= %0.2f (!!)" % pdu[ty + "HighCrit"]
                elif pdu[ty] <= pdu[ty + "LowCrit"]:
                    state = 2
                    s_out = " <= %0.2f (!!)" % pdu[ty + "LowCrit"]
                elif pdu[ty] >= pdu[ty + "HighWarn"]:
                    state = 1
                    s_out = " >= %0.2f (!)" % pdu[ty + "HighWarn"]
                elif pdu[ty] <= pdu[ty + "LowWarn"]:
                    state = 1
                    s_out = " <= %0.2f (!)" % pdu[ty + "LowWarn"]

                return state, "%s: %0.2f%s%s" % (label, pdu[ty], uom, s_out), perfdata

            if pdu["Type"] == "TEMP":
                state, out, perf = handle_type("Temp", "Temperature", "C")
                output.append(out)
                perfdata.append(perf)

            elif pdu["Type"] == "HUM":
                state, out, perf = handle_type("Hum", "Humidity", "%")
                output.append(out)
                perfdata.append(perf)

            elif pdu["Type"] == "DOOR":
                # DoorConfig: 1 -> open, 0 -> disabled
                if pdu["DoorConfig"] == 1 and lgp_pdu_aux_states[pdu["DoorState"]] == "open":
                    state = 2
                    output.append("Door is %s (!!)" % lgp_pdu_aux_states[pdu["DoorState"]])
                else:
                    output.append("Door is %s" % lgp_pdu_aux_states[pdu["DoorState"]])

            return (state, ", ".join(output), perfdata)

    return (3, "Could not find given PDU.")


check_info["lgp_pdu_aux"] = (check_lgp_pdu_aux, "Liebert PDU AUX %s", 1, inventory_lgp_pdu_aux)

snmp_info["lgp_pdu_aux"] = (
    ".1.3.6.1.4.1.476.1.42.3.8.60.15",
    [
        OID_END,
        "1",  # LIEBERT-GP-PDU-MIB::lgpPduAuxMeasTable
    ],
)

snmp_scan_functions["lgp_pdu_aux"] = (
    lambda oid: oid(".1.3.6.1.2.1.1.2.0") == ".1.3.6.1.4.1.476.1.42"
)

# check_info["lgp_pdu_aux"] = {
#    "check_function"        : check_lgp_pdu_aux,
#    "inventory_function"    : inventory_lgp_pdu_aux,
#    "service_description"   : "Liebert PDU AUX %s",
#    "has_perfdata"          : True,
#    "snmp_scan_function"    : lambda oid: oid(".1.3.6.1.2.1.1.2.0") == \
#                                          ".1.3.6.1.4.1.476.1.42"
# }
