# ------------------------------------------------------------------------------
# Copyright (c) Lukas Vik. All rights reserved.
# ------------------------------------------------------------------------------

import re


class UtilizationParser():

    """
    Used for parsing the utilization report generated by Vivado
    """

    @staticmethod
    def get_size(report):
        """
        Takes a hierarchical utilization report as a string and returns the top level size
        for the specified run.

        Args:
            report (string): A string containing the entire Vivado hierarchical utilization report.
        """
        result = dict()
        lines = report.split("\n")
        for idx, line in enumerate(lines):
            # Find the table line that is the top level
            if re.search(r"\(top\)", line):
                # Parse the report, remove uninteresting fields and create dictionary
                # Note that "|" is the column separator. Heading titles for the data is two lines above
                # the row for the top level.
                headers = [column_data.strip() for column_data in lines[idx - 2].split("|")]
                numbers = [column_data.strip() for column_data in line.split("|")]
                # The first columns contain entity name, etc. We only want the numbers
                headers = headers[3:-1]
                numbers = numbers[3:-1]
                # Convert numbers from string to integers
                numbers = [int(number) for number in numbers]
                result = dict(zip(headers, numbers))
                break

        return result


class LessThan:

    """
    Limit to be used with a checker to see that a resource number is less than the
    specified value.
    """

    def __init__(self, value):
        """
        Args:
            value (int): The result size value shall be less than this.
        """
        self.value = value

    def check(self, result_value):
        return result_value < self.value

    def __str__(self):
        return f"< {self.value}"


class EqualTo:

    """
    Limit to be used with a checker to see that a resource number is equal to the
    specified value.
    """

    def __init__(self, value):
        """
        Args:
            value (int): The result size value shall be equal to this.
        """
        self.value = value

    def check(self, result_value):
        return result_value == self.value

    def __str__(self):
        return str(self.value)


class SizeChecker:

    """
    Check a build result size value against a limit.

    Overload and set the correct ``resource_name``, according to the names
    in the vendor utilization report.
    """

    resource_name = ""

    def __init__(self, limit):
        """
        Args:
            limit: The limit that the specified resource shall be checked against. Should
                be e.g. a :class:`LessThan` object.
        """
        self.limit = limit

    def check(self, result_size):
        """
        Args:
            result_size (dict): A size dictionary as found in the :class:`.BuildResult`
                object.
        """
        result_value = result_size[self.resource_name]
        if self.limit.check(result_value):
            message = f"Result size check passed for {self.resource_name}: "\
                f"{result_value} ({self.limit})"
            print(message)
            return True

        message = f"Result size check failed for {self.resource_name}. "\
            f"Got {result_value}, expected {self.limit}."
        print(message)
        return False


class TotalLuts(SizeChecker):

    resource_name = "Total LUTs"


class LogicLuts(SizeChecker):

    resource_name = "Logic LUTs"


class Dsp48Blocks(SizeChecker):

    resource_name = "DSP48 Blocks"


class Ffs(SizeChecker):

    resource_name = "FFs"


class Ramb36(SizeChecker):

    resource_name = "RAMB36"


class Ramb18(SizeChecker):

    resource_name = "RAMB18"
