#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
"""
This script provides common DV simulation specific utilities.
"""

import re
from collections import OrderedDict


# Capture the summary results as a list of lists.
# The text coverage report is passed as input to the function, in addition to
# the tool used. The tool returns a 2D list if the coverage report file was read
# and the coverage was extracted successfully. It returns a tuple of:
#   List of metrics and values
#   Final coverage total
#   Error message, if failed
def get_cov_summary_table(cov_report_txt, tool):
    try:
        with open(cov_report_txt, 'r') as f:
            if tool == 'xcelium':
                return xcelium_cov_summary_table(f)
            if tool == 'vcs':
                return vcs_cov_summary_table(f)

            err_msg = "Unsupported tool for cov extraction: {}".format(tool)
            return None, None, err_msg

    except Exception as e:
        err_msg = "Exception occurred: {}".format(str(e))
        return None, None, err_msg


# Same desc as above, but specific to Xcelium and takes an opened input stream.
def xcelium_cov_summary_table(buf):
    for line in buf:
        if "name" in line:
            # Strip the line and remove the unwanted "* Covered" string.
            metrics = line.strip().replace("* Covered", "").split()
            # Change first item to 'Score'.
            metrics[0] = 'Score'

            # metric.
            items = OrderedDict()
            for metric in metrics:
                items[metric] = {}
                items[metric]['covered'] = 0
                items[metric]['total'] = 0
            # Next line is a separator.
            line = buf.readline()
            # Subsequent lines are coverage items to be aggregated.
            for line in buf:
                line = re.sub(r"%\s+\(", "%(", line)
                values = line.strip().split()
                for i, value in enumerate(values):
                    value = value.strip()
                    m = re.search(r"\((\d+)/(\d+)\)", value)
                    if m:
                        items[metrics[i]]['covered'] += int(m.group(1))
                        items[metrics[i]]['total'] += int(m.group(2))
                        items['Score']['covered'] += int(m.group(1))
                        items['Score']['total'] += int(m.group(2))
            # Capture the percentages and the aggregate.
            values = []
            cov_total = None
            for metric in items.keys():
                if items[metric]['total'] == 0:
                    values.append("-- %")
                else:
                    value = items[metric]['covered'] / items[metric][
                        'total'] * 100
                    value = "{0:.2f} %".format(round(value, 2))
                    values.append(value)
                    if metric == 'Score':
                        cov_total = value
            return [metrics, values], cov_total, None

    # If we reached here, then we were unable to extract the coverage.
    err_msg = "ParseError: coverage data not found!"
    return None, None, err_msg


# Same desc as above, but specific to VCS and takes an opened input stream.
def vcs_cov_summary_table(buf):
    for line in buf:
        match = re.match("total coverage summary", line, re.IGNORECASE)
        if match:
            # Metrics on the next line.
            line = buf.readline().strip()
            metrics = line.split()
            # Values on the next.
            line = buf.readline().strip()
            # Pretty up the values - add % sign for ease of post
            # processing.
            values = []
            for val in line.split():
                val += " %"
                values.append(val)
            # first row is coverage total
            cov_total = values[0]
            return [metrics, values], cov_total, None

    # If we reached here, then we were unable to extract the coverage.
    err_msg = "ParseError: coverage data not found!"
    return None, None, err_msg
