#!/usr/bin/python

# ============================ adjust path =====================================

import sys

import struct
from datetime import date

if __name__ == '__main__':
    here = sys.path[0]
    #sys.path.insert(0, os.path.join(here, '..'))

# ============================ imports =========================================

import Tkinter

import hartFields

# ============================ body ============================================

class hartFrameResponse(hartFields.hartFields):
    def __init__(self, parentElem, guiLock,hartDef, frameName="HART response", row=0, column=0):
        # init parent
        self.hartDef = hartDef
        hartFields.hartFields.__init__(
            self,
            parentElem=parentElem,
            guiLock=guiLock,
            hartDef=hartDef,
            frameName=frameName,
            row=row,
            column=column,
        )

        # ======================== public ==========================================
    def decodeHartResponse(self, hartResponse):

        #HART data start at fifth byte
        dataByte = 5
        # this is minimum length of HART response
        if len(hartResponse) >= 6:
            self.cmdNum  = hartResponse[2]*256 + hartResponse[3]
            self.dataLen = hartResponse[4]
            if self.dataLen == len(hartResponse[5:]):
                commandDef = self.hartDef.getCommandFromId(self.cmdNum)
                fieldNames = self.hartDef.getResponseFieldNames([commandDef['name']])

                # build the response fields
                responseFields = {fieldNames[i]: None for i in range(len(fieldNames))}

                try:
                    for field in fieldNames:
                        fieldLen    = self.hartDef.getResponseFieldLength([commandDef['name']], field )
                        fieldFormat = self.hartDef.getResponseFieldFormat([commandDef['name']], field )

                        if fieldFormat == 'hex':
                            responseFields[field] = []
                            for i in reversed(range(fieldLen)):
                                responseFields[field].append(hartResponse[dataByte])
                                dataByte += 1

                        if fieldFormat == 'int':
                            responseFields[field] = 0
                            for i in reversed(range(fieldLen)):
                                responseFields[field] += (hartResponse[dataByte] << 8 * i)
                                dataByte += 1

                        if fieldFormat == 'string':
                            a = ""
                            for i in reversed(range(fieldLen)):
                                if hartResponse[dataByte] != 0:
                                    a += chr(hartResponse[dataByte])
                                dataByte += 1
                            responseFields[field]= a.decode('latin-1')

                        if fieldFormat == 'float':
                            a = ""
                            for i in reversed(range(fieldLen)):
                                a += chr(hartResponse[dataByte + i])
                            dataByte += 4
                            b = struct.unpack('f', a)
                            responseFields[field] = b[0]

                        if fieldFormat == 'date':
                            hart_date = date(hartResponse[dataByte + 2] + 1990,
                                             hartResponse[dataByte + 1],
                                             hartResponse[dataByte])
                            responseFields[field] = str(hart_date)

                        if fieldFormat == 'packed':
                            a = ""
                            for i in reversed(range(fieldLen/3)):
                                b = [0,0,0,0]
                                b[0] = (hartResponse[dataByte] & 0xFC) >> 2
                                b[1] = ((hartResponse[dataByte] & 0x03) << 4) | ((hartResponse[dataByte + 1] & 0xF0) >> 4)
                                b[2] = ((hartResponse[dataByte + 1] & 0x0F) << 2) | ((hartResponse[dataByte + 2] & 0xC0) >> 6)
                                b[3] = hartResponse[dataByte + 2] & 0x3F
                                print(b)
                                for j in range(0, 4):
                                    if b[j] < 0x20:
                                        b[j] += 0x40
                                    if b[j] != 0x20: #space symbol
                                        a += chr(b[j])
                                dataByte += 3

                            responseFields[field] = a.decode('ascii')

                    #print(responseFields)

                    #show the fields
                    self.indicateFields([commandDef['name']], responseFields)
                    return responseFields

                except:
                    print("error code received")

                    # build the response fields
                    responseFields = {'RC': hartResponse[5]}
                    #print(responseFields)
                    self.indicateError([commandDef['name']], responseFields)
                    return responseFields
            else:
                print('Invalid Length of Data Field')
        else:
            print('Too few response bytes received')




        # ======================== private =========================================


# ============================ sample app ======================================
# The following gets called only if you run this module as a standalone app, by
# double-clicking on this source file. This code is NOT executed when importing
# this module is a larger application
#
class exampleApp(object):
    def __init__(self):
        self.window = dustWindow(
            "dustFrameResponse",
            self._closeCb,
        )

        hartDef = hartDefinition.hartDefinition()

        self.guiLock = threading.Lock()
        self.frame = hartFrameResponse(
            self.window,
            self.guiLock,
            hartDef = hartDef,
            row=0,
            column=0,
        )
        self.frame.show()

        #rawHartResponse = [0,0,0,72,2,0,1] # CMD72 SQUAWK
        #rawHartResponse = [0, 0, 0, 103, 10, 0,1,0,0,0,4,0,0,0,5]  # CMD103 WriteBurstPeriod
        #rawHartResponse = [0, 0, 0, 20, 33, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 97,98]  # CMD20 ReadLongTag
        #rawHartResponse = [8, 0, 0, 0, 23, 0, 254, 226, 142, 5, 7, 1, 1, 12, 9, 0, 0, 6, 5, 4, 0, 0, 0, 0, 4, 0, 4, 130] # CMD1 Read UID
        rawHartResponse = [8, 0, 0, 13, 22, 0, 4, 66, 109, 52, 245, 5, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 23, 6, 3] # CMD13
        self.frame.decodeHartResponse(rawHartResponse)

        #fields = {'RC':0,'Squawk Control': 1}
        #self.frame.indicateFields(['72: Squawk'], fields)
        #fields = {'RC':0,'Polling Address': 200, 'Loop Current Mode': 1}
        #self.frame.indicateFields(['7: Read Loop Configuration'], fields)
        #fields = {'RC':0,'Burst Message': 1, 'Update Period': 32000, 'Maximum Update Period': 33000}
        #self.frame.indicateFields(['103: Write Burst Period'], fields)
        #fields = {'RC':0,'Long Tag': 'abc'}
        #self.frame.indicateFields(['20: Read Long Tag'], fields)


        self.window.mainloop()

    def _closeCb(self):
        print " _closeCb called"


if __name__ == '__main__':
    import threading
    from dustUI.dustWindow import dustWindow
    import hartDefinition

    exampleApp()