"""
Name: module_inventory_service
Title: 
Author: Cooper
Date: 07/12/2018
Modified: 14/05/2020

Desc:  Port of the original ITxPT MIS module, this is not backwards compatible as a lot of the structure has changed
since.  This version is different in the sense that it no longer grabs the hardware details, it is already provided
from the importer.

Dictionaries used here are created by OnionApp & passed in by the appropriate itxpt_mqtt (e.g. lausanne_mqtt.py)

"""
import os
import sys
import time
import _thread
import threading
import xmltodict

from hanip.itxpt import DNS_SD

from bottle import Bottle

class ModuleInventoryService(object):
    def __init__(self, config_dict, hw_dict, config_dir=None, data_dir=None):
        self.config_dict = config_dict
        self.hw_dict = hw_dict

        self.version = "2.1.4"
        self.module_type = self.get_module_type()
        self.blank_level = 0

        self.stop = False
        self.http_server = Bottle()


    """
    ###################################################################################################################
    HTTP Server 
    """

    def startHTTPServer(self):
        if sys.platform == "linux":
            port = 80
        else:
            port = 8080

        self.http_server.route('/test', method="GET", callback=self.test_page)
        self.http_server.route('/', method="GET", callback=self.provide_mis_xml)
        self.http_server.route('/moduleinfo.xml', method="GET", callback=self.provide_mis_xml)

        self.http_thread = threading.Thread(target=self.http_server.run, kwargs=dict(host="0.0.0.0",
                                                                                port=port,
                                                                                debug=False
                                                                                ))
        self.http_thread.daemon = True
        self.http_thread.start()

    def test_page(self):
        return "Hello!"

    """
    ###################################################################################################################
    DNS-SD
    """

    def register_service(self):
        """
        Changes made to align this with the latest ITxPT spec, S02P01 v2.1.2 (2023-07)

        Previous Inventory Service SRV:  [hostname]._inventory._itxpt_http._tcp.local 3600 IN SRV 0 0 80 [hostname]
        As of v2.1.2:                    [UniqueIdentifier]_inventory._itxpt_http._tcp.local 120 IN SRV 0 0 80 [hostname]

        The unique identifier is no longer allowed to contain underscores
        :return:
        """
        txtrecord = {
            "txtvers": "1",
            "version": self.version,
            "type": self.get_module_type(),
            "model": self.hw_dict["model"],
            "manufacturer": "Hanover Displays",
            "serialnumber": self.hw_dict["serial_number"],
            "softwareversion": self.hw_dict["software_version"],
            "hardwareVersion": self.hw_dict["hardware_version"],
            "macaddress": self.hw_dict["unit_MAC"],
            "status": self.hw_dict["hw_status"],
            "xstatus": "C0FFFFFFFFFFFFFF",
            "submodules": "false",
            "path": "/moduleinfo.xml",
            "services": "inventory"
        }

        self.mis_broadcast = DNS_SD.ITxPT_DNSSD(self.hw_dict["unit_IP"], "Han-%s-%s" % (self.hw_dict["hw_type"], self.hw_dict["serial_number"]))

        print("Advertising MIS via mDNS...")
        self.mis_broadcast.module_inventory_service(txtrecord)

    def advertiseService(self):
        # Leaving this in for DG as he calls it
        self.run()

    def register_service_asthread(self):
        _thread.start_new_thread(self.register_service, ())

    def unregister_service(self):
        print("Stopping MIS mDNS")
        self.mis_broadcast.unregister_service()
        time.sleep(1)

    """
    ###################################################################################################################
    MIS Functions 
    """
    def update_information(self, hw_dict):
        """
        Allows the importing class to update the hw_dict, although I am not really sure if much changes during runtime
        """
        self.hw_dict = hw_dict

    def update_blank_level(self, blank_level: int):
        """
        Used to update the blanking level
        """
        self.blank_level = blank_level

    def get_module_type(self, short=False):
        """
        Returns the ITxPT module type as defined in SO1
        """
        module_type_dict = {
            "con": ["OBU", "Generic Onboard Unit"],
            "int": ["INTD", "Internal Display"],
            "ext":  ["EXTD", "External Display"],
            "hires": ["EXTD", "External Display"],
            "tft": ["INTD", "Internal Display"]
        }

        module_type_override = self.config_dict.get("ITXPT_module_type", None)

        if module_type_override is None:
            try:
                module_type = module_type_dict[self.hw_dict["hw_type"]]
            except KeyError:
                module_type = ["OBU", "Generic Onboard Unit"]

        else:
            try:
                module_short, module_long = module_type_override.split(",")
            except ValueError:
                module_type = ["OBU", "Generic Onboard Unit"]
            else:
                module_type = [module_short, module_long]

        if short:
            return module_type[0]
        else:
            return module_type[1]

    def get_eco_status(self, blank_level: int):
        """
        Accepts an int 0-2, where 0 is full power and 2 is blanked.
        There is no support for 3, but I've added it for completeness’s sake.

        This converts the sign_task blank_levels into the MIS ecomodes:
        ECO0 | ECO1 | ECO2 | SLEEP

        Not really sure how to respond when in sleep mode...
        """
        eco_map = ["ECO0", "ECO1", "ECO2", "SLEEP"]

        try:
            eco_level = eco_map[blank_level]
        except IndexError:
            return "ECO0"
        else:
            return eco_level

    def generateMISXML(self, save):
        timestamp = time.strftime("%Y-%m-%dT%H:%M:%S")

        module_inventory_dict = {
            "ModulesDelivery": {
                "@version": self.version,
                "Module": {
                    "Type": self.get_module_type(),
                    "Model": self.hw_dict["model"],
                    "Manufacturer": "Hanover Displays",
                    "SerialNumber": self.hw_dict["serial_number"],
                    "SoftwareVersion": self.hw_dict["software_version"],
                    "HardwareVersion": self.hw_dict["hardware_version"],
                    "MACAddress": self.hw_dict["unit_MAC"],
                    "EcoMode": self.get_eco_status(self.blank_level),
                    "Status": self.hw_dict["hw_status"],
                    "XStatus": {
                        "@page": "1",
                        "@timestamp": timestamp,
                        "#text": "C0FFFFFFFFFFFFFF"
                    },
                    "Services": {
                        "ServiceName": "inventory",
                        "ServiceType": "itxpt_http"
                    }
                }
            }
        }
        mis_xml = xmltodict.unparse(module_inventory_dict, pretty=True)

        if save:
            mis_xml_file = open(os.path.join(r"/tmp", "moduleinfo.xml"), "wb")
            mis_xml_file.write(mis_xml)
            mis_xml_file.close()
        print("MIS XML Generated")

        return mis_xml

    def provide_mis_xml(self):
        return self.generateMISXML(False)

    def run(self):
        self.startHTTPServer()
        self.register_service()


if __name__ == "__main__":
    hw_dict = {
        "hw_type": "con",
        "model": "COL030",
        "manufacturer": "Hanover Displays",
        "serial_number": "123456",
        "software_version": "1.0.0",
        "hardware_version": "RevA",
        "unit_MAC": "DE:AD:BE:EF:00:00",
        "unit_IP": "127.0.0.1",
        "hw_status": "0"

    }

    conf_dict = {

    }

    mis = ModuleInventoryService(conf_dict, hw_dict)
    mis.run()

    while 1:
        try:
            time.sleep(1)
        except KeyboardInterrupt:
            mis.unregister_service()
