# coding=UTF-8
import struct
# import common_util
import binascii

profile = [{"tag": 128, "identifier": "Error", "dataType": "eventOutputData", "eventOutputData": [{"tag": 1, "identifier": "ErrorCode", "dataType": "uint8_t"}]},
           {"tag": 144, "identifier": "SyncTime", "dataType": "serviceData", "serviceInputData": [{"tag": 1, "identifier": "LocalTime", "dataType": "text"}]},
           {"tag": 1, "identifier": "LightSwitch", "dataType": "uint8_t"},
           {"tag": 2, "identifier": "ColorTemperature", "dataType": "uint32_t"},
           {"tag": 3, "identifier": "Brightness", "dataType": "uint32_t"},
           {"tag": 4, "identifier": "LightMode", "dataType": "uint8_t"},
           {"tag": 5, "identifier": "HSVColor", "dataType": "struct", "struct": [{"tag": 1, "identifier": "Hue", "dataType": "uint16_t"},
                                                                                 {"tag": 2, "identifier": "Saturation", "dataType": "uint8_t"},
                                                                                 {"tag": 3, "identifier": "Value", "dataType": "uint8_t"}]},
            {"tag": 6, "identifier": "RSSI", "dataType": "int8_t"}]

# "<":小端 ">" 大端
ENDIAN_MODE = "<" 
# 物联网平台Topic，设备上传属性数据到云端。
ALINK_PROP_REPORT_METHOD = 'thing.event.property.post'
# 物联网平台Topic，云端下发属性控制指令到设备端。 
ALINK_PROP_SET_METHOD = 'thing.service.property.set' 
# 物联网平台Topic，设备上报属性设置的结果到云端。
ALINK_PROP_SET_REPLY_METHOD = 'thing.service.property.set'


# 示例数据：
# 设备上报属性数据：
# 传入参数：
#    0x010100
# 输出结果：
#    {"method":"thing.event.property.post","id":"1","params":{"LightSwitch":0},"version":"1.0"}
# 属性设置的返回结果：
# 传入参数：
#    0x0300223344c8
# 输出结果：
#    {"code":"200","data":{},"id":"2241348","version":"1.0"}

def raw_data_to_protocol(bytes):
    # print "Decoding %s..." % binascii.hexlify(bytes)

    uint8Array = []
    for byteValue in bytes:
        uint8Array.append(byteValue & 0xff)

    raw_data = str(bytearray(uint8Array))

    params = {}
    reprofile = profile
    is_prop = 0 # 1=属性 2=事件
    eventIdentifier = ""

    HEAD = 2

    while raw_data:
        tag, length = struct.unpack('BB', raw_data[:HEAD])
        value = raw_data[HEAD:(HEAD+length)]

        # print "tag=%d length=%d" % (tag, length)

        for i in range(len(reprofile)):
            if reprofile[i]["tag"] == tag:
                if is_prop == 0:
                    if reprofile[i]["dataType"] == "eventOutputData":
                        eventIdentifier = reprofile[i]["identifier"]
                        reprofile = reprofile[i]["eventOutputData"]
                        is_prop = 2
                        break
                    else:
                        is_prop = 1
                if reprofile[i]["dataType"] == "int8_t":
                    params[reprofile[i]["identifier"]] = bytes_to_int8_t(value)
                elif reprofile[i]["dataType"] == "uint8_t":
                    params[reprofile[i]["identifier"]] = bytes_to_uint8_t(value)
                elif reprofile[i]["dataType"] == "int16_t":
                    params[reprofile[i]["identifier"]] = bytes_to_int16_t(value)
                elif reprofile[i]["dataType"] == "uint16_t":
                    params[reprofile[i]["identifier"]] = bytes_to_uint16_t(value)
                elif reprofile[i]["dataType"] == "int32_t":
                    params[reprofile[i]["identifier"]] = bytes_to_int32_t(value)
                elif reprofile[i]["dataType"] == "uint32_t":
                    params[reprofile[i]["identifier"]] = bytes_to_uint32_t(value)
                elif reprofile[i]["dataType"] == "float":
                    params[reprofile[i]["identifier"]] = bytes_to_float(value)
                elif reprofile[i]["dataType"] == "double":
                    params[reprofile[i]["identifier"]] = bytes_to_double(value)
                elif reprofile[i]["dataType"] == "text":
                    params[reprofile[i]["identifier"]] = bytes_to_text(value)
                elif reprofile[i]["dataType"] == "struct":
                    id = reprofile[i]["identifier"]
                    params_s = {}
                    profile_s = reprofile[i]["struct"]
                    # print "Decoding %s..." % binascii.hexlify(value)
                    print profile_s
                    while value:
                        struct_tag, struct_length = struct.unpack("BB", value[:HEAD])
                        struct_value = value[HEAD:(HEAD+struct_length)]

                        # print "stag=%d slength=%d" % (struct_tag, struct_length)

                        for j in range(len(profile_s)):
                            # print "j:%d id:%s dt:%s" % (j, profile_s[j]["identifier"], profile_s[j]["dataType"])
                            if profile_s[j]["tag"] == struct_tag:
                                if profile_s[j]["dataType"] == "uint8_t":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_uint8_t(struct_value)
                                elif profile_s[j]["dataType"] == "int8_t":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_int8_t(struct_value)
                                elif profile_s[j]["dataType"] == "uint16_t":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_uint16_t(struct_value)
                                elif profile_s[j]["dataType"] == "int16_t":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_int16_t(struct_value)
                                elif profile_s[j]["dataType"] == "uint32_t":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_uint32_t(struct_value)
                                elif profile_s[j]["dataType"] == "int32_t":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_int32_t(struct_value)
                                elif profile_s[j]["dataType"] == "float":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_float(struct_value)
                                elif profile_s[j]["dataType"] == "double":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_double(struct_value)
                                elif profile_s[j]["dataType"] == "text":
                                    params_s[profile_s[j]["identifier"]] = bytes_to_text(struct_value)
                        value = value[(HEAD+struct_length):]

                    params[reprofile[i]["identifier"]] = params_s
 
        raw_data = raw_data[(HEAD+length):]

    jsonMap = {}
    if is_prop == 1:
        jsonMap['method'] = ALINK_PROP_REPORT_METHOD
        jsonMap['version'] = '1.0'
        jsonMap['id'] = '1'
        jsonMap['params'] = params
    elif is_prop == 2:
        jsonMap['method'] = 'thing.event.'+eventIdentifier+'.post'
        jsonMap['version'] = '1.0'
        jsonMap['id'] = '1'
        jsonMap['params'] = params 

    return jsonMap


# 示例数据：
# 云端下发属性设置指令：
# 传入参数：
#    {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"LightSwitch":1}}
# 输出结果：
#    0x010101
# 设备上报的返回结果：
# 传入数据：
#    {"method":"thing.event.property.post","id":"12345","version":"1.0","code":200,"data":{}}
# 输出结果 ->
#    0x0200003039c8
def protocol_to_raw_data(json):
    method = json.get('method', None)
    id = json.get('id', None)
    version = json.get('version', None)
    payload_array = []
    is_param = 0
    serviceIdentifier = ''
    reprofile = profile

    if method == ALINK_PROP_REPORT_METHOD:
        payload_array = text_to_bytes("report reply")
        return payload_array
    elif method == ALINK_PROP_SET_METHOD:
        is_param = 1
    else:
        serviceIdentifier = method[len('thing.service.'):]
        for i in range(len(profile)):
            if profile[i]['identifier'] == serviceIdentifier:
                print 'find'
                reprofile = profile[i]["serviceInputData"]
                payload_array.append(profile[i]['tag'])
                payload_array.append(1)
                payload_array.append(1)
                is_param = 2
                break

    if is_param == 1 or is_param == 2:
        params = json.get('params', None)
        for i in range(len(reprofile)):
            for key, values in params.items():
                if reprofile[i]["identifier"] == key:
                    payload_array.append(reprofile[i]["tag"])
                    if reprofile[i]["dataType"] == "int8_t":
                        payload_array.append(1)
                        payload_array = payload_array + int8_t_to_bytes(values)
                    elif reprofile[i]["dataType"] == "uint8_t":
                        payload_array.append(1)
                        payload_array = payload_array + uint8_t_to_bytes(values)
                    elif reprofile[i]["dataType"] == "int16_t":
                        payload_array.append(2)
                        payload_array = payload_array + int16_t_to_bytes(values)
                    elif reprofile[i]["dataType"] == "uint16_t":
                        payload_array.append(2)
                        payload_array = payload_array + uint16_t_to_bytes(values)
                    elif reprofile[i]["dataType"] == "int32_t":
                        payload_array.append(4)
                        payload_array = payload_array + int32_t_to_bytes(values)
                    elif reprofile[i]["dataType"] == "uint32_t":
                        payload_array.append(4)
                        payload_array = payload_array + int32_t_to_bytes(values)
                    elif reprofile[i]["dataType"] == "float":
                        payload_array.append(4)
                        payload_array = payload_array + float_to_bytes(values)
                    elif reprofile[i]["dataType"] == "double":
                        payload_array.append(8)
                        payload_array = payload_array + double_to_bytes(values)
                    elif reprofile[i]["dataType"] == "text":
                        payload_array.append(len(values))
                        payload_array = payload_array + text_to_bytes(values)
                    elif reprofile[i]["dataType"] == "struct":
                        payload_array_s = []
                        reprofile_s = reprofile[i]["struct"]
                        for j in range(len(reprofile_s)):
                            for key_s, values_s in values.items():
                                if reprofile_s[j]["identifier"] == key_s:
                                    # print "k=%s v=%d" % (key_s, values_s)
                                    payload_array_s.append(reprofile_s[j]["tag"])
                                    if reprofile_s[j]["dataType"] == "int8_t":
                                        payload_array_s.append(1)
                                        payload_array_s = payload_array_s + int8_t_to_bytes(values_s)
                                    if reprofile_s[j]["dataType"] == "uint8_t":
                                        payload_array_s.append(1)
                                        payload_array_s = payload_array_s + uint8_t_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "int16_t":
                                        payload_array_s.append(2)
                                        payload_array_s = payload_array_s + int16_t_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "uint16_t":
                                        payload_array_s.append(2)
                                        payload_array_s = payload_array_s + uint16_t_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "int32_t":
                                        payload_array_s.append(4)
                                        payload_array_s = payload_array_s + int32_t_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "uint32_t":
                                        payload_array_s.append(4)
                                        payload_array_s = payload_array_s + uint32_t_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "float":
                                        payload_array_s.append(4)
                                        payload_array_s = payload_array_s + float_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "double":
                                        payload_array_s.append(8)
                                        payload_array_s = payload_array_s + double_to_bytes(values_s)
                                    elif reprofile_s[j]["dataType"] == "text":
                                        payload_array_s.append(len(values_s))
                                        payload_array_s = payload_array_s +  text_to_bytes(values_s)
                        payload_array.append(len(payload_array_s))
                        payload_array = payload_array + payload_array_s

    return payload_array


#  示例数据：
#  自定义Topic：
#      /user/update，上报数据。
#  输入参数：
#      topic:/{productKey}/{deviceName}/user/update
#      bytes: 0x000000000100320100000000
#  输出参数：
#  {
#     "prop_float": 0,
#     "prop_int16": 50,
#     "prop_bool": 1,
#     "topic": "/{productKey}/{deviceName}/user/update"
#   }
def transform_payload(topic, bytes):
    jsonMap = {}
    return jsonMap

# byte转成int8_t。
def bytes_to_int8_t(bytes):
    return struct.unpack(ENDIAN_MODE+"b", bytes)[0]

# byte转成uint8_t。
def bytes_to_uint8_t(bytes):
    return struct.unpack(ENDIAN_MODE+"B", bytes)[0]

# byte转成int16_t。
def bytes_to_int16_t(bytes):
    return struct.unpack(ENDIAN_MODE+"h", bytes)[0]

# byte转成uint16_t。
def bytes_to_uint16_t(bytes):
    return struct.unpack(ENDIAN_MODE+"H", bytes)[0]

# byte转成int32_t。
def bytes_to_int32_t(bytes):
    return struct.unpack(ENDIAN_MODE+"i", bytes)[0]

# byte转成uint32_t。
def bytes_to_uint32_t(bytes):
    return struct.unpack(ENDIAN_MODE+"I", bytes)[0]

# byte转成float，不带精度。
def bytes_to_float(bytes):
    return struct.unpack(ENDIAN_MODE+'f', bytes)[0]

# byte转成double，不带精度。
def bytes_to_double(bytes):
    return struct.unpack(ENDIAN_MODE+'d', bytes)[0]

# byte转成string
def bytes_to_text(bytes):
    return bytes

# 8位整形转成byte数组。
# def char_to_bytes(value):
#     t_value = '%02X' % value
#     if len(t_value) % 2 != 0:
#         t_value += '0'

#     return hex_string_to_byte_array(t_value)

def int8_t_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"b", value).encode('hex'))

def uint8_t_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"B", value).encode('hex'))

def int16_t_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"h", value).encode('hex'))

def uint16_t_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"H", value).encode('hex'))

def int32_t_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"i", value).encode('hex'))

def uint32_t_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"I", value).encode('hex'))

# float转成整形数组。
def float_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"f", value).encode('hex'))

def double_to_bytes(value):
    return hex_string_to_byte_array(struct.pack(ENDIAN_MODE+"d", value).encode('hex'))


def text_to_bytes(value):
    res = []
    for i in range(len(value)):
        res = res + hex_string_to_byte_array(value[i].encode('hex'))
    return res


# 16进制字符串转成byte数组。
def hex_string_to_byte_array(str_value):
    if len(str_value) % 2 != 0:
        return None

    cycle = len(str_value) / 2

    pos = 0
    result = []
    for i in range(0, cycle, 1):
        temp_str_value = str_value[pos:pos + 2]
        temp_int_value = int(temp_str_value, base=16)

        result.append(temp_int_value)
        pos += 2
    return result

# rawdata = [1,1,1]
# rawdata = [128, 1, 1, 1, 1, 1]
# rawdata = [1,1,1,2,4,1,0,0,0]
# rawdata = [5, 10, 1, 2, 1, 0, 2, 1, 2, 3, 1, 3]
# rawdata = [6,1,255]
# string = raw_data_to_protocol(rawdata)
# print string

# json_string = {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"LightSwitch":1,"Common":"123456"}}
# json_string = {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{'LightSwitch': 1, 'ColorTemperature': 1}}
# json_string = {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{"HSVColor":{"Hue":1, "Saturation":2, "Value":3}}}
# json_string = {"method":"thing.service.SyncTime","id":"12345","version":"1.0","params":{"LocalTime":"123"}}
# json_string = {"method":"thing.service.property.set","id":"12345","version":"1.0","params":{'RSSI': -1}}

# hexaray = protocol_to_raw_data(json_string)
# print hexaray
