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

'''Code representing clocking or resets for an IP block'''

from typing import Dict, List, Optional

from .lib import check_keys, check_list, check_bool, check_optional_name


class ClockingItem:
    def __init__(self, clock: Optional[str], reset: Optional[str], primary: bool):
        if primary:
            assert clock is not None
            assert reset is not None

        self.clock = clock
        self.reset = reset
        self.primary = primary

    @staticmethod
    def from_raw(raw: object, only_item: bool, where: str) -> 'ClockingItem':
        what = f'clocking item at {where}'
        rd = check_keys(raw, what, [], ['clock', 'reset', 'primary'])

        clock = check_optional_name(rd.get('clock'), 'clock field of ' + what)
        reset = check_optional_name(rd.get('reset'), 'reset field of ' + what)
        primary = check_bool(rd.get('primary', only_item),
                             'primary field of ' + what)

        if primary:
            if clock is None:
                raise ValueError('No clock signal for primary '
                                 f'clocking item at {what}.')
            if reset is None:
                raise ValueError('No reset signal for primary '
                                 f'clocking item at {what}.')

        return ClockingItem(clock, reset, primary)

    def _asdict(self) -> Dict[str, object]:
        ret = {}  # type: Dict[str, object]
        if self.clock is not None:
            ret['clock'] = self.clock,
        if self.reset is not None:
            ret['reset'] = self.reset

        ret['primary'] = self.primary
        return ret


class Clocking:
    def __init__(self, items: List[ClockingItem], primary: ClockingItem):
        assert items
        self.items = items
        self.primary = primary

    @staticmethod
    def from_raw(raw: object, where: str) -> 'Clocking':
        what = f'clocking items at {where}'
        raw_items = check_list(raw, what)
        if not raw_items:
            raise ValueError(f'Empty list of clocking items at {where}.')

        just_one_item = len(raw_items) == 1

        items = []
        primaries = []
        for idx, raw_item in enumerate(raw_items):
            item_where = f'entry {idx} of {what}'
            item = ClockingItem.from_raw(raw_item, just_one_item, item_where)
            if item.primary:
                primaries.append(item)
            items.append(item)

        if len(primaries) != 1:
            raise ValueError('There should be exactly one primary clocking '
                             f'item at {where}, but we saw {len(primaries)}.')

        return Clocking(items, primaries[0])

    def other_clocks(self) -> List[str]:
        ret = []
        for item in self.items:
            if not item.primary and item.clock is not None:
                ret.append(item.clock)
        return ret

    def clock_signals(self) -> List[str]:
        return [item.clock for item in self.items if item.clock is not None]

    def reset_signals(self) -> List[str]:
        return [item.reset for item in self.items if item.reset is not None]
