# I3C High Level Analyzer

from saleae.analyzers import HighLevelAnalyzer, AnalyzerFrame, ChoicesSetting
from I3CDictionaries import I3CDictionaries, DecodingModes, I3cVersions
from SDRDecoder import SDRDecoder
from DDRDecoder import DDRDecoder
from BTDecoder import BTDecoder
import logging
import sys


# High level analyzers must subclass the HighLevelAnalyzer class.
class Hla(HighLevelAnalyzer):

    choices = [I3cVersions.VERSION1_0.value, I3cVersions.VERSION1_1.value, I3cVersions.VERSION1_1_1.value, I3cVersions.VERSION1_2.value]
    i3c_version_option = ChoicesSetting(choices, label='I3C Version')
    second_layer_HLA_option = ChoicesSetting(['None', 'SPD', 'MCTP Packets', 'MCTP Messages'])

    I3C_logger = logging.getLogger("I3C")
    
    result_types = I3CDictionaries.result_types

    temp_frame = None

    def __init__(self):

        '''
        Initialize HLA.
        '''

        logging.basicConfig(level=logging.INFO, stream=sys.stdout)

        '''
            Obtain the instances for the SDR and DDR decoder
        '''
        self.sdrDecoder = SDRDecoder(self.second_layer_HLA_option, I3cVersions(self.i3c_version_option))
        self.ddrDecoder = DDRDecoder(self.second_layer_HLA_option, I3cVersions(self.i3c_version_option))
        self.btDecoder  = BTDecoder(self.second_layer_HLA_option, I3cVersions(self.i3c_version_option))
        self.mode = DecodingModes.SDR


    """This method will be called by the Analyzer every time
    a frame is committed so it can be processed by the HLA
    This method it must always return an AnalyzerFrame or
    None if nothing is to be committed.
    """
    def decode(self, frame: AnalyzerFrame):

        frame_to_push = None
        if self.mode == DecodingModes.SDR:
            frame_to_push, self.mode = self.sdrDecoder.processFrame(frame)
        elif self.mode == DecodingModes.DDR:
            frame_to_push, self.mode = self.ddrDecoder.processFrame(frame)
        elif self.mode == DecodingModes.BT:
            frame_to_push, self.mode = self.btDecoder.processFrame(frame)

        return frame_to_push