import csv
import sys
from dataclasses import dataclass
from generate import renderer

@dataclass
class RegisterBitDef:
    name: str
    bits: tuple[int, int]
    bit_prefix: str
    bit_name: str
    enum_name: str
    enum_value: str
    description: str

def parse_bit(s):
    if ':' in s:
        a, b = s.split(':')
        return int(a, 10), int(b, 10)
    else:
        return int(s, 10), int(s, 10)

last_def = None

def parse_value(s):
    if not s:
        return None
    elif s.startswith("0x"):
        return int(s.removeprefix("0x"), 16)
    else:
        return int(s.removeprefix("0x"), 10)

def parse_csv_row(row):
    global last_def
    name, bits, bit_prefix, bit_name, enum_name, enum_value, description = row
    if not name:
        assert last_def is not None
        assert not bits
        assert not bit_prefix
        assert not bit_name
        assert enum_name
        assert enum_value != ''
        assert not description

        assert last_def.enum_name
        assert last_def.enum_value is not None

        name = last_def.name
        bits = last_def.bits
        bit_prefix = last_def.bit_prefix
        bit_name = last_def.bit_name
        description = last_def.description
    else:
        bits = parse_bit(bits)

    assert name, name
    assert bit_name, bit_name
    if enum_name:
        assert enum_value, (enum_name, enum_value)
    assert description, description

    bit_def = RegisterBitDef(
        name,
        bits,
        bit_prefix or None,
        bit_name,
        enum_name or None,
        parse_value(enum_value),
        description
    )
    last_def = bit_def
    return bit_def

def filter_row(row):
    if row == ['', '', '', '', '', '', '']:
        return False
    name, bits, bit_prefix, bit_name, enum_name, enum_value, description = row
    return description != 'reserved' and (bit_name or enum_name)

def bit_mask(d):
    high, low = d.bits
    return (1 << ((high - low) + 1)) - 1

def format_value(d):
    if d.enum_name is not None:
        assert d.enum_value is not None
        assert d.enum_value <= bit_mask(d)
        return f"({d.enum_value} << {d.bits[1]})"
    elif bit_mask(d) == 1:
        return f"(1 << {d.bits[1]})"
    else:
        return f"(((n) & {hex(bit_mask(d))}) << {d.bits[1]})"

def format_macro(d):
    macro = f"{d.name.upper()}"
    if d.bit_prefix is not None:
        macro += f"__{d.bit_prefix.upper()}"
    macro += f"__{d.bit_name.upper()}"
    if d.enum_name is not None:
        macro += f"__{d.enum_name.upper()}"
    elif bit_mask(d) != 1:
        macro += "(n)"
    return macro

def format_def(d):
    return f"#define {format_macro(d)} {format_value(d)}"

def render_defs(defs):
    last_name = None
    for d in defs:
        if last_name is not None and d.name != last_name:
            yield ""
        yield format_def(d)
        last_name = d.name

with open(sys.argv[1], 'r') as f:
    reader = csv.reader(f)
    defs = list(map(parse_csv_row, filter(filter_row, reader)))

render, out = renderer()
render(render_defs(defs))
sys.stdout.write(out.getvalue())
