# This file consists of the common useful functions for eFuse
#
# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
#
# SPDX-License-Identifier: GPL-2.0-or-later

from bitstring import Bits

import esptool


def hexify(bitstring, separator=""):
    as_bytes = tuple(b for b in bitstring)
    return separator.join((f"{b:02x}") for b in as_bytes)


def json_raw_value_hex(efuse_type: str, bits: Bits) -> str:
    """``0x``-prefixed lowercase hex string for JSON ``raw_value``,
    same style for all field types.

    For ``bytes`` fields, uses the same byte order as the text/JSON ``value`` hex
    (``bits.bytes`` reversed). For other types, encodes the field bit pattern with
    leading zero bits padded to a nibble boundary so ``Bits.hex`` is defined.
    """
    if efuse_type.startswith("bytes"):
        return "0x" + str(bits.bytes[::-1].hex())
    b = bits if isinstance(bits, Bits) else Bits(bits)
    pad = (4 - (b.len % 4)) % 4
    if pad:
        b = Bits(pad) + b
    return "0x" + str(b.hex)


def popcnt(b):
    """Return number of "1" bits set in 'b'"""
    return len([x for x in bin(b) if x == "1"])


def check_duplicate_name_in_list(name_list):
    duples_name = [name for i, name in enumerate(name_list) if name in name_list[:i]]
    if duples_name != []:
        raise esptool.FatalError(f"Found repeated {duples_name} in the name list.")


class SdkConfig:
    def __init__(self, path_to_file):
        self.sdkconfig = dict()
        if path_to_file is None:
            return
        with open(path_to_file) as file:
            for line in file.readlines():
                if line.startswith("#"):
                    continue
                config = line.strip().split("=", 1)
                if len(config) == 2:
                    self.sdkconfig[config[0]] = (
                        True if config[1] == "y" else config[1].strip('"')
                    )

    def __getitem__(self, config_name):
        try:
            return self.sdkconfig[config_name]
        except KeyError:
            return False
