import struct

class BSL_Pack():
    def __init__(self):
        self.BSL_HEADER = b'\x80'
        self.CMD_PASSWORD = b'\x11'
    def password_pack(self, password):
        bsl_err = 0
        values = bytearray(password)
 #       print(values)
        DATA_Length = len(values) + 1
        DATA_Length_B = bytearray([DATA_Length])
        txdata = self.BSL_HEADER + DATA_Length_B + b'\x00' + self.CMD_PASSWORD + values
        txdata_crc = self.CMD_PASSWORD + values
        checksum = 0
        checksum = self.crc16(txdata_crc)
        # print("%x"%checksum)
        checksum_B = struct.pack('<H', checksum)
        #    print(checksum_B)
        txdata = txdata + checksum_B
        return txdata
    def firmware_pack(self, firmware):
        bsl_err = 0
        send_count = 0
        address_count = 0
        bytes_buf = b''
        addr_buf = b''
        addr_bufarray = b''
        data_array = []
        data_b_array = []
 #       with open('test0.txt', 'w+') as file_write:
 #           for line in firmware:
 #               file_write.write(line)
#        print(firmware)
        for line in firmware:
            if line[0] != 'q':
                if line[0] == '@':
                    #                data_array.append(line)
                    linel = line[1:]
                    linel = linel.rstrip()
                    address_count = int(linel, 16)
                    if send_count != 0:
                        data_array.append('&\n')
                    send_count = 0
                #                print(address)
                else:
                    #                print(line)
                    linel = line.rstrip()
                    bytes_buf = bytes.fromhex(linel)
                    send_count += len(bytes_buf)
                    address_count += len(bytes_buf)
                    if send_count > 230:
                        address_count1 = address_count - len(bytes_buf)
                        #                    print(hex(address_count1))
                        #                    print(line)
                        linel = hex(address_count1)
                        linel = linel[2:]
                        data_array.append('&\n')
                        linel = '@' + linel + '\n'
                        data_array.append(linel)
                        send_count = len(bytes_buf)
            #               data_array.append(line)
            else:
                data_array.append('&\n')
            data_array.append(line)
        #    print(data_array)
        #     with open('test1.txt', 'w+') as file_write:
        #         for line in data_array:
        #             file_write.write(line)
        bytes_buf = b''
        for line in data_array:
            if line[0] != 'q':
                if line[0] == '@':
                    send_count = 0
                    #                data_array.append(line)
                    linel = line[1:]
                    linel = linel.rstrip()
                    address_count2 = int(linel, 16)
                    #address_count = hex(int(linel, 16))
                    #                print(address_count2)
                    #                print(address_count)
                    #                print(type(address_count))
                    if address_count2 >= 0x10000:
                        linel = '0' + linel
                    addr_buf = bytes.fromhex(linel)
                    addr_bufarray = bytearray(addr_buf)
                    addr_bufarray.reverse()
                    if address_count2 < 0x10000:
                        addr_bufarray = addr_bufarray + b'\x00'
                    addr_bufarray = b'\x10' + addr_bufarray
                    #                print(addr_bufarray)
                    #                address_count_b=struct.pack('<I',address_count)
                    #                print(address_count_b)
                    bytes_buf = b''
                    DATA_Length1 = 0
                else:
                    if line[0] != '&':
                        linel = line.rstrip()
                        #                    print(linel)
                        bytes_buf += bytes.fromhex(linel)
                    else:
                        addr_bufarray += bytes_buf
                        checksum = 0
                        checksum = self.crc16(addr_bufarray)
                        # print("%x"%checksum)
                        checksum_B = struct.pack('<H', checksum)
                        #                    print(checksum_B)
                        DATA_Length1 = len(bytes_buf) + 4
                        #                    print(DATA_Length1)
                        DATA_Length1_b = struct.pack('<H', DATA_Length1)
                        #                    print(DATA_Length1_b)
                        DATA_Length1_b += addr_bufarray
                        DATA_Length1_b = b'\x80' + DATA_Length1_b + checksum_B
                        data_b_array.append(DATA_Length1_b)
        return data_b_array


    def crc16(self, data_B):
        crc = 0xFFFF
        for b in data_B:
            x = ((crc >> 8) ^ b) & 0xff
            x ^= x >> 4
            crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x
        return crc & 0xFFFF
    def set_pc_pack(self, firmware):
        start_addr = b''
        address_count = 0
        for line in firmware:
            if line[0] != 'q':
                if line[0] == '@':
                    linel = line[1:]
                    linel = linel.rstrip()
                    address_count = int(linel, 16)
                else:
                    linel = line.rstrip()
                    bytes_buf = bytes.fromhex(linel)
                    address_count += len(bytes_buf)
                    if address_count == 0xFF3E:
                        start_addr = bytes_buf[-2:] + b'\x00'
                        break
        send_data = b'\x17' + start_addr
        checksum = 0
        checksum = self.crc16(send_data)
        # print("%x"%checksum)
        checksum_B = struct.pack('<H', checksum)
        send_package = b'\x80\x04\x00' + send_data + checksum_B
        return send_package