import logging
import re

from LCM.SyslogPublisher import LcmPublisher
from app.Nema import NemaBase
from app.UdpSocket import UdpListener

logger = logging.getLogger("backseat")


class AltitudeBridge(LcmPublisher, UdpListener, NemaBase):


    def __init__(self, lcm):
        logger.info("Creating AltitudeBridge.")
        LcmPublisher.__init__(self, lcm)
        UdpListener.__init__(self, port=5555)

        self.add_float("_.height_above_sea_floor", -1, "meter")
        self.altitude = -1

        self.run = True



    def parse_altitude(self, nema_str: str):
        """
        Extracts altitude in meters from a NEMA DBDBT sentence.

        NEMA $DBDBT:

            Example Output:
                $DBDBT,603.84,f,184.05,M,100.64,F*25

            The Delimited Fields:
                1 = data type = $DBDBT
                2 = distance value in feet to 2 decimal places
                3 = noting the preceding value is in feet = f
                4 = distance value in meters to 2 decimal places
                5 = noting the preceding value is in meters = M
                6 = distance value in fathoms to 2 decimal places
                7 = noting the preceding value is in fathoms = F

                * = the end of the data fields and the break before the check sum
                Check sum = 2 digit hexadecimal value

        Args:
            nema_str: string containing DBDBT NEMA sentence.

        Returns: true upon successful parse.

        """

        # split the NEMA message to payload/checksum
        nema_split = nema_str.split("*")

        try:
            # get the NEMA message checksum
            nema_checksum = int(nema_split[1], 16)
        except IndexError:
            logger.error("Failed to extract NEMA checksum from message.")
            return False

        try:
            # get the NEMA message payload excluding the leading "$"
            nema_payload = nema_split[0][1:]
        except IndexError:
            logger.error("Failed to extract NEMA payload from message.")
            return False

        # verify checksum match
        if nema_checksum != self.checksum(nema_payload):
            logger.error("NEMA checksum did not match.")
            return False

        # extract altitude in meters
        self.altitude = float(re.findall(r"[-+]?\d*\.?\d+", nema_payload)[1])
        return True


    def handle(self):

        # listen for data on the designated UDP port
        data = self.listen(timeout_sec=0.1)

        if data and self.parse_altitude(data) and self.altitude:

            # update the LCM message and publish to LRAUV front-seat
            self.assign_value("_.height_above_sea_floor", self.altitude)
            self.publish("tethys_data")
            self.altitude = None


    def spin(self):
        logger.info("Starting altitude bridge.")
        while self.run:
            self.handle()


    def stop(self):
        logger.info("Stopping altitude bridge.")
        self.run = False
