#!/usr/bin/env python3

# SPDX-FileCopyrightText: © 2022 Decompollaborate
# SPDX-License-Identifier: MIT

from __future__ import annotations

import bisect

from ... import common

from .. import symbols

from . import SectionBase


class SectionBss(SectionBase):
    def __init__(self, context: common.Context, bssVramStart: int, bssVramEnd: int, filename: str):
        super().__init__(context, bssVramStart, filename, bytearray(), common.FileSectionType.Bss)

        self.bssVramStart: int = bssVramStart
        self.bssVramEnd: int = bssVramEnd

        self.bssTotalSize: int = bssVramEnd - bssVramStart

        self.vram = bssVramStart


    def setVram(self, vram: int):
        super().setVram(vram)

        self.bssVramStart = vram
        self.bssVramEnd = vram + self.bssTotalSize

    def analyze(self):
        self.checkAndCreateFirstSymbol()

        # If something that could be a pointer found in data happens to be in the middle of this bss file's addresses space
        # Then consider it a new bss variable
        for ptr in sorted(self.context.newPointersInData):
            if ptr < self.bssVramStart:
                continue
            if ptr >= self.bssVramEnd:
                break

            contextSym = self.context.getGenericSymbol(ptr)
            if contextSym is None:
                contextSym = self.context.addSymbol(ptr, None, common.FileSectionType.Bss)
                contextSym.isAutogenerated = True
                contextSym.isDefined = True


        offsetSymbolsInSection = self.context.offsetSymbols[common.FileSectionType.Bss]
        bssSymbolOffsets: dict[int, common.ContextSymbolBase] = {offset: sym for offset, sym in offsetSymbolsInSection.items()}

        vramIndexLow = bisect.bisect(self.context.symbolsVramSorted, self.bssVramStart)
        vramIndexHigh = bisect.bisect(self.context.symbolsVramSorted, self.bssVramEnd)
        for vramIndex in range(vramIndexLow-1, vramIndexHigh-1):
            symbolVram = self.context.symbolsVramSorted[vramIndex]
            contextSym = self.context.symbols[symbolVram]
            # Mark every known symbol that happens to be in this address space as defined
            contextSym.isDefined = True
            contextSym.sectionType = common.FileSectionType.Bss

            # Needs to move this to a list because the algorithm requires to check the size of a bss variable based on the next bss variable' vram
            bssSymbolOffsets[symbolVram-self.bssVramStart] = contextSym


        sortedOffsets = sorted(bssSymbolOffsets.items())

        i = 0
        while i < len(sortedOffsets):
            symbolOffset, contextSym = sortedOffsets[i]
            symbolVram = self.bssVramStart + symbolOffset

            # Calculate the space of the bss variable
            space = self.bssTotalSize - symbolOffset
            if i + 1 < len(sortedOffsets):
                nextSymbolOffset, _ = sortedOffsets[i+1]
                if nextSymbolOffset <= self.bssTotalSize:
                    space = nextSymbolOffset - symbolOffset

            sym = symbols.SymbolBss(self.context, symbolOffset + self.inFileOffset, symbolVram, contextSym.name, space)
            sym.setCommentOffset(self.commentOffset)
            sym.analyze()
            self.symbolList.append(sym)

            i += 1
