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

import copy


def _transform_check_http(params):
    if isinstance(params, dict):
        return params
    name, mode = copy.deepcopy(params)
    mode_name = 'cert' if "cert_days" in mode else 'url'

    transformed = {"name": name, "mode": (mode_name, mode)}
    # The proxy option has ben isolated in version 1.6.0i1
    proxy_address = mode.get("proxy")
    if proxy_address:
        proxy = transformed.setdefault("proxy", {"address": proxy_address})
        # ':' outside a IPv6 address indicates port
        if ':' in proxy_address.split(']')[-1]:
            addr, port = proxy_address.rsplit(":", 1)
            try:
                proxy["port"] = int(port)
                proxy["address"] = addr
            except ValueError:
                pass  # leave address as it is
        if "proxy_auth" in mode:
            proxy["auth"] = mode["proxy_auth"]

    # The host options have ben isolated in version 1.6.0i1
    host_settings = transformed.setdefault("host", {})
    # URL mode:
    if "virthost" in mode:
        virthost, omit_ip = mode.pop("virthost")
        host_settings["virthost"] = virthost
        if omit_ip or proxy_address:
            host_settings["address"] = virthost
    # CERT mode:
    if "cert_host" in mode:
        host_settings["address"] = mode.pop("cert_host")
    # both modes:
    for key in ("port", "address_family"):
        if key in mode:
            host_settings[key] = mode.pop(key)

    mode.pop("sni", None)

    return transformed


def _get_host(params):
    # Use the address family of the monitored host by default
    host = params.get("host", {})

    family = host.get("address_family")
    if family is None:
        family = "ipv6" if is_ipv6_primary(host_name()) else "ipv4"

    address = host.get("address")
    if address is None:
        address = "$_HOSTADDRESS_%s$" % family[-1]

    HostSettings = collections.namedtuple("HostSettings", ("address", "port", "family", "virtual"))
    return HostSettings(address, host.get("port"), family, host.get('virthost'))


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

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

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


def _certificate_args(host, proxy, settings):
    args = []

    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 proxy:
        args += ['--ssl', '-j', 'CONNECT']

    return args


def _url_args(host, _proxy, settings):
    args = []

    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 "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 "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 _server_address(host, proxy):
    if proxy:
        return proxy.address
    return host.address


def _host_name(host, proxy, params):
    if proxy and host.port:
        return '%s:%s' % (host.address, host.port)
    if proxy:
        return host.address
    if host.virtual:
        return host.virtual
    if params['mode'][0] == 'cert':
        return host.address
    # Don't return the address in this case, because check_http would
    # automatically set the HTTP Host header and use HTTP/1.1 instead of
    # HTTP/1.0. This can lead to request timeouts on hosts which are
    # not compliant with HTTP/1.1.
    return None


def _common_args(host, proxy, params):
    args = []

    if host.family == 'ipv6':
        args += ['-6']
    if not params.get("disable_sni"):
        args += ['--sni']
    if proxy and proxy.auth:
        args += ["-b", proxy.auth]

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

    # last two arguments correspond to -I/-H, respectively
    args += [_server_address(host, proxy)]
    host_name = _host_name(host, proxy, params)
    if host_name:
        args += [host_name]

    return args


def check_http_arguments(params):
    params = _transform_check_http(params)

    mode_name, settings = params["mode"]

    host = _get_host(params)
    proxy = _get_proxy(params)

    if mode_name == 'cert':
        args = _certificate_args(host, proxy, settings)
    else:
        args = _url_args(host, proxy, settings)

    return args + _common_args(host, proxy, params)


def check_http_description(params):
    params = _transform_check_http(params)

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

    mode_name, settings = params["mode"]
    # here we have to cover connection and certificate checks
    if settings.get("ssl") or mode_name == "cert":
        return "HTTPS %s" % description
    return "HTTP %s" % description


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