from __future__ import annotations

from ._isa import Encoding


class Instruction:
    def __init__(self, pc : int, encoding_bytes : int) -> None:
        """
        Constructor

        :param pc: Program counter
        :type pc: int
        :param encoding_bytes: Instruction encoding
        :type encoding_bytes: int
        """
        self.pc = pc
        self.encoding_bytes = encoding_bytes
        self.encoding = None
        self.operands = {}
        self.prev = None
        self.next = None

        self.decode()

    def __str__(self) -> str:
        """
        Return a string representation of the Instruction.

        :return: String representation of the Instruction.
        :rtype: str
        """

        s = f"{self.pc:016x} : "
        s += f"{self.prev.encoding.mnemonic}" if self.prev is not None else "None"
        s += " -> "
        s += f"\033[31m{self.encoding.mnemonic}\033[0m"
        s += " -> "
        s += f"{self.next.encoding.mnemonic}" if self.next is not None else "None"

        return s

    def link(self, next : Instruction) -> None:
        """
        Create 2 way link to next instruction (if you can)

        Next / Prev refers to location in program (i.e. pc +/- one instruction)
        not location in trace

        :param next: Next instruction
        :type next: Instruction
        """
        if next is not None:
            self.next = next
            self.next.prev = self


    def decode(self) -> None:
        """
        Decode instruction to get mnemonic and operands
        """

        # Determine size (compressed or standard)
        if (self.encoding_bytes & 0b11) != 0b11:
            self.size = 2
            instr_code = self.encoding_bytes & 0xFFFF
        else:
            self.size = 4
            instr_code = self.encoding_bytes & 0xFFFFFFFF

        self.encoding = Encoding.get_encoding(instr_code)

        # Extract Operand Values
        for k in self.encoding.operands.keys():
            self.operands[k] = Encoding.get_operand(instr_code, k)

__all__ = [
    "Instruction"
]
