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


def _clean_v4_address(chunks):
    return "%d.%d.%d.%d" % tuple(chunks)


def _clean_v6_address(chunks):
    ichunks = iter('%02x' % int(i) for i in chunks)
    blocks = ("%s%s" % pair for pair in zip(ichunks, ichunks))
    stripped_blocks = ('0' if b == '0000' else b.lstrip('0') for b in blocks)
    v6_string = ':'.join(b for b in stripped_blocks)

    # replace longest series of zeros
    for length in range(8, 0, -1):
        subs = ':'.join('0' * length)
        if subs in v6_string:
            shortened = v6_string.replace(subs, '', 1)
            if not shortened or shortened.startswith(':'):
                shortened = ':' + shortened
            if shortened.endswith(':'):
                shortened += ':'
            return '[%s]' % shortened
    return v6_string


def juniper_bgp_state_create_item(peering_entry):
    try:
        if len(peering_entry) == 4:
            return _clean_v4_address(peering_entry)
        elif len(peering_entry) == 16:
            return _clean_v6_address(peering_entry)
    except (ValueError, IndexError):
        pass
    return ' '.join('%02X' % int(i) for i in peering_entry)  # that's what has been in the data


def parse_juniper_bgp_state(info):
    bgp_state_map = {
        "0": "undefined",  # 0 does not exist
        "1": "idle",  # 1
        "2": "connect",  # 2
        "3": "active",  # 3
        "4": "opensent",  # 4
        "5": "openconfirm",  # 5
        "6": "established",  # 6
    }
    bgp_operational_state_map = {
        "0": "undefined",  # 0 does not exist
        "1": "halted",  # 1
        "2": "running"  # 2
    }
    parsed = {}
    for state, operational_state, peering_entry in info:
        item = juniper_bgp_state_create_item(peering_entry)
        state_txt = bgp_state_map.get(state.strip(), "undefined")
        operational_txt = bgp_operational_state_map.get(operational_state.strip(), "undefined")

        parsed[item] = {
            "state": state_txt,
            "operational_state": operational_txt,
        }
    return parsed


@get_parsed_item_data
def check_juniper_bgp_state(item, _no_params, data):
    state = data.get('state', "undefined")
    operational_state = data.get('operational_state', "undefined")

    status = {
        "established": 0,
        "undefined": 3,
    }.get(state, 2)
    # if we're halted, being un-established is fine
    yield status if operational_state == "running" else 0, \
        "Status with peer %s is %s" % (item, state)

    op_status = {
        "running": 0,
        "undefined": 3,
    }.get(operational_state, 1)
    yield op_status, "operational status: %s" % operational_state


check_info["juniper_bgp_state"] = {
    "parse_function": parse_juniper_bgp_state,
    "check_function": check_juniper_bgp_state,
    "inventory_function": discover(),
    "service_description": "BGP Status Peer %s",
    "snmp_info": (
        '.1.3.6.1.4.1.2636.5.1.1.2.1.1.1',
        [
            2,  # jnxBgpM2PeerState
            3,  # jnxBgpM2PeerStatus (like operational status)
            BINARY(11),  # jnxBgpM2PeerRemoteAddr
        ]),
    "snmp_scan_function": lambda oid: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.2636.1.1.1"
                                                                          ),
}
