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

from os.path import join, exists
import hashlib

from tsfpga.system_utils import create_file, delete
from tsfpga.vivado_project import VivadoProject


class VivadoIpCores:

    """
    Handle a list of IP core sources. Has a mechanism to detect whether a regenerate of IP files is needed.
    """

    _project_name = "vivado_ip_project"

    def __init__(self, modules, project_path, part_name="xc7z020clg400-1"):
        self._project_folder = join(project_path, self._project_name)
        self._part_name = part_name
        self._hash_file = join(self._project_folder, "ip_files_hash.txt")

        self._setup(modules)

    @property
    def compile_order_file(self):
        """
        Path to the generated compile order file.
        """
        return join(self._project_folder, "compile_order.txt")

    @property
    def vivado_project_sources_directory(self):
        """
        Path to the "sources" directory of the Vivado project.
        """
        return join(self._project_folder, "vivado_ip_project.srcs", "sources_1")

    @property
    def vivado_project_file(self):
        """
        Path to the Vivado project file.
        """
        return self._vivado_project.project_file(self._project_folder)

    def create_vivado_project(self):
        """
        Create IP core Vivado project.
        """
        print(f"Creating IP core project in {self._project_folder}")
        delete(self._project_folder)
        self._vivado_project.create(self._project_folder)
        self._save_hash()

    def create_vivado_project_if_needed(self):
        """
        Create IP core Vivado project if anything has changed since last time this was run.
        """
        if self._should_create():
            self.create_vivado_project()
            return True

        return False

    def _setup(self, modules):
        ip_tcl_files = []
        for module in modules:
            ip_tcl_files += module.get_ip_core_files()

        self._vivado_project = VivadoProject(
            name=self._project_name,
            modules=[],
            part=self._part_name,
            tcl_sources=ip_tcl_files
        )

        self._hash = self._calculate_hash(ip_tcl_files)

    @staticmethod
    def _calculate_hash(files):
        ip_hash = hashlib.md5()
        for file in files:
            ip_hash.update(file.encode())
            with open(file) as file_handle:
                ip_hash.update(file_handle.read().encode())

        return ip_hash.hexdigest()

    def _save_hash(self):
        create_file(self._hash_file, self._hash)

    def _should_create(self):
        """
        Return True if a Vivado project create is needed, i.e. if anything has changed.
        """
        if not (exists(self._hash_file) and exists(self.compile_order_file)):
            return True

        with open(self._hash_file) as file_handle:
            saved_hash = file_handle.read()
        if saved_hash != self._hash:
            return True

        return False
