"""
@package   mqtt-hardware-definition-service
@file      mqtt_hardware_definition_service.py
@brief     Publishes hardware definitions via MQTT

@author    andy wright
@date      11/06/2024
@copyright Copyright 2024 Hanover Displays Limited.
@license   This program is the confidential and proprietary product of
           Hanover Displays Limited. Any unauthorised use, reproduction or
           transfer of this program is strictly prohibited. (Subject to
           limited distribution and restricted disclosure only.) All
           rights reserved.
"""

import time
import datetime
import argparse
import mqtt_service as mqtt
import logging
import signal
logger = logging.getLogger(__name__)

class hardwareDefinitionService(object):
    def __init__(self, broker            = "127.0.0.1",
                       port              = 1883,
                       user_name         = "",
                       password          = "",
                       deviceID          = "",
                       customerID        = "",
                       VIN               = "",
                ):

        def inc_level(sig, frame):
            level = logger.getEffectiveLevel()
            if level == logging.CRITICAL:
                logger.setLevel(logging.ERROR)
            elif level == logging.ERROR:
                logger.setLevel(logging.WARNING)
            elif level == logging.WARNING:
                logger.setLevel(logging.INFO)
            elif level == logging.INFO:
                logger.setLevel(logging.DEBUG)
            print(f"Set logging to {logging.getLevelName(logger.getEffectiveLevel())}")

        def dec_level(sig, frame):
            level = logger.getEffectiveLevel()
            if level == logging.NOTSET:
                logger.setLevel(logging.DEBUG)
            elif level == logging.DEBUG:
                logger.setLevel(logging.INFO)
            elif level == logging.INFO:
                logger.setLevel(logging.WARNING)
            elif level == logging.WARNING:
                logger.setLevel(logging.ERROR)
            elif level == logging.ERROR:
                logger.setLevel(logging.CRITICAL)
            print(f"Set logging to {logging.getLevelName(logger.getEffectiveLevel())}")

        signal.signal(signal.SIGUSR2, inc_level)
        signal.signal(signal.SIGUSR1, dec_level)

        self.eth_dict_array = []

        self.hardware_definitions_dictionary = {
            "atDateTime":        "",
            "manufacturer":      "Hanover Displays Ltd",
            "productType":       "",
            "ProductName":       "",
            "variantName":       "",
            "serialNumber":      "",
            "hardwareVersion":   "",
            "dateOfManufacture": "",
            "ethernetPhys":      self.eth_dict_array
        }

        if deviceID == "":
            self.topic = "info/device"
        else:
            self.topic = customerID + "/" + VIN + "/hanover/inventory/equipment/" + deviceID + "/info/device"

        self.mqttService = mqtt.mqttService("mqtt-hardware-definition-service",
                                            broker    = broker,
                                            port      = port,
                                            user_name = user_name,
                                            password  = password)

    def setPayload(self, manufacturer      = None,
                         productType       = None,
                         productName       = None,
                         variantName       = None,
                         serialNumber      = None,
                         hardwareVersion   = None,
                         dateOfManufacture = None):
        if manufacturer != None:
            self.hardware_definitions_dictionary["manufacturer"] = manufacturer
        if productType != None:
            self.hardware_definitions_dictionary["productType"] = productType
        if productName != None:
            self.hardware_definitions_dictionary["ProductName"] = productName
        if variantName != None:
            self.hardware_definitions_dictionary["variantName"] = variantName
        if serialNumber != None:
            self.hardware_definitions_dictionary["serialNumber"] = serialNumber
        if hardwareVersion != None:
            self.hardware_definitions_dictionary["hardwareVersion"] = hardwareVersion
        if dateOfManufacture != None:
            self.hardware_definitions_dictionary["dateOfManufacture"] = dateOfManufacture

    def setManufacturer(self, manufacturer):
            self.hardware_definitions_dictionary["manufacturer"] = manufacturer

    def setProductType(self, productType):
            self.hardware_definitions_dictionary["productType"] = productType

    def setProductName(self, productName):
            self.hardware_definitions_dictionary["ProductName"] = productName

    def setVariantName(self, variantName):
            self.hardware_definitions_dictionary["variantName"] = variantName

    def setSerialNumber(self, serialNumber):
            self.hardware_definitions_dictionary["serialNumber"] = serialNumber

    def setHardwareVersion(self, hardwareVersion):
            self.hardware_definitions_dictionary["hardwareVersion"] = hardwareVersion

    def setDateOfManufacture(self, dateOfManufacture):
            self.hardware_definitions_dictionary["dateOfManufacture"] = dateOfManufacture

    def setEthernetPhy(self, name, mac):
        found = 0
        for eth in self.eth_dict_array:
            if eth["name"] == name:
                eth["MAC"] = mac
                found = 1
                break
        if found == 0:
            eth_dict = {"name": name, 
                        "MAC": mac }
            self.eth_dict_array.append(eth_dict)

    def delEthernetPhy(self, name):
        for eth in self.eth_dict_array:
            if eth["name"] == name:
                self.eth_dict_array.remove(eth)
                break

    def publish(self):
        self.hardware_definitions_dictionary["atDateTime"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
        logger.debug(f"publish - {self.topic}\n{self.hardware_definitions_dictionary}\n")
        self.mqttService.publish(self.topic, self.hardware_definitions_dictionary)

if __name__ == "__main__":
    # Instantiate the parser
    parser = argparse.ArgumentParser(description='Publishes hardware definitions via MQTT')

    # Parse arguments
    parser.add_argument('--period', type=int, default=5, help='MQTT message publish period in seconds (default 5 seconds)')
    parser.add_argument('--manufacturer', type=str, help='Hardware manufacturer to publish')
    parser.add_argument('--productType', type=str, help='Product type to publish')
    parser.add_argument('--productName', type=str, help='Product name to publish')
    parser.add_argument('--variantName', type=str, help='Variant name to publish')
    parser.add_argument('--serialNumber', type=str, help='Serial number to publish')
    parser.add_argument('--hardwareVersion', type=str, help='Hardware version to publish')
    parser.add_argument('--dateOfManufacture', type=str, help='Date of manufacture to publish')
    parser.add_argument('--eth0', type=str, help='eth0 MAC address to publish')
    parser.add_argument('--eth1', type=str, help='eth1 MAC address to publish')
    args = parser.parse_args()

    #use local broker to forward topics
    hwDefService = hardwareDefinitionService()

    #send topics direct to cloud
    #hwDefService = hardwareDefinitionService(broker            = "mqtt.ver.hanover.cloud",
    #                                         port              = 2023,
    #                                         user_name         = "1031_300",
    #                                         password          = "z3Qs38jn",
    #                                         deviceID          = "EG4",
    #                                         customerID        = "1031",
    #                                         VIN               = "0")

    if args.manufacturer != None:
        hwDefService.setManufacturer(args.manufacturer)
    if args.productType != None:
        hwDefService.setProductType(args.productType)
    if args.productName != None:
        hwDefService.setProductName(args.productName)
    if args.variantName != None:
        hwDefService.setVariantName(args.variantName)
    if args.serialNumber != None:
        hwDefService.setSerialNumber(args.serialNumber)
    if args.hardwareVersion != None:
        hwDefService.setHardwareVersion(args.hardwareVersion)
    if args.dateOfManufacture != None:
        hwDefService.setDateOfManufacture(args.dateOfManufacture)
    if args.eth0 != None:
        hwDefService.setEthernetPhy("eth0", args.eth0)
    if args.eth1 != None:
        hwDefService.setEthernetPhy("eth1", args.eth1)

    while 1:
        hwDefService.publish()
        time.sleep(args.period)
