import clr
clr.AddReference('Soti.Connect.SemanticEngine.Conversions')
from System.Collections.Generic import List

from Soti.Connect.SemanticEngine.Conversions.Interpreters import FirmwareInterpreter
from Soti.Connect.SemanticEngine.Conversions.Interpreters import FirmwareMetadata
import re

print("Loading ZebraRFDFirmwareInterpreter")

class ZebraRFDFirmwareInterpreter(FirmwareInterpreter):

    def GetMetadata(self, fileName, fileBytes):
        version = ""
        models = List[str]()  

        offset_hex = 0x408  # Default for Zebra RFID firmware
        read_length = 16    # Default for Zebra RFID firmware
        offset_decimal = int(offset_hex)

        if offset_decimal >= len(fileBytes):
            print("ZebraRFDFirmwareInterpreter Error: Offset is out of file bounds.")
            return FirmwareMetadata(version, models)

        snippet = fileBytes[offset_decimal : offset_decimal + read_length]
        decoded_snippet = bytes(snippet).decode("ascii", errors="ignore").strip()

        parts = decoded_snippet.split('-')
        
        if len(parts) >= 3:
            rawVersion = parts[1] + '-' + parts[2]
            
            if self.ValidateVersion(rawVersion):
                version = rawVersion
            else:
                print("ZebraRFDFirmwareInterpreter Warning: Invalid version format. Version remains empty.")
        else:
            print("ZebraRFDFirmwareInterpreter Warning: Expected at least 2 '-' delimiters in snippet. Version remains empty.")

        models = self.CheckSupportedModels(decoded_snippet)

        if not models:
            print("ZebraRFDFirmwareInterpreter Error: No supported models found in firmware file.")
            return FirmwareMetadata(version, models)

        return FirmwareMetadata(version, models)

    def CheckSupportedModels(self, decoded_snippet):
        models = List[str]()
        model_identifier = decoded_snippet[1:5]

        if model_identifier == "AAFK":  # RFD40/90
            models.Add('RFD40')
            models.Add('RFD90')

        return models

    def ValidateVersion(self, rawVersion):
        """
        Checks whether rawVersion matches the format:
            <3 digits>-R<2 digits>
        Examples: '007-R00', '015-R09', etc.
        """
        pattern = r'^\d{3}-R\d{2}$'
        return bool(re.match(pattern, rawVersion))

    def CompareVersions(self, deviceStateVersionRaw, firmwareFileVersionRaw):
        """
        Compare two versions.
        Format: NNN-XNN
        - NNN = exactly 3 digits
        - X   = any letter (A-Z, case-insensitive)
        - NN  = exactly 2 digits
        
        We ignore the letter when comparing. We only compare (major, minor).
        
        Returns:
        1 if deviceStateVersion > firmwareFileVersion
        -1 if deviceStateVersion < firmwareFileVersion
        0 if equal (or parse failed for either)
        """

        device_core = self.findVersion(deviceStateVersionRaw)
        firmware_core = self.findVersion(firmwareFileVersionRaw)

        if not device_core:
            print("ZebraRFDFirmwareInterpreter Error: Could not parse version from deviceStateVersionRaw.")
            return 0
        if not firmware_core:
            print("ZebraRFDFirmwareInterpreter Error: Could not parse version from firmwareFileVersionRaw.")
            return 0

        device_major, device_minor = self.parseVersion(device_core)
        firmware_major, firmware_minor = self.parseVersion(firmware_core)

        if (device_major, device_minor) > (firmware_major, firmware_minor):
            return 1
        elif (device_major, device_minor) < (firmware_major, firmware_minor):
            return -1
        else:
            return 0


    def findVersion(self, rawString):
        """
        Searches anywhere in 'rawString' for a substring matching NNN-XNN,
        where:
        - NNN = exactly 3 digits
        - X   = any single letter (A-Z, a-z)
        - NN  = exactly 2 digits
        
        Returns the matched substring (e.g. '007-R00', '007-D06', '123-a09'), or None if not found.
        """
        match = re.search(r'(\d{3}-[A-Za-z]\d{2})', rawString)
        if match:
            return match.group(1)
        return None


    def parseVersion(self, versionCore):
        """
        Given 'NNN-XNN', convert to (major, minor), ignoring the letter.
        Examples:
        '007-R05' -> (7, 5)
        '007-D06' -> (7, 6)
        '123-a09' -> (123, 9)
        
        If it doesn't match the pattern, returns (0, 0).
        """
        m = re.match(r'^(\d{3})-[A-Za-z](\d{2})$', versionCore)
        if not m:
            print("ZebraRFDFirmwareInterpreter Warning: Unexpected version format")
            return (0, 0)

        major_str, minor_str = m.groups()
        major = int(major_str)
        minor = int(minor_str)
        return (major, minor)

plugin = ZebraRFDFirmwareInterpreter("ZebraRFDFirmwareInterpreter")

store.Add(plugin)