#!/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-
# ails.  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 fritz_parse_info(info):
    data = {}
    for l in info:
        data[l[0]] = ' '.join(l[1:])
    return data

#
# Internet connection
#

def inventory_fritz_conn(info):
    data = fritz_parse_info(info)
    if 'NewConnectionStatus' in data \
       and 'NewExternalIPAddress' in data \
       and data.get('NewConnectionStatus') != 'Unconfigured':
        return [(None, {})]

fritz_conn_states = {
    'Connected':    0,
    'Connecting':   1,
    'Disconnected': 1,
    'Unconfigured': 1,
}

def check_fritz_conn(_unused, _no_params, info):
    if not info:
        return 3, 'Connection info is missing'
    data = fritz_parse_info(info)
    state_txt = data['NewConnectionStatus']
    nag_state = fritz_conn_states.get(state_txt)
    if nag_state is None:
        return 3, 'Got unhandled state output "%s"' % state_txt

    output = 'State: %s' % state_txt
    if state_txt == 'Connected':
        output += ', WAN IP Address: %s' % data['NewExternalIPAddress']

    last_err = data.get('NewLastConnectionError')
    if last_err and last_err != 'ERROR_NONE':
        output += ', Last Error: %s' % last_err

    perfdata = []
    if data.get('NewUptime'):
        conn_time = check_uptime_seconds({}, float(data['NewUptime']))
        output += ', %s' % conn_time[1]
        perfdata = conn_time[2]

    return nag_state, output, perfdata

check_info['fritz.conn'] = {
  "inventory_function"  : inventory_fritz_conn,
  "check_function"      : check_fritz_conn,
  "service_description" : "Connection",
  "includes"            : [ "uptime.include" ],
  "has_perfdata"        : True,
}


#
# Config
#

def inventory_fritz_config(info):
    data = fritz_parse_info(info)
    if 'NewDNSServer1' in data:
        return [(None, {})]

def check_fritz_config(_unused, _no_params, info):
    data = fritz_parse_info(info)

    output = []
    for label, key in [
            ('DNS-Server1', 'NewDNSServer1'),
            ('DNS-Server2', 'NewDNSServer2'),
            ('VoIP-DNS-Server1', 'NewVoipDNSServer1'),
            ('VoIP-DNS-Server2', 'NewVoipDNSServer2'),
            ('uPnP Config Enabled', 'NewUpnpControlEnabled'),
        ]:
        if key in data and data[key] != '0.0.0.0':
            output.append('%s: %s' % (label, data[key]))

    if not output:
        return 3, 'Configuration info is missing'

    return 0, ', '.join(output)

check_info['fritz.config'] = {
  "inventory_function"  : inventory_fritz_config,
  "check_function"      : check_fritz_config,
  "service_description" : "Configuration",
  "has_perfdata"        : False,
}

#
# WAN Interface Check
#

def fritz_wan_if_to_if64(data):
    if 'NewLinkStatus' not in data:
        oper_status = None
    elif data['NewLinkStatus'] == 'Up':
        oper_status = '1'
    else:
        oper_status = '2'

    return [
        # ifIndex, ifDescr, ifType, ifSpeed, ifOperStatus, ifInOctets, inucast,
        # inmcast, inbcast, ifInDiscards, ifInErrors, ifOutOctets, outucast,
        # outmcast, outbcast, ifOutDiscards, ifOutErrors, ifOutQLen, ifAlias, ifPhysAddress
        ('0', 'WAN', '6', data.get('NewLayer1DownstreamMaxBitRate'), oper_status,
         data.get('NewTotalBytesReceived'), '0', '0', '0', '0', '0',
         data.get('NewTotalBytesSent'),     '0', '0', '0', '0', '0', '0',
         'WAN', '')
    ]

def inventory_fritz_wan_if(info):
    data = fritz_parse_info(info)
    return inventory_if_common(fritz_wan_if_to_if64(data))

def check_fritz_wan_if(item, params, info):
    # TODO: This check modifies params!! This is strictly forbidden
    if not info:
        return 3, 'Interface info is missing'
    data = fritz_parse_info(info)
    if 'assumed_speed_in' not in params:
        params['assumed_speed_in'] = int(data['NewLayer1DownstreamMaxBitRate'])
    if 'assumed_speed_out' not in params:
        params['assumed_speed_out'] = int(data['NewLayer1UpstreamMaxBitRate'])
    if 'unit' not in params:
        params['unit'] = 'Bit'
    return check_if_common(item, params, fritz_wan_if_to_if64(data))

check_info["fritz.wan_if"] = {
    'check_function':          check_fritz_wan_if,
    'inventory_function':      inventory_fritz_wan_if,
    'service_description':     'Interface %s',
    'has_perfdata':            True,
    'group':                   'if',
    'default_levels_variable': 'if_default_levels',
    'includes':                [ 'if.include' ],
}

#
# Link
#

def inventory_fritz_link(info):
    data = fritz_parse_info(info)
    if 'NewLinkStatus' in data and 'NewPhysicalLinkStatus' in data:
        return [ (None, {}) ]

def check_fritz_link(_no_item, _no_params, info):
    data = fritz_parse_info(info)

    output = []
    for label, key in [
            ('Link Status',          'NewLinkStatus'),
            ('Physical Link Status', 'NewPhysicalLinkStatus'),
            ('Link Type',            'NewLinkType'),
            ('WAN Access Type',      'NewWANAccessType'),
        ]:
        if key in data:
            output.append('%s: %s' % (label, data[key]))

    if not output:
        return 3, 'Link info is missing'

    return 0, ', '.join(output)

check_info["fritz.link"] = {
    'check_function':          check_fritz_link,
    'inventory_function':      inventory_fritz_link,
    'service_description':     'Link Info',
    'has_perfdata':            False,
}
