#!/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 _is_certificate_check(settings):
    return "cert_days" in settings


def _get_family_and_address(settings):
    # Use the address family of the monitored host by default
    family = settings.get("address_family")
    if family is None:
        family = "ipv6" if is_ipv6_primary(host_name()) else "ipv4"

    if family == "ipv6":
        address = "$_HOSTADDRESS_6$"
    else:
        address = "$_HOSTADDRESS_4$"

    return family, address


def _get_proxy_setting(settings):
    """return proxys (address, port, auth) or None"""
    proxy = settings.get("proxy")
    if not proxy:
        return None

    # ':' outside a IPv6 address indicates port
    if ':' in proxy.split(']')[-1]:
        address, port = proxy.rsplit(':', 1)
    else:
        address, port = proxy, None

    auth = settings.get("proxy_auth")
    if auth:
        auth = passwordstore_get_cmdline("%s:%%s" % auth[0], auth[1])

    proset = collections.namedtuple("ProxySettings", ("address", "port", "auth"))
    return proset(address, port, auth)


def _certificate_args(address_family, address, settings):
    args = []

    server = settings.get('cert_host', address)

    if address_family == 'ipv6':
        args += ['-6']

    if "cert_days" in settings:
        # legacy behavior
        if isinstance(settings["cert_days"], int):
            args += ['-C', settings["cert_days"]]
        else:
            warn, crit = settings["cert_days"]
            args += ['-C', '%d,%d' % (warn, crit)]

    if "sni" in settings:
        args += ['--sni']

    proxy = _get_proxy_setting(settings)
    server_port = settings.get("port")

    specify_port = proxy.port if proxy else server_port
    if specify_port:
        args += ['-p', specify_port]

    if proxy:
        args += ['--ssl', '-j', 'CONNECT']
        if proxy.auth:
            args += ["-b", proxy.auth]
        args.append(proxy.address)
        if server_port:
            server += ':%s' % server_port

    elif settings.get("sni"):
        args += ['-H', server]

    args += [server]
    return args


def _url_args(address_family, address, settings):

    # get virthost settings:
    # TODO: when did 'vhost' dissapear from WATO?
    vhost, omit_ip = settings.get("virthost", (settings.get("vhost"), False))
    proxy = _get_proxy_setting(settings)

    args = []

    if proxy:
        args += ["-I", proxy.address]
    elif not omit_ip:
        args += ["-I", address]

    if vhost:
        args += ["-H", vhost]

    if address_family == 'ipv6':
        args += ['-6']

    # TODO: I think this should be overridden by the proxy port
    #       in the same way as in the cert check. (mo)
    if "port" in settings:
        args += ['-p', settings["port"]]

    if "uri" in settings:
        args += ['-u', settings["uri"]]

    ssl = settings.get("ssl")
    if ssl in [True, "auto"]:
        args += ['--ssl']
    elif ssl:
        args += ['--ssl=%s' % ssl]

    if "sni" in settings:
        args += ['--sni']

    if "response_time" in settings:
        args += [
            '-w',
            '%f' % (settings["response_time"][0] / 1000.0), '-c',
            '%f' % (settings["response_time"][1] / 1000.0)
        ]

    if "timeout" in settings:
        args += ['-t', settings["timeout"]]

    if "user_agent" in settings:
        args += ['-A', settings["user_agent"]]

    for header in settings.get("add_headers", []):
        args += ['-k', header]

    if "auth" in settings:
        username, password = settings["auth"]
        args += ["-a", passwordstore_get_cmdline("%s:%%s" % username, password)]

    if proxy and proxy.auth:
        args += ["-b", proxy.auth]

    if "onredirect" in settings:
        args += ['--onredirect=%s' % settings["onredirect"]]

    if "expect_response" in settings:
        args += ['-e', ",".join(settings["expect_response"])]

    if "expect_string" in settings:
        args += ['-s', settings["expect_string"]]

    if "expect_response_header" in settings:
        args += ['-d', settings["expect_response_header"]]

    if "expect_regex" in settings:
        if len(settings['expect_regex']) >= 4 and settings['expect_regex'][3]:
            args += ['-l']
        if settings['expect_regex'][1]:
            args += ['-R']
        else:
            args += ['-r']
        args += [settings['expect_regex'][0]]
        if settings['expect_regex'][2]:
            args += ['--invert-regex']

    if settings.get("extended_perfdata"):
        args += ['--extended-perfdata']

    if "post_data" in settings:
        data, content_type = settings["post_data"]
        args += ['-P', data, '-T', content_type]

    if "method" in settings:
        args += ['-j', settings["method"]]

    if settings.get("no_body"):
        args += ['--no-body']

    if "page_size" in settings:
        args += ['-m', '%d:%d' % settings["page_size"]]

    if "max_age" in settings:
        args += ['-M', settings["max_age"]]

    # FIXME: This option is deprecated. According to the monitoring-plugins
    # the "urlize" plugin should be used.
    if settings.get("urlize"):
        args += ['-L']

    return args


def check_http_arguments(params):
    _description, settings = params
    args = []

    address_family, address = _get_family_and_address(settings)

    if _is_certificate_check(settings):
        args += _certificate_args(address_family, address, settings)
    else:
        args += _url_args(address_family, address, settings)

    return args


def check_http_description(params):
    description, settings = params

    if description.startswith("^"):
        return description[1:]

    # here we have to cover connection and certificate checks
    if settings.get("ssl") or settings.get("cert_days"):
        protocol = "HTTPS"
    else:
        protocol = "HTTP"

    return "%s %s" % (protocol, description)


active_check_info['http'] = {
    "command_line": '$USER1$/check_http $ARG1$',
    "argument_function": check_http_arguments,
    "service_description": check_http_description,
    "has_perfdata": True,
}
