# Copyright 2024 Volvo Car Corporation
# Licensed under Apache 2.0.

# -*- coding: utf-8 -*-
"""Module containing classes for generating RTE dummy code.

These files are needed for building test SW,
where the RTE is not available.
For example, when running Silver tests.
"""

from powertrain_build.problem_logger import ProblemLogger

from pathlib import Path


class RteDummy(ProblemLogger):
    """A class for RTE dummy file generation."""

    def __init__(self, build_cfg, nvm_def):
        """Init.

        Args:
            build_cfg (BuildProjConfig): Object with build configuration settings.
            nvm_def (ZCNVMDef): Object with NVM definition information.
        """
        super().__init__()
        self.build_cfg = build_cfg
        self.nvm_def = nvm_def
        self.header_file_name = "Rte_Type"
        self.source_file_name = "Rte_Dummy"
        nvm_port_pattern = self.build_cfg.get_composition_config("nvmPortPattern")
        if nvm_port_pattern is None:
            nvm_port_pattern = "{NvName}"
        self.nvm_port_pattern = nvm_port_pattern

    def _get_header_header(self):
        """Get header for the RTE dummy header."""
        include_nvm_header = ""
        if not self.build_cfg.get_code_generation_config("useRteNvmStructs"):
            nvm_defs = self.build_cfg.get_nvm_defs()
            nvm_file_name = nvm_defs["fileName"]
            include_nvm_header = f'#include "{nvm_file_name}.h"\n'
        return (
            "/*\n"
            " * This file is generated by the Powertrain Build System.\n"
            " * It defines RTE dummy types.\n"
            " * Do not modify this file manually.\n"
            " */\n"
            f"#ifndef {self.header_file_name.upper()}_H\n"
            f"#define {self.header_file_name.upper()}_H\n\n"
            '#include "tl_basetypes.h"\n'
            f"{include_nvm_header}\n"
            "#define FALSE 0U\n"
            "#define TRUE 1U\n\n"
        )

    def _get_header_footer(self):
        """Get footer for the RTE dummy header."""
        return f"\n#endif /* {self.header_file_name.upper()}_H */\n"

    def _get_source_header(self):
        """Get header for the RTE dummy source."""
        return (
            "/*\n"
            " * This file is generated by the Powertrain Build System.\n"
            " * It defines RTE dummy functions.\n"
            " * Do not modify this file manually.\n"
            " */\n"
            f'#include "{self.header_file_name}.h"\n\n'
        )

    def _get_nvm_header_dummy(self):
        """Get NVM dummy header code."""
        typedefs = []
        struct_defines = []
        function_declarations = []
        include_name = self.build_cfg.get_composition_config("softwareComponentName")
        function_name = self.build_cfg.get_composition_config("compositionName")
        if function_name is None:
            function_name = include_name
        prefix = self.build_cfg.get_scheduler_prefix()
        use_rte_nvm_structs = self.build_cfg.get_code_generation_config("useRteNvmStructs")

        if self.build_cfg.get_code_generation_config("generateRteCheckpointIds"):
            typedefs.append(f"typedef UInt8 {function_name}FctList;")
        typedefs.append("")

        for memory_area in self.nvm_def._nvm_memory_areas:
            nvm_name = f"{prefix}{memory_area}"
            struct_name = f"dt_{nvm_name}" if use_rte_nvm_structs else f"struct {nvm_name}"
            function_prefix = f"Rte_Call_{self.nvm_port_pattern.format(NvName=nvm_name)}"
            function_declarations.append(f"{struct_name} *Rte_Pim_{nvm_name}(void);")
            function_declarations.append(f"void {function_prefix}_SetRamBlockStatus(UInt8 status);")
            function_declarations.append(f"void {function_prefix}_GetErrorStatus(UInt8 *status);")
            function_declarations.append(f"void {function_prefix}_WriteBlock({struct_name} *block);")

            if use_rte_nvm_structs:
                struct_defines.append("typedef struct\n{")
                memory_area_index = self.nvm_def._get_nvm_areas_index(memory_area)
                nr_of_unused_signals = self.nvm_def.nvm_definitions[memory_area_index]["size"]
                signals = self.nvm_def.nvm_definitions[memory_area_index]["signals"]
                for signal in signals:
                    signal_string = ""
                    nr_of_unused_signals -= signal["x_size"] * signal["y_size"]
                    signal_string += f'  {signal["type"]} {self.nvm_def.struct_member_prefix}{signal["name"]}'
                    size = max(signal["x_size"], 1) * max(signal["y_size"], 1)
                    if size > 1:
                        if signal["x_size"] > 1:
                            signal_string += f'[{signal["x_size"]}]'
                        if signal["y_size"] > 1:
                            signal_string += f'[{signal["y_size"]}]'
                    signal_string += ";"
                    struct_defines.append(signal_string)
                if nr_of_unused_signals > 0:
                    struct_defines.append(
                        f'  {self.nvm_def.nvm_definitions[memory_area_index]["default_datatype"]} '
                        f'unused[{nr_of_unused_signals}];'
                    )
                struct_defines.append(f"}} {struct_name};\n")

        return "\n".join(typedefs + struct_defines + function_declarations)

    def _generate_nvm_source_dummy(self):
        """Generate NVM source dummy code."""
        lines_to_write = []
        prefix = self.build_cfg.get_scheduler_prefix()
        use_rte_nvm_structs = self.build_cfg.get_code_generation_config("useRteNvmStructs")
        for memory_area in self.nvm_def._nvm_memory_areas:
            nvm_name = f"{prefix}{memory_area}"
            struct_name = f"dt_{nvm_name}" if use_rte_nvm_structs else f"struct {nvm_name}"
            function_prefix = f"Rte_Call_{self.nvm_port_pattern.format(NvName=nvm_name)}"
            lines_to_write.append(f"{struct_name} *Rte_Pim_{nvm_name}(void) {{ return ({struct_name} *)0; }}")
            lines_to_write.append(f"void {function_prefix}_SetRamBlockStatus(UInt8 status) {{}}")
            lines_to_write.append(f"void {function_prefix}_GetErrorStatus(UInt8 *status) {{}}")
            lines_to_write.append(f"void {function_prefix}_WriteBlock({struct_name} *block) {{}}")
        lines_to_write.append("")
        return "\n".join(lines_to_write)

    def generate_rte_dummy(self):
        """Generate RTE dummy files."""
        src_code_dest_dir = self.build_cfg.get_src_code_dst_dir()
        header_file = Path(src_code_dest_dir, self.header_file_name + ".h")
        source_file = Path(src_code_dest_dir, self.source_file_name + ".c")
        with header_file.open(mode="w", encoding="utf-8") as header_fh:
            header_fh.write(self._get_header_header())
            header_fh.write(self._get_nvm_header_dummy())
            header_fh.write(self._get_header_footer())
        with source_file.open(mode="w", encoding="utf-8") as source_fh:
            source_fh.write(self._get_source_header())
            source_fh.write(self._generate_nvm_source_dummy())
