#!/usr/bin/env python3
import time
import mqtt_service as mqtt
import datetime
import traceback
import select
import logging
import signal
import htc_database_access as htcdb
logger = logging.getLogger(__name__)

NEXT_NODE_TOPIC         = "NEXT_NODE"
NEXT_NODE_TOPIC_PATH    = "htc_ipc/+/export_symbols/" + NEXT_NODE_TOPIC

class stopEntry(object):

    def __init__(self, stop_code, stop_name, sequence_number, latitude, longitude):
        self.stop_code = stop_code
        self.stop_name = stop_name
        self.sequence_number = sequence_number
        self.latitude = latitude
        self.longitude = longitude

class nextStopMonitoringService(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 = "next_stops/stops"
        else:
            self.topic = customerID + "/" + VIN + "/hanover/next_stops/stops"

        self.mqttService = mqtt.mqttService("mqtt-monitoring-next-stop-service",
                                            broker    = broker,
                                            port      = port,
                                            user_name = user_name,
                                            password  = password,
                                            callback = self.topicUpdated,
                                            service = self)
        
        self.topic_dictionary = {
            "atDateTime":           "",
            "expectedCalls":        []
        }

        self.next_node = ""
        self.stops = []

        self.mqttService.subscribe(NEXT_NODE_TOPIC_PATH)

        self.publish()

    def topicUpdated(mqtt, self, topic, payload):
        if topic.endswith(NEXT_NODE_TOPIC):
            next_node = payload
            self.nextNodeUpdated(next_node)

    def nextNodeUpdated(self, next_node):
        if self.next_node != next_node:

            self.next_node = next_node
            logger.debug(f"Got new next node, code: {self.next_node}")

            db = htcdb.databaseAccess()

            self.stops.clear()

            # Get the next NODE_MAX nodes, plus the end node
            NODE_MAX = 3
            node_count = 0
            while next_node and node_count <= NODE_MAX:

                logger.debug(f"using next node: {next_node}")

                point_id = db.getAttribute(next_node, "POINTID")
                logger.debug(f"point ID: {point_id}")

                stop_seq = int(db.getAttribute(next_node, "StopSeq"))
                logger.debug(f"stop sequence: {stop_seq}")

                latitude = float(db.getAttribute(point_id, "Latitude"))
                logger.debug(f"latitude: {latitude}")

                longitude = float(db.getAttribute(point_id, "Longitude"))
                logger.debug(f"longitude: {longitude}")

                name = db.getAttribute(point_id, "Name")
                logger.debug(f"name: {name}")

                stop_code = db.getAttribute(point_id, "PointIdentifier")
                logger.debug(f"stop code: {stop_code}")

                stop = stopEntry(stop_code, name, stop_seq, latitude, longitude)
                self.stops.append(stop)

                if node_count < NODE_MAX - 1:
                    next_next_node = db.getAttribute(next_node, "NEXT_STOP")
                else:
                    route = db.getAttribute(next_node, "RouteId")
                    logger.debug(f"route: {route}")
                    next_next_node = db.getAttribute(route, "EndNode")

                logger.debug(f"next next node: {next_next_node}")
                next_node = next_next_node

                node_count = node_count + 1

            self.publish()

    def updateDictionary(self):
        self.topic_dictionary["atDateTime"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
        self.topic_dictionary["expectedCalls"].clear()

        for stop in self.stops:

            expectedCall = {}

            expectedCall["stopCode"] = stop.stop_code

            stop_names_dict = {
                "langCode":             "en",
                "text":                 stop.stop_name
            }

            expectedCall["stopNames"] = stop_names_dict
            expectedCall["sequenceNumber"] = stop.sequence_number

            lat = stop.latitude
            lat_dir = "E"
            long = stop.longitude
            long_dir = "N"

            # check for negative values and convert to absolute with directions
            if lat < 0:
                lat = abs(lat)
                lat_dir = "W"
            if long < 0:
                long = abs(long)
                long_dir = "S"

            lat_dict = {
                "degree": lat,
                "direction": lat_dir
            }

            long_dict = {
                "degree": long,
                "direction": long_dir
            }

            location_dict = {
                "latitude": lat_dict,
                "longitude": long_dict
            }

            expectedCall["location"] = location_dict

            self.topic_dictionary["expectedCalls"].append(expectedCall)

    def publish(self):
        self.updateDictionary()

        logger.debug(f"publish - {self.topic}\n{self.topic_dictionary}\n")
        self.mqttService.publish(self.topic, self.topic_dictionary)

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

    #use local broker to forward topics
    nextStopMonitoringService = nextStopMonitoringService()

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

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