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 ZebraRPCFirmwareInterpreter")

class ZebraRPCFirmwareInterpreter(FirmwareInterpreter):

    def GetMetadata(self, fileName, fileBytes):
        #models
        models = List[str]()
        version = ""
              
        # Decode the bytearray to an ASCII string
        fileString = bytes(fileBytes).decode('ascii', errors='ignore')
        lines = fileString.splitlines()

        if len(lines) < 2 or not lines[0].strip().startswith('! PROGRAM'):
              return FirmwareMetadata(version, models)
        
        # zebra firmware is VXX.XX.XXZ or SPXX-XXXXXXA on the second line
        version = lines[1].strip()
        modelIdentifier = ""

        if version.startswith("V"):
            modelIdentifier = version.split('.')[0].strip('V')
        elif version.startswith("SP"):
            modelIdentifier = version.split('-')[0].replace("SP", "").strip()

        if modelIdentifier == "68":
            models.Add('QLn220')
            models.Add('QLn310')
            models.Add('QLn320')
            models.Add('QLn420')
            models.Add('QLn220 HC')
            models.Add('QLn320 HC')
        elif modelIdentifier == "72":
            models.Add('ZT210')
            models.Add('ZT220')
            models.Add('ZT230')
        elif modelIdentifier == "73":
            models.Add('iMZ220')
            models.Add('iMZ320')
        elif modelIdentifier == "74":
            models.Add('ZD500')
            models.Add('ZD500R')
        elif modelIdentifier == "75":
            models.Add('FedEx ZT400')
            models.Add('ZT410')
            models.Add('ZT420')
        elif modelIdentifier == "76":
            models.Add('ZQ510')
            models.Add('ZQ520')
        elif modelIdentifier == "78":
            models.Add('ZR338')
        elif modelIdentifier == "79":
            models.Add('ZR628')
            models.Add('ZR638')
        elif modelIdentifier == "80": # Listed below as 96, for these three models FW is V80 priority to Link-OS 6.8 release 2
            models.Add('ZT510')
            models.Add('ZT610')
            models.Add('ZT620')
        elif modelIdentifier == "81":
            models.Add('ZQ310')
            models.Add('ZQ320')
        elif modelIdentifier == "82":
            models.Add('ZR318')
            models.Add('ZR328')
        elif modelIdentifier == "83":
            models.Add('ZD510')
            models.Add('ZD510-HC')
        elif modelIdentifier == "84":
            models.Add('ZD410d')
            models.Add('ZD420c')
            models.Add('ZD420d')
            models.Add('ZD420t')
            models.Add('ZD620d')
            models.Add('ZD620t')
        elif modelIdentifier == "85":
            models.Add('ZQ610')
            models.Add('ZQ620')
            models.Add('ZQ630')
            models.Add('ZQ630R')
        elif modelIdentifier == "86":
            models.Add('ZR658')
            models.Add('ZR668')
        elif modelIdentifier == "89":
            models.Add('ZD220')
            models.Add('ZD230')
            models.Add('ZD888')
        elif modelIdentifier == "91":
            models.Add('ZQ511')
            models.Add('ZQ511R')
            models.Add('ZQ521')
            models.Add('ZQ521R')
        elif modelIdentifier == "92":
            models.Add('ZT411')
            models.Add('ZT421')
            models.Add('ZT411R')
            models.Add('ZT421R')
        elif modelIdentifier == "93":
            models.Add('ZD411')
            models.Add('ZD421')
            models.Add('ZD421c')
            models.Add('ZD421d')
            models.Add('ZD421t')
            models.Add('ZD611')
            models.Add('ZD621')
            models.Add('ZD611R')
            models.Add('ZD621R')
            models.Add('ZD621d')
            models.Add('ZD621t')
        elif modelIdentifier == "94":
            models.Add('ZE511')
            models.Add('ZE511 RH')
            models.Add('ZE511R')
            models.Add('ZE521')
            models.Add('ZE521R')
            models.Add('ZE521 RH')
        elif modelIdentifier == "96":
            models.Add('ZT510')
            models.Add('ZT610')
            models.Add('ZT620')
            models.Add('ZT610R')
            models.Add('ZT620R')
        elif modelIdentifier == "97":
            models.Add('ZT111')
            models.Add('ZT211')
            models.Add('ZT231')
            models.Add('ZT231R')
        elif modelIdentifier == "100":
            models.Add('ZQ610 Plus')
            models.Add('ZQ620 Plus')
            models.Add('ZQ630 Plus')
            models.Add('ZQ630R Plus')
        elif modelIdentifier == "101":
            models.Add('ZQ310 Plus')
            models.Add('ZQ320 Plus')
             
        return FirmwareMetadata(version, models)

        
    def ValidateVersion(self, rawVersion):

        # rawVersion is the version parsed from the method above (GetMetaData)
        # we validate the version here to make sure it's in the correct format
        # which in this case for zebra is Vxx.xx.xxZ
        if rawVersion.startswith("V") and rawVersion.endswith("Z"):
            content = rawVersion[1:-1] # remove first and last char
            parts = content.split(".") # split by . 

            # check to make sure everything is a digit
            for part in parts:
                if not part.isdigit():
                    return False
            return True

        elif rawVersion.startswith("SP"):
            # Format: SPXX-XXXXXXA
            content = rawVersion[2:]  # remove 'SP'
            parts = content.split("-")
            if len(parts) != 2:
                return False

            major = parts[0]
            rest = parts[1]

            # major must be digits
            if not major.isdigit():
                return False
            # rest must be at least 7 chars: 6 digits + 1 letter
            if len(rest) < 7:
                return False

            build = rest[:6]
            revision = rest[6]

            # validate build and revision
            if not build.isdigit():
                return False

            if not revision.isalpha():
                return False

            return True

        return False

    ##version 1 is device state property
    ##version 2 is firmware file version
    def CompareVersions(self, deviceStateVersionRaw, firmwareFileVersionRaw):

        def normalize(version):

            # ---- Vxx.xx.xxZ ----
            if re.match(r'^V\d+\.\d+\.\d+Z$', version):
                content = version[1:-1]
                parts = content.split(".")
                return ("V", tuple(int(p) for p in parts))

            # ---- SPxx-XXXXXXA  ----
            sp_match = re.match(r'^(SP\d{2}-\d{6}[A-Z])', version)
            if sp_match:
                clean_version = sp_match.group(1)
                content = clean_version[2:-1]
                major, build = content.split("-")
                revision = clean_version[-1]
                return ("SP", (int(major), int(build), revision))

            return (None, None)

        deviceFirmwareType, deviceParsedVersion = normalize(deviceStateVersionRaw)
        fileFirmwareType, fileParsedVersion = normalize(firmwareFileVersionRaw)

        if deviceFirmwareType != fileFirmwareType:
            return 0  

        if deviceParsedVersion > fileParsedVersion:
            return 1
        elif fileParsedVersion > deviceParsedVersion:
            return -1
        else:
            return 0


plugin = ZebraRPCFirmwareInterpreter("ZebraRPCFirmwareInterpreter")

store.Add(plugin)