#!/usr/bin/env python3
import time
import mqtt_service as mqtt
import datetime
import traceback
import threading
from enum import Enum
import logging
import signal
logger = logging.getLogger(__name__)

class DoorState(Enum):
    INIT = 1
    CLOSED = 2
    OPENED = 3

class doorStateMonitoringService(object):
    def __init__(self, broker            = "127.0.0.1",
                       port              = 1883,
                       user_name         = "",
                       password          = "",
                       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)

        if customerID == "":
            self.topic = "door_states/state"
        else:
            self.topic = customerID + "/" + VIN + "/hanover/door_states/state"

        self.mqttService = mqtt.mqttService("mqtt-monitoring-door-state-service",
                                            broker    = broker,
                                            port      = port,
                                            user_name = user_name,
                                            password  = password)
        
        self.door_state_dictionary = {
            "atDateTime":        "",
            "changedAt":         "",
            "state":             "CLOSED"
        }

        self.door_state = DoorState.INIT
        self.openDoors = set()
    
    def setState(self, ID, state) -> bool:
        #only allow CLOSED door state when all doors are closed
        if state == DoorState.OPENED:
            self.openDoors.add(ID)
        elif state == DoorState.CLOSED:
            if ID in self.openDoors:
                self.openDoors.remove(ID)
            if len(self.openDoors):
                state = DoorState.OPENED

        if state != self.door_state:
            self.door_state = state
            if self.door_state == DoorState.CLOSED:
                self.door_state_dictionary["state"] = "CLOSED"
            elif self.door_state == DoorState.OPENED:
                self.door_state_dictionary["state"] = "OPENED"
            self.door_state_dictionary["changedAt"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
            return True
        else:
            return False

    def publish(self):
        # only publish a valid door state once retrieved, not the initial state
        if self.door_state_dictionary["changedAt"] != "":
            self.door_state_dictionary["atDateTime"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
            logger.debug(f"publish - {self.topic}\n{self.door_state_dictionary}\n")
            self.mqttService.publish(self.topic, self.door_state_dictionary)

if __name__ == "__main__":
    logger.info("Door State Monitoring Service running in foreground")

    #use local broker to forward topics
    dsMonService = doorStateMonitoringService()
    
    dsMonService.setState("door1", DoorState.OPENED)
    dsMonService.setState("door2", DoorState.OPENED)
    dsMonService.setState("door1", DoorState.CLOSED)
    dsMonService.setState("door2", DoorState.CLOSED)

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

    while 1:
        dsMonService.publish()
        time.sleep(5)
