#!/usr/bin/env python3

r"""
This module is the python counterpart to openbmc_ffdc.robot..
"""

import os

import gen_print as gp
import gen_valid as gv
import gen_robot_keyword as grk
import state as st

from robot.libraries.BuiltIn import BuiltIn

redfish_support_trans_state = int(os.environ.get('REDFISH_SUPPORT_TRANS_STATE', 0)) or \
    int(BuiltIn().get_variable_value("${REDFISH_SUPPORT_TRANS_STATE}", default=0))


def ffdc(ffdc_dir_path=None,
         ffdc_prefix=None,
         ffdc_function_list="",
         comm_check=True):
    r"""
    Gather First Failure Data Capture (FFDC).

    This includes:
    - Set global FFDC_TIME.
    - Create FFDC work space directory.
    - Write test info details.
    - Call BMC methods to write/collect FFDC data.

    Description of arguments:
    ffdc_dir_path                   The dir path where FFDC data should be put.
    ffdc_prefix                     The prefix to be given to each FFDC file name generated.
    ffdc_function_list              A colon-delimited list of all the types of FFDC data you wish to have
                                    collected.  A blank value means that all possible kinds of FFDC are to be
                                    collected.  See FFDC_METHOD_CALL object in lib/openbmc_ffdc_list.py for
                                    possible choices.
    comm_check                      Do a communications check prior to collecting FFDC.  If commincation to
                                    the BMC can't be established, abort the FFDC collection.
    """

    ffdc_file_list = []

    # Check if Ping and SSH connection is alive
    OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")

    if comm_check:
        if not redfish_support_trans_state:
            interface = 'rest'
        else:
            interface = 'redfish'

        state = st.get_state(req_states=['ping', 'uptime', interface])
        gp.qprint_var(state)
        if not int(state['ping']):
            gp.print_error("BMC is not ping-able.  Terminating FFDC collection.\n")
            return ffdc_file_list

        if not int(state[interface]):
            gp.print_error("%s commands to the BMC are failing." % interface)

        if state['uptime'] == "":
            gp.print_error("BMC is not communicating via ssh.\n")

        # If SSH and Redfish connection doesn't works, abort.
        if not int(state[interface]) and state['uptime'] == "":
            gp.print_error("BMC is not communicating via ssh or Redfish.  Terminating FFDC"
                           + " collection.\n")
            return ffdc_file_list

    gp.qprint_timen("Collecting FFDC.")

    # Get default values for arguments.
    ffdc_dir_path, ffdc_prefix = set_ffdc_defaults(ffdc_dir_path, ffdc_prefix)
    gp.qprint_var(ffdc_dir_path)
    gp.qprint_var(ffdc_prefix)

    # LOG_PREFIX is used by subordinate functions.
    LOG_PREFIX = ffdc_dir_path + ffdc_prefix
    BuiltIn().set_global_variable("${LOG_PREFIX}", LOG_PREFIX)

    cmd_buf = ["Create Directory", ffdc_dir_path]
    gp.qprint_issuing(cmd_buf)
    status, output = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
    if status != "PASS":
        error_message = gp.sprint_error_report("Create Directory failed"
                                               + " with the following"
                                               + " error:\n" + output)
        BuiltIn().fail(error_message)

    # FFDC_FILE_PATH is used by Header Message.
    FFDC_FILE_PATH = ffdc_dir_path + ffdc_prefix + "BMC_general.txt"
    BuiltIn().set_global_variable("${FFDC_FILE_PATH}", FFDC_FILE_PATH)

    status, ffdc_file_list = grk.run_key_u("Header Message")
    status, ffdc_file_sub_list = \
        grk.run_key_u("Call FFDC Methods  ffdc_function_list="
                      + ffdc_function_list)

    # Combine lists, remove duplicates and sort.
    ffdc_file_list = sorted(set(ffdc_file_list + ffdc_file_sub_list))

    gp.qprint_timen("Finished collecting FFDC.")

    return ffdc_file_list


def set_ffdc_defaults(ffdc_dir_path=None,
                      ffdc_prefix=None):
    r"""
    Set a default value for ffdc_dir_path and ffdc_prefix if they don't
    already have values.  Return both values.

    Description of arguments:
    ffdc_dir_path  The dir path where FFDC data should be put.
    ffdc_prefix    The prefix to be given to each FFDC file name generated.

    NOTE: If global variable ffdc_dir_path_style is set to ${1}, this function
    will create default values in a newer way.  Otherwise, its behavior
    will remain unchanged.
    """

    # Note: Several subordinate functions like 'Get Test Dir and Name' and
    # 'Header Message' expect global variable FFDC_TIME to be set.
    cmd_buf = ["Get Current Time Stamp"]
    gp.dprint_issuing(cmd_buf)
    FFDC_TIME = BuiltIn().run_keyword(*cmd_buf)
    BuiltIn().set_global_variable("${FFDC_TIME}", FFDC_TIME)

    ffdc_dir_path_style = BuiltIn().get_variable_value(
        "${ffdc_dir_path_style}")

    if ffdc_dir_path is None:
        if ffdc_dir_path_style:
            try:
                ffdc_dir_path = os.environ['FFDC_DIR_PATH']
            except KeyError:
                ffdc_dir_path = os.path.dirname(
                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
        else:
            FFDC_LOG_PATH = os.getcwd() + "/logs/"
            if FFDC_LOG_PATH is None:
                FFDC_LOG_PATH = ""
            if FFDC_LOG_PATH == "":
                FFDC_LOG_PATH = os.path.dirname(
                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
            error_message = gv.valid_value(FFDC_LOG_PATH,
                                           var_name="FFDC_LOG_PATH")
            if error_message != "":
                error_message = gp.sprint_error_report(error_message)
                BuiltIn().fail(error_message)
            FFDC_LOG_PATH = os.path.normpath(FFDC_LOG_PATH) + os.sep

            cmd_buf = ["Get Test Dir and Name"]
            gp.print_issuing(cmd_buf)
            suitename, testname = BuiltIn().run_keyword(*cmd_buf)

            ffdc_dir_path = FFDC_LOG_PATH + suitename + "/" + testname + "/"

    # Add trailing slash.
    ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep

    if ffdc_prefix is None:
        FFDC_TIME = BuiltIn().get_variable_value("${FFDC_TIME}")
        if ffdc_prefix is None:
            if ffdc_dir_path_style:
                OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")
                OPENBMC_NICKNAME = BuiltIn().get_variable_value(
                    "${OPENBMC_NICKNAME}", default=OPENBMC_HOST)
                ffdc_prefix = OPENBMC_NICKNAME + "." + FFDC_TIME[2:8] + "." +\
                    FFDC_TIME[8:14] + "."
            else:
                ffdc_prefix = FFDC_TIME + "_"

    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
    BuiltIn().set_global_variable("${FFDC_PREFIX}", ffdc_prefix)

    return ffdc_dir_path, ffdc_prefix