# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

from typing import Dict, Optional
from .clocks import Clocks


class ResetItem:
    '''Individual resets'''
    def __init__(self, hier: Dict[str, str], raw: Dict[str, object], clocks: Clocks):
        if not raw['name']:
            raise ValueError('Reset has no name')

        self.name = raw['name']
        self.gen = raw.get('gen', True)
        self.rst_type = raw.get('type', 'top')

        self.path = ""
        if self.rst_type == 'top':
            self.path = f"{hier['top']}rst_{self.name}_n"
            self.lpg_path = f"{hier['lpg']}{self.name}"
        elif self.rst_type == 'ext':
            self.path = f"{hier['ext']}{self.name}"

        self.shadow_path = ""
        if self.rst_type == 'top':
            self.shadow_path = f"{hier['top']}rst_{self.name}_shadowed_n"

        # to be constructed later
        self.domains = []
        self.shadowed = False

        self.parent = raw.get('parent', "")

        # This can be a source clock or a derived source
        if self.rst_type != 'ext':
            self.clock = clocks.get_clock_by_name(raw['clk'])
        else:
            self.clock = None

        self.sw = bool(raw.get('sw', 0))

    def _asdict(self) -> Dict[str, object]:
        ret = {
            'name': self.name,
            'gen': self.gen,
            'type': self.rst_type,
            'domains': self.domains,
            'shadowed': self.shadowed,
            'sw': self.sw,
            'path': self.path
        }

        if self.parent:
            ret['parent'] = self.parent

        if self.clock:
            ret['clock'] = self.clock.name

        return ret


class Resets:
    '''Resets for the chip'''
    def __init__(self, raw: Dict[str, object], clocks: Clocks):
        self.hier_paths = {}
        assert isinstance(raw['hier_paths'], dict)
        for rst_src, path in raw['hier_paths'].items():
            self.hier_paths[str(rst_src)] = str(path)

        assert isinstance(raw['nodes'], list)

        self.nodes = {}
        for node in raw['nodes']:
            assert isinstance(node, dict)
            reset = ResetItem(self.hier_paths, node, clocks)
            self.nodes[reset.name] = reset

    def _asdict(self) -> Dict[str, object]:
        ret = {
            'hier_paths': self.hier_paths,
            'nodes': list(self.nodes.values())
        }

        return ret

    def get_reset_by_name(self, name: str) -> ResetItem:

        ret = self.nodes.get(name, None)
        if ret:
            return ret
        else:
            raise ValueError(f'{name} is not a defined reset')

    def mark_reset_shadowed(self, name: str):
        '''Mark particular reset as requiring shadow'''

        reset = self.get_reset_by_name(name)
        reset.shadowed = True

    def get_reset_domains(self, name: str):
        '''Get available domains for a reset'''

        return self.get_reset_by_name(name).domains

    def get_clocks(self) -> list:
        '''Get associated clocks'''

        clocks = {}
        for reset in self.nodes.values():
            if reset.rst_type != 'ext':
                clocks[reset.clock.name] = 1

        return list(clocks)

    def get_generated_resets(self) -> list:
        '''Get generated resets and return reset object
        '''
        return [reset
                for reset in self.nodes.values()
                if reset.gen]

    def get_top_resets(self) -> list:
        '''Get resets pushed to the top level'''

        return [reset
                for reset in self.nodes.values()
                if reset.rst_type == 'top']

    def get_sw_resets(self) -> list:
        '''Get software controlled resets'''

        return [reset.name
                for reset in self.nodes.values()
                if reset.sw]

    def get_path(self, name: str, domain: Optional[str], shadow = False) -> str:
        '''Get path to reset'''

        reset = self.get_reset_by_name(name)
        if reset.rst_type == 'int':
            raise ValueError(f'Reset {name} is not a reset exported from rstmgr')

        if reset.rst_type == 'ext':
            return reset.path

        if shadow:
            path = reset.shadow_path
        else:
            path = reset.path

        if domain:
            path += f'[rstmgr_pkg::Domain{domain}Sel]'

        return path

    def get_lpg_path(self, name: str, domain: Optional[str]) -> str:
        '''Get path to lpg indication signals'''

        reset = self.get_reset_by_name(name)
        if reset.rst_type == 'int':
            raise ValueError(f'Reset {name} is not a reset exported from rstmgr')

        if reset.rst_type == 'ext':
            raise ValueError(f'External reset {name} cannot be associated with an LPG')

        path = reset.lpg_path
        if domain:
            path += f'[rstmgr_pkg::Domain{domain}Sel]'

        return path

    def get_unused_resets(self, domains: list) -> Dict[str, str]:
        '''Get unused resets'''

        top_resets = [reset
                      for reset in self.nodes.values()
                      if reset.rst_type == 'top']

        ret = {}
        for reset in top_resets:
            for dom in domains:
                if dom not in reset.domains:
                    doml = dom.lower()
                    ret[f'unused_d{doml}_rst_{reset.name}'] = \
                        f'{reset.path}[rstmgr_pkg::Domain{dom}Sel]'

                    if reset.shadowed:
                        ret[f'unused_d{doml}_rst_{reset.name}_shadowed'] = \
                            f'{reset.shadow_path}[rstmgr_pkg::Domain{dom}Sel]'

        return ret

    def add_reset_domain(self, name: str, domain: str):
        '''Mark particular reset as requiring shadow'''

        reset = self.get_reset_by_name(name)

        # Other reset types of hardwired domains
        if reset.rst_type == 'top':
            if domain not in reset.domains:
                reset.domains.append(domain)

    def has_shadowed_reset(self) -> bool:
        '''Do any generated resets have a shadow version?'''

        for reset in self.nodes.values():
            if reset.shadowed:
                return True

        return False
