#!/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.poe import *  # pylint: disable=wildcard-import,unused-wildcard-import

# Maps poe power status to faulty status detail string.
# See tpPoePowerStatus in TPLINK-POWER-OVER-ETHERNET-MIB
poe_faulty_status_to_string = {
    "3": "overload",
    "4": "short",
    "5": "nonstandard-pd",
    "6": "voltage-high",
    "7": "voltage-low",
    "8": "hardware-fault",
    "9": "overtemperature",
}


def _deci_watt_to_watt(deci_watt):
    """Convert from deci watt to watt"""
    return float(deci_watt) / 10


def parse_tplink_poe(info):
    """
    parse info data and create dictionary with namedtuples for each item.

    {
       item : PoeData(poe_max, poe_used, pse_op_status)
    }

    :param info: parsed snmp data
    :return: dictionary
    """
    interface_list, poe_info = info

    poe_dict = {}
    for port_index, poe_port_status, poe_max, poe_used, poe_power_status in poe_info:
        try:
            # port_index is the 1 based port number not the interface index.
            # But we can use this number to index the list of interfaces.
            interface_index = int(port_index) - 1
            item = interface_list[interface_index][0]
            poe_status = PoeStatus.FAULTY
            poe_status_detail = None

            if poe_port_status == "1":
                # poe feature enabled for port
                if poe_power_status == "0":  # status: off
                    poe_status = PoeStatus.OFF
                elif poe_power_status == "1":  # status: turning-on
                    poe_status = PoeStatus.OFF
                elif poe_power_status == "2":  # status: on
                    poe_status = PoeStatus.ON
                else:
                    # Some faulty status. Try to map status detail string
                    poe_status_detail = poe_faulty_status_to_string.get(poe_power_status, None)
            else:
                # poe feature disabled for port
                continue

            poe_dict[item] = PoeValues(
                poe_max=_deci_watt_to_watt(poe_max),
                poe_used=_deci_watt_to_watt(poe_used),
                poe_status=poe_status,
                poe_status_detail=poe_status_detail,
            )
        except (ValueError, IndexError):
            pass
    return poe_dict


def inventory_tplink_poe(parsed):
    return [(item, {}) for item in parsed]


@get_parsed_item_data
def check_tplink_poe(item, params, poe_data):
    return check_poe_data(params, poe_data)


check_info["tplink_poe"] = {
    "parse_function": parse_tplink_poe,
    "check_function": check_tplink_poe,
    "inventory_function": inventory_tplink_poe,
    "service_description": "POE%s consumption",
    "has_perfdata": True,
    "snmp_info": [
        (".1.3.6.1.2.1.2.2.1", ["1"]),
        (".1.3.6.1.4.1.11863.6.56.1.1.2.1.1", ["1", "2", "4", "7", "11"]),
    ],
    "snmp_scan_function": lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.11863.5"),
}
