#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2014             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software;  you can redistribute it and/or modify it
# under the  terms of the  GNU General Public License  as published by
# the Free Software Foundation in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.

# Example for output from agent
# ---------------------------------------------------------
#<<<mtr>>>
#www.google.com|1451237587|8|80.69.76.120|0.0%|10|39.2|7.0|0.3|39.2|14.2|80.249.209.100|0.0%|10|1.2|1.2|1.0|1.4|0.0|209.85.240.61|0.0%|10|1.4|1.6|1.2|2.4|0.0|209.85.248.247|0.0%|10|1.6|1.7|1.5|2.1|0.0|216.239.51.17|0.0%|10|4.8|5.0|4.7|5.3|0.0|216.239.49.36|0.0%|10|6.1|5.5|4.7|8.8|1.1|???|100.0|10|0.0|0.0|0.0|0.0|0.0|74.125.136.105|0.0%|10|4.7|5.0|4.7|5.4|0.0
# ---------------------------------------------------------

factory_settings["mtr_default_levels"] = {
    "pl": (10, 25),  # warn/crit for loss percentage
    "rta": (150, 250),  # warn/crit for average roundtrip time
    "rtstddev": (150, 250),  # warn/crit for standard deviation
}


def parse_mtr(info):
    hosts = {}
    for line in info:
        if line[0].startswith("**ERROR**"):
            continue

        ret = {'hops': {}}
        if not len(line) > 0:
            return ret
        hostname = line[0]
        ret['hostname'] = hostname
        ret['last_check'] = line[1]
        ret['hopcount'] = int(float(line[2]))
        rest = line[3:]

        if ret['hopcount'] > 0:
            for hopnum in range(0, ret['hopcount']):
                ret['hops'][hopnum + 1] = {
                    'hopname': rest[0 + 8 * hopnum],
                    'pl': rest[1 + 8 * hopnum].replace("%", "").rstrip(),
                    'snt': rest[2 + 8 * hopnum],
                    'response_time': rest[3 + 8 * hopnum],
                    'rta': rest[4 + 8 * hopnum],
                    'rtmin': rest[5 + 8 * hopnum],
                    'rtmax': rest[6 + 8 * hopnum],
                    'rtstddev': rest[7 + 8 * hopnum],
                }
        hosts[hostname] = ret
    return hosts


def inventory_mtr(parsed):
    for host in parsed.keys():
        yield host, {}


def _transform_mtr_params(p):
    if "avg" in p:
        p["rta"] = p.pop("avg")
    if "stddev" in p:
        p["rtstddev"] = p.pop("stddev")
    if "loss" in p:
        p["pl"] = p.pop("loss")
    return p


def check_mtr(item, params, parsed):
    hostinfo = parsed.get(item)
    if not hostinfo:
        return

    if hostinfo["hopcount"] == 0:
        yield 3, "Insufficient data: No hop information available"
        return

    params = _transform_mtr_params(params)

    hopnames = []
    perfdata = []
    hops = hostinfo['hops']

    def get_hop_info(hops, idx, apply_levels=False):
        if apply_levels:
            pl_warn, pl_crit = params["pl"]
            rta_warn, rta_crit = params["rta"]
            rtstddev_warn, rtstddev_crit = params["rtstddev"]
        else:
            pl_warn, pl_crit = None, None
            rta_warn, rta_crit = None, None
            rtstddev_warn, rtstddev_crit = None, None

        hop = hops[idx]
        hopnames.append(hop["hopname"])
        rta = float(hop['rta'])
        rtmin = float(hop['rtmin'])
        rtmax = float(hop['rtmax'])
        rtstddev = float(hop['rtstddev'])
        response_time = float(hop['response_time'])
        pl = float(hop['pl'])
        #        snt    = float(hop['snt'])
        #        perfdata.append( ( 'hop_%d_snt' % idx, snt, "", "", "", "" ) )  # packets sent
        perfdata.append(('hop_%d_rta' % idx, rta / 1000.0, rta_warn and
                         rta_warn / 1000.0, rta_crit and rta_crit / 1000.0))
        perfdata.append(('hop_%d_rtmin' % idx, rtmin / 1000.0))
        perfdata.append(('hop_%d_rtmax' % idx, rtmax / 1000.0))
        perfdata.append(('hop_%d_rtstddev' % idx, rtstddev / 1000.0, rtstddev_warn and
                         rtstddev_warn / 1000.0, rtstddev_crit and rtstddev_crit / 1000.0))
        perfdata.append(('hop_%d_response_time' % idx, response_time / 1000.0))
        perfdata.append(('hop_%d_pl' % idx, pl, pl_warn, pl_crit))

        if apply_levels:  # the params only apply to the last host
            hop_text_entries = []
            hop_states = []
            for what, unit, value, warn, crit in [
                ("Packet loss", "%", pl, pl_warn, pl_crit),
                ("Round trip average", "ms", rta, rta_warn, rta_crit),
                ("Standard deviation", "ms", rtstddev, rtstddev_warn, rtstddev_crit),
            ]:
                what_state = 0
                hop_text = ""
                if value >= crit:
                    what_state = 2
                elif value >= warn:
                    what_state = 1
                hop_text = "%s %s%s%s" % (what, value, unit,
                                          what_state and state_markers[what_state] or "")
                if what_state:
                    hop_text += " (warn/crit at %d%s/%d%s)" % (warn, unit, crit, unit)
                hop_text_entries.append(hop_text)
                hop_states.append(what_state)

            return max(hop_states), ", ".join(hop_text_entries), perfdata
        return None, None, perfdata

    hc = int(hostinfo['hopcount'])
    hop_perfdata = [('hops', hc)]

    def format_hopnames(hopnames):
        result = "Hops in last check:\n"
        for idx, name in enumerate(hopnames):
            result += "Hop %d: %s\n" % (idx + 1, name)
        return result

    for idx in range(0, hc):
        state, text, perfdata = get_hop_info(hops, idx + 1, apply_levels=(idx + 1 == hc))
        if state is None:
            # This is perfdata from a hop, we do not yield it yet (looks ugly..)
            hop_perfdata.extend(perfdata)
        else:
            # Last hop with state, text and perfdata. Yield everything we have
            yield 0, "Number of Hops: %d" % hc, hop_perfdata
            yield state, text + "\r\n%s" % format_hopnames(hopnames), perfdata


check_info['mtr'] = {
    "parse_function": parse_mtr,
    "check_function": check_mtr,
    "inventory_function": inventory_mtr,
    "service_description": "Mtr to %s",
    "has_perfdata": True,
    "group": "mtr",
    "default_levels_variable": "mtr_default_levels",
}
