"""
Configure a Pacemaker/Corosync cluster with PCS
===============================================

Configure Pacemaker/Cororsync clusters with the
Pacemaker/Cororsync conifguration system (PCS)

:depends: pcs

.. versionadded:: 2016.3.0
"""


import logging

import salt.utils.path

log = logging.getLogger(__name__)


def __virtual__():
    """
    Only load if pcs package is installed
    """
    if salt.utils.path.which("pcs"):
        return "pcs"
    return (False, "Missing dependency: pcs")


def __use_new_commands():
    """
    The command line arguments of pcs changed after version 0.10
    This will return True if the new arguments are needed and
    false if the old ones are needed
    """
    pcs_version = __salt__["pkg.version"]("pcs")
    log.debug("PCS package version %s", pcs_version)

    if __salt__["pkg.version_cmp"](pcs_version, "0.10") == 1:
        log.debug("New version, new command")
        return True
    else:
        log.debug("Old Version")
        return False


def item_show(
    item, item_id=None, item_type=None, show="show", extra_args=None, cibfile=None
):
    """
    Show an item via pcs command
    (mainly for use with the pcs state module)

    item
        config, property, resource, constraint etc.
    item_id
        id of the item
    item_type
        item type
    show
        show command (probably None, default: show or status for newer implementation)
    extra_args
        additional options for the pcs command
    cibfile
        use cibfile instead of the live CIB
    """

    new_commands = __use_new_commands()

    cmd = ["pcs"]

    if isinstance(cibfile, str):
        cmd += ["-f", cibfile]

    if isinstance(item, str):
        cmd += [item]
    elif isinstance(item, (list, tuple)):
        cmd += item

    # constraint command follows a different order
    if item in ["constraint"]:
        cmd += [item_type]

    # New implementions use config instead of show. This resolves that issue.
    if new_commands and (
        item != "config" and item != "constraint" and item != "property"
    ):
        if show == "show":
            show = "config"
        elif isinstance(show, (list, tuple)):
            for index, value in enumerate(show):
                if show[index] == "show":
                    show[index] = "config"

    if isinstance(show, str):
        cmd += [show]
    elif isinstance(show, (list, tuple)):
        cmd += show

    if isinstance(item_id, str):
        cmd += [item_id]

    if isinstance(extra_args, (list, tuple)):
        cmd += extra_args

    # constraint command only shows id, when using '--full'-parameter
    if item in ["constraint"]:
        if not isinstance(extra_args, (list, tuple)) or "--full" not in extra_args:
            cmd += ["--full"]
    log.debug("Running item show %s", cmd)
    return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)


def item_create(
    item, item_id, item_type, create="create", extra_args=None, cibfile=None
):
    """
    Create an item via pcs command
    (mainly for use with the pcs state module)

    item
        config, property, resource, constraint etc.
    item_id
        id of the item
    item_type
        item type
    create
        create command (create or set f.e., default: create)
    extra_args
        additional options for the pcs command
    cibfile
        use cibfile instead of the live CIB
    """
    cmd = ["pcs"]
    if isinstance(cibfile, str):
        cmd += ["-f", cibfile]

    if isinstance(item, str):
        cmd += [item]
    elif isinstance(item, (list, tuple)):
        cmd += item

    # constraint command follows a different order
    if item in ["constraint"]:
        if isinstance(item_type, str):
            cmd += [item_type]

    if isinstance(create, str):
        cmd += [create]
    elif isinstance(create, (list, tuple)):
        cmd += create

    # constraint command needs item_id in format 'id=<id' after all params
    # constraint command follows a different order
    if item not in ["constraint"]:
        cmd += [item_id]
        if isinstance(item_type, str):
            cmd += [item_type]

    if isinstance(extra_args, (list, tuple)):
        # constraint command needs item_id in format 'id=<id' after all params
        if item in ["constraint"]:
            extra_args = extra_args + ["id={}".format(item_id)]
        cmd += extra_args

    return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)


def auth(nodes, pcsuser="hacluster", pcspasswd="hacluster", extra_args=None):
    """
    Authorize nodes to the cluster

    nodes
        a list of nodes which should be authorized to the cluster
    pcsuser
        user for communitcation with PCS (default: hacluster)
    pcspasswd
        password for pcsuser (default: hacluster)
    extra_args
        list of extra option for the \'pcs cluster auth\' command. The newer cluster host command has no extra args and so will ignore it.

    CLI Example:

    .. code-block:: bash

        salt '*' pcs.auth nodes='[ node1.example.org node2.example.org ]' pcsuser=hacluster pcspasswd=hoonetorg extra_args=[ '--force' ]
    """
    if __use_new_commands():
        cmd = ["pcs", "host", "auth"]
    else:
        cmd = ["pcs", "cluster", "auth"]

    cmd.extend(["-u", pcsuser, "-p", pcspasswd])

    if not __use_new_commands() and isinstance(extra_args, (list, tuple)):
        cmd += extra_args

    cmd += nodes

    return __salt__["cmd.run_all"](cmd, output_loglevel="trace", python_shell=False)


def is_auth(nodes, pcsuser="hacluster", pcspasswd="hacluster"):
    """
    Check if nodes are already authorized

    nodes
        a list of nodes to be checked for authorization to the cluster
    pcsuser
        user for communitcation with PCS (default: hacluster)
    pcspasswd