"""
Name: hcp
Title: 
Author: Cooper
Date: 29/08/2018

Desc:  Just a very basic HCP encoder.  Does what it says on the tin!

Note:
-----
Needs extending to cope with LRC checking as well as generation.
Also to decode and deliver payloads.

"""

import json
from hanip.debug.print_text import PrintText

class HCP(object):
    def __init__(self):
        pass

    def genCheckSum(self, input):
        sum = 0
        for c in input:
            sum += ord(c)

        check = ("%02X" % ((256 - (sum % 256)) & 0xFF))

        return check

    def encodeMaster(self, message):
        stx = "\x02"
        etx = "\x03"

        message = message + etx
        check = self.genCheckSum(message)

        return stx + message + check

    def encodeSlave(self, message):
        sot = "\x01"
        eot = "\x04"

        message = message + eot
        check = self.genCheckSum(message)

        return sot + message + check

class HMFError(Exception):
    def __init__(self, msg=""):
        self.msg = msg

    def __str__(self):
        return self.msg

class RawHMFmsg(object):

    STX = 0x02
    ETX = 0x03
    SOH = 0x01
    EOT = 0x04

    CMD_LH_TEXT = 0x00
    CMD_GRAPHIC = 0x01
    CMD_STATUS = 0x02
    CMD_TEST_MSG = 0x03
    CMD_RH_TEXT = 0x04
    CMD_ADVERT = 0x05
    CMD_RN_BROAD = 0x06
    CMD_TTS = 0x07
    CMD_EXT_STAT = 0x09
    CMD_CLEAR = 0x0C
    CMD_ESC_BIN = 0x0E
    CMD_PARAM_B = 0x0F

    def __init__(self, msg, route_number=None):
        msgLen = len(msg)
        if msgLen >= 3 and (ord(msg[0]) == RawHMFmsg.STX or ord(msg[0]) == RawHMFmsg.SOH):
            self.body = msg[3:msgLen - 3]
            self.header = msg[:1]
            self.command = int(msg[1], 16)
            self.address = int(msg[2], 16)
            self.tail = msg[msgLen - 3]
            self.checksum = msg[msgLen - 2:]
            self.isMasterMsg = ord(self.header) == RawHMFmsg.STX
            self.isValid = True
            self.route_number = route_number.lstrip("0")
        else:
            raise HMFError("Bad Input to RawHMFmsg!\n%d bytes\n%s\n" % (msgLen, PrintText.to_ascii(msg)))

    def encodeAsJSON(self):
        """
        Encode a message in a format suitable for sending over MQTT.
        Parameter
        ---------
        msg: str
            Raw HMF message, including all message elements
        Returns
            JSON string containing the message with HCP Command and HCP Address exposed.
        """
        jsonDict = {}
        jsonDict["type"] = "rawHMF"
        jsonDict["header"] = self.header
        jsonDict["command"] = self.command
        jsonDict["address"] = self.address
        jsonDict["body"] = self.body
        jsonDict["tail"] = self.tail
        jsonDict["checksum"] = self.checksum
        jsonDict["route_number"] = self.route_number
        result = json.dumps(jsonDict, indent=4, separators=(',', ': '))
        return result

    def extractHMF(self):
        """
        Decode a dictionary as a byte array suitable for sending as an HMF message
        Parameter
        ---------
        msgDict: dict
            Contains the raw message, together with the HMF Command and HCP Address.
        """
        result = "%c%X%X%s%c%s" % (self.header, self.command, self.address, self.body, self.tail, self.checksum)
        return result

    def validate(self):
        hcp = HCP()
        summable = self.extractHMF()[1:-2]
        rxSum = hcp.genCheckSum(summable)
        self.isValid = (rxSum == self.checksum)
        if not self.isValid:
            print(summable)
            print("RxSum: %s, Checksum: %s" % (rxSum, self.checksum))
        return self.isValid

    def isShortStatusQuery(self):
        result = (self.command == 2) and (self.address != 0) and self.isValid
        return result

    def isShortStatusReply(self):
        result = (self.command == 2) and not self.isMasterMsg and self.isValid
        return result

    def isDisplayGraphicMsg(self):
        result = self.command == 1 and self.isMasterMsg and self.isValid
        return result

    def isDisplayTestMsg(self):
        result = self.command == 3 and self.isMasterMsg and self.isValid
        return result

    def isDisplayLHtextMsg(self):
        result = self.command == 0 and self.isMasterMsg and self.isValid
        return result

    def isDisplayRHtextMsg(self):
        result = self.command == 4 and self.isMasterMsg and self.isValid
        return result

    def isRouteNumberMsg(self):
        result = self.command == 6 and self.isMasterMsg and self.isValid
        return result

    def isExtStatusQuery(self):
        result = self.command == 9 and self.isMasterMsg and self.isValid
        return result

    def isExtStatusReply(self):
        result = (self.command == 9) and not self.isMasterMsg and self.isValid
        return result

    def isClearSignMsg(self):
        result = (self.command == 0x0C) and self.isValid
        return result

    def isEscapedBinaryMsg(self):
        result = (self.command ==0x45) and self.isValid
        return result

class ShortStatusQuery(RawHMFmsg):
    def __init__(self, hcpAddress):
        self.hcp = HCP()
        body = "2"
        body = body + "%0X" % (hcpAddress & 0x0F)
        source = self.hcp.encodeMaster(body)
        super().__init__(source)

class ShortStatusResponse(RawHMFmsg):
    def __init__(self, msg):
        super().__init__(msg)

    def getStatusReply(self):
        reply = self.body[1:3]
        return reply

    def getStatusAsInt(self):
        return int(self.getStatusReply(), 16)

class AssembledHMFmsg(RawHMFmsg):
    def __init__(self, command, hcpAddress, contents, master):
        hcp = HCP()
        body = "%s%s%s" % (command, hcpAddress, contents)
        if master:
            msg = hcp.encodeMaster(body)
        else:
            msg = hcp.encodeSlave(body)
        super().__init__(msg)

class HMFmsgFromJSON(RawHMFmsg):
    def __init__(self, jsonStr):
        jsonDict = json.loads(jsonStr)
        self.header = jsonDict["header"]
        self.command = int(jsonDict["command"])
        self.address = int(jsonDict["address"])
        self.body = jsonDict["body"]
        self.tail = jsonDict["tail"]
        self.checksum = jsonDict["checksum"]
        self.isMasterMsg = ord(self.header) == RawHMFmsg.STX
        self.route_number = jsonDict.get("route_number", None)

def printAscii(stuff):
    #Need to remove, as this function has been moved to debug.print_text
    temp = ""
    for x in stuff:
        x_ = ord(x)
        if x_ < 33 or x_ > 126:
            temp += ("<0x%02X>" % x_)
        else:
            temp += x
    print(temp)

def testMain():

    """

    """
    hcpEnc = HCP()
    stuff = ""
    listenPort = serial.Serial("/dev/ttyS2", 115200, 8, "N", stopbits=1, timeout=0.1)
    if listenPort.isOpen():
        print("listenPort Open...")
        body = []
        tail = 0
        while True:
            for c in listenPort.read():
                body.append(chr(c))
                if c == 0x03:
                    tail = 1
                elif tail == 1:
                    tail = 2
                elif tail == 2:
                    tail = 0
                    stuff = "".join(x for x in body)
                    example = RawHMFmsg(stuff)
                    if example.isShortStatusQuery():
                        print("Status Query for HCP Addr: ", example.address)
                        reply = hcpEnc.encodeSlave("0").encode("latin-1")
                        listenPort.write(reply)
                        print("Sent: ", reply)
                    else:
                        print("JSON:")
                        print(example.encodeAsJSON())
                        print("HCP Message:")
                        printAscii(example.extractHMF())
                    body = []
    else:
        print("Could not open serial port.")


    hiccup = HCP()
    print("Graphics Message:")
    weird = "1F2A3034524C32382A0000000000000000000000000000000000000000000\
0000000000000000000000000000000000000000000000000000000000000000000000\
00000000000000000180018FF1FFF0F0000E307F30F381C181818181818381CF30FE30\
70000F81FF81F3000180018001800F81FF01F0000FF1FFF1F8001C003E007700E381C1\
81800100000E307F30F381C181818181818381CF30FE3070000F8FFF8FF300C1818181\
81818381CF00FE0070000FB1FFB1F0000F81FF81F3000180018001800F81FF01F0000E\
003F06738EE18CC18CC18CC30E6F87FF83F00000000000000000000"
    print(weird, "[", len(weird), "]")
    example = RawHMFmsg(hiccup.encodeMaster(weird))
    print(example.encodeAsJSON())
    print("HMF msg:")
    printAscii(example.extractHMF())
    print("Is MasterMsg:", example.isMasterMsg)

    print("\nStatus Query:")
    example = ShortStatusQuery(0xFF)
    print("Verified SSQ: ", example.isShortStatusQuery())
    print(example.encodeAsJSON())
    print("HMF msg:")
    printAscii(example.extractHMF())

    print("\nStatus Response:")
    example = ShortStatusResponse(hiccup.encodeSlave("2F08"))
    print("Verified SSR: ", example.isShortStatusReply())
    print(example.encodeAsJSON())
    print("HMF msg:")
    printAscii(example.extractHMF())
    print("Status Value: ", example.getStatusReply())
    print("Status as Int: 0x%02X" % example.getStatusAsInt())

    print("\nAssembled SuperX Message:")
    cmd = "0"
    addr = "4"
    content = r"{\mode0\fl\rep3 Flash}{\mode0\sl\rep1 Scroll}{\mode0\pt20 Static}"
    example = AssembledHMFmsg(cmd, addr, content, True)
    print(example.encodeAsJSON())
    print("HMF msg:")
    printAscii(example.extractHMF())

    print("\nJSON string to HMF Message:")
    example = RawHMFmsg(hiccup.encodeMaster(weird))
    jsonStr = example.encodeAsJSON()
    print(jsonStr)
    thing = HMFmsgFromJSON(jsonStr)
    print("Is Master: ", thing.isMasterMsg)
    print("HMF msg:")
    printAscii(thing.extractHMF())

if __name__ == "__main__":
    import serial
    import os
    import sys
    import time
    testMain()
