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

from typing import Mapping, Optional

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

# 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

# Example output from agent:

# <<<allnet_ip_sensoric:sep(59)>>>
# sensor0.alarm0;0
# sensor0.all4000_typ;0
# sensor0.function;1
# sensor0.limit_high;50.00
# sensor0.limit_low;10.00
# sensor0.maximum;28.56
# sensor0.minimum;27.50
# sensor0.name;Temperatur intern
# sensor0.value_float;27.50
# sensor0.value_int;2750
# sensor0.value_string;27.50
# sensor1.alarm1;0
# sensor1.all4000_typ;0
# sensor1.function;3
# sensor1.limit_high;50.00
# sensor1.limit_low;-0.50
# sensor1.maximum;0.00
# sensor1.minimum;2048000.00
# sensor1.name;ADC 0
# sensor1.value_float;0.00
# sensor1.value_int;0
# sensor1.value_string;0.00
# [...]
# sensor9.alarm9;1
# sensor9.all4000_typ;101
# sensor9.function;12
# sensor9.limit_high;85.00
# sensor9.limit_low;10.00
# sensor9.maximum;100.00
# sensor9.minimum;2048000.02
# sensor9.name;USV Spannung
# sensor9.value_float;100.00
# sensor9.value_int;100
# sensor9.value_string;100
# system.alarmcount;4
# system.date;30.06.2014
# system.devicename;all5000
# system.devicetype;ALL5000
# system.sys;114854
# system.time;16:08:48

# no idea why we need this.
_FIXUP_ENCODING = (("°".encode("utf-8").decode("latin-1"), "°"),)


def parse_allnet_ip_sensoric(info):
    """parses agent output in a structure like:
    {'sensor0': {'alarm0': '0',
              'all4000_typ': '0',
              'function': '1',
              'limit_high': '50.00',
              'limit_low': '10.00',
              'maximum': '28.56',
              'minimum': '27.43',
              'name': 'Temperatur intern',
              'value_float': '27.50',
              'value_int': '2750',
              'value_string': '27.50'},
    [...]
    'system': {'alarmcount': '4',
             'date': '30.06.2014',
             'devicename': 'all5000',
             'devicetype': 'ALL5000',
             'sys': '116240',
             'time': '16:57:50'}}
    """
    parsed = {}
    for key, value in info:
        match = re.search(r"(\w+)\.(\w+)", key)
        if not match:
            continue

        for wrong, right in _FIXUP_ENCODING:
            value = value.replace(wrong, right)
        sensor = match.group(1)
        field = match.group(2)
        parsed.setdefault(sensor, {})[field] = value

    return parsed


def allnet_ip_sensoric_compose_item(sensor_id, sensor):
    sensor_id = re.sub("sensor", "", sensor_id)
    if "name" in sensor:
        item = "%s Sensor %s" % (sensor["name"], sensor_id)
    else:
        item = "Sensor %s" % (sensor_id)
    return item


def _match_function_or_unit(
    sensor_data: Mapping[str, str], function: str, unit: Optional[str] = None
) -> bool:
    return sensor_data.get("function") == function or (
        unit is not None and sensor_data.get("unit") == unit
    )


#   .--el. tension---------------------------------------------------------.
#   |                  _     _                 _                           |
#   |              ___| |   | |_ ___ _ __  ___(_) ___  _ __                |
#   |             / _ \ |   | __/ _ \ '_ \/ __| |/ _ \| '_ \               |
#   |            |  __/ |_  | ||  __/ | | \__ \ | (_) | | | |              |
#   |             \___|_(_)  \__\___|_| |_|___/_|\___/|_| |_|              |
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_allnet_ip_sensoric_tension(parsed):
    return [
        (allnet_ip_sensoric_compose_item(sensor, sensor_data), None)
        for sensor, sensor_data in parsed.items()
        if _match_function_or_unit(sensor_data, "12")
    ]


def check_allnet_ip_sensoric_tension(item, _no_params, parsed):
    sensor_id = "sensor" + re.sub(".+Sensor ", "", item)

    if sensor_id not in parsed:
        return 3, "%s not found in agent output" % item

    value = float(parsed[sensor_id]["value_float"])

    perfdata = [("tension", value, None, None, 0, 100)]

    status = 0
    if value == 0:
        status = 2

    return status, "%d%% of the normal level" % value, perfdata


check_info["allnet_ip_sensoric.tension"] = {
    "check_function": check_allnet_ip_sensoric_tension,
    "inventory_function": inventory_allnet_ip_sensoric_tension,
    "service_description": "Electric Tension %s",
    "has_perfdata": True,
}

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

factory_settings["allnet_ip_sensoric_temp_default_levels"] = {"levels": (35, 40)}


def inventory_allnet_ip_sensoric_temp(parsed):
    return [
        (allnet_ip_sensoric_compose_item(sensor, sensor_data), {})
        for sensor, sensor_data in parsed.items()
        if _match_function_or_unit(sensor_data, "1", "°C")
    ]


def check_allnet_ip_sensoric_temp(item, params, parsed):
    sensor_id = "sensor" + re.sub(".+Sensor ", "", item)

    if sensor_id not in parsed:
        return 3, "Sensor not found in agent output"

    temp = float(parsed[sensor_id]["value_float"])

    return check_temperature(temp, params, "allnet_ip_sensoric_temp_%s" % item)


check_info["allnet_ip_sensoric.temp"] = {
    "check_function": check_allnet_ip_sensoric_temp,
    "inventory_function": inventory_allnet_ip_sensoric_temp,
    "service_description": "Temperature %s",
    "has_perfdata": True,
    "group": "temperature",
    "default_levels_variable": "allnet_ip_sensoric_temp_default_levels",
}

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

allnet_ip_sensoric_humidity_default_levels = (35, 40, 60, 65)


def inventory_allnet_ip_sensoric_humidity(parsed):
    return [
        (
            allnet_ip_sensoric_compose_item(sensor, sensor_data),
            "allnet_ip_sensoric_humidity_default_levels",
        )
        for sensor, sensor_data in parsed.items()
        if _match_function_or_unit(sensor_data, "2", "%")
    ]


def check_allnet_ip_sensoric_humidity(item, params, parsed):
    sensor_id = "sensor" + re.sub(".+Sensor ", "", item)
    if sensor_id not in parsed:
        return 3, "%s not found in agent output" % item

    return check_humidity(float(parsed[sensor_id]["value_float"]), params)


check_info["allnet_ip_sensoric.humidity"] = {
    "check_function": check_allnet_ip_sensoric_humidity,
    "inventory_function": inventory_allnet_ip_sensoric_humidity,
    "service_description": "Humidity %s",
    "has_perfdata": True,
    "group": "humidity",
}

# .
#   .--pressure------------------------------------------------------------.
#   |                                                                      |
#   |               _ __  _ __ ___  ___ ___ _   _ _ __ ___                 |
#   |              | '_ \| '__/ _ \/ __/ __| | | | '__/ _ \                |
#   |              | |_) | | |  __/\__ \__ \ |_| | | |  __/                |
#   |              | .__/|_|  \___||___/___/\__,_|_|  \___|                |
#   |              |_|                                                     |
#   '----------------------------------------------------------------------'


def inventory_allnet_ip_sensoric_pressure(parsed):
    return [
        (allnet_ip_sensoric_compose_item(sensor, sensor_data), None)
        for sensor, sensor_data in parsed.items()
        if _match_function_or_unit(sensor_data, "16", "hpa")
    ]


def check_allnet_ip_sensoric_pressure(item, _no_params, parsed):
    sensor_id = "sensor" + re.sub(".+Sensor ", "", item)

    if sensor_id not in parsed:
        return 3, "%s not found in agent output" % item

    pressure = float(parsed[sensor_id]["value_float"]) / 1000

    perfdata = [("pressure", str(pressure) + "bars", None, None, 0)]

    return 0, "%0.5f bar" % pressure, perfdata


check_info["allnet_ip_sensoric.pressure"] = {
    "check_function": check_allnet_ip_sensoric_pressure,
    "inventory_function": inventory_allnet_ip_sensoric_pressure,
    "service_description": "Pressure %s",
    "has_perfdata": True,
}

# .

check_info["allnet_ip_sensoric"] = {
    "parse_function": parse_allnet_ip_sensoric,
}
