import datetime
import hashlib
import sys
import time

import requests

sys.path.append("..")

import uuid
import message_pb2 as message
import google.protobuf.text_format as tf
import http_client
import mytool.db_helper.db_operation as spmng

MeasureStatu = {"ok": message.MeasureStatu.Value('Measure_OK'),
                "无数据": message.MeasureStatu.Value('Measure_Empty_Clouds'),
                "噪声": message.MeasureStatu.Value('Measure_Failture'),
                "PLC超界": message.MeasureStatu.Value('Measure_Border'),
                "终端超界": message.MeasureStatu.Value('Measure_Terminal_Border'),
                "失去连接": message.MeasureStatu.Value('Lidar_Disconnect')
                }
Range_status = {"未超界": message.Range_status.Value('Range_correct'),
                "前超界": message.Range_status.Value('Range_front'),
                "后超界": message.Range_status.Value('Range_back'),
                "左超界": message.Range_status.Value('Range_left'),
                "右超界": message.Range_status.Value('Range_right'),
                "底盘超界": message.Range_status.Value('Range_bottom'),
                "车顶超界": message.Range_status.Value('Range_top'),
                "车宽超界": message.Range_status.Value('Range_car_width'),
                "轴距超界": message.Range_status.Value('Range_car_wheelbase'),
                "左旋转超界": message.Range_status.Value('Range_angle_anti_clock'),
                "右旋转超界": message.Range_status.Value('Range_angle_clock'),
                "方向盘未回正": message.Range_status.Value('Range_steering_wheel_nozero'),
                "车辆移动": message.Range_status.Value('Range_car_moving')
                }


class CommandChecker:
    def __init__(self, db_config):
        self.db = spmng.DBOperation(db_config['db_ip'], db_config['db_port'], db_config['db_name'],
                                    db_config['db_user'], db_config['db_password'])
        self._dispatch_statu = {}
        self._measure_statu = {}


    def receive_dispatch_statu(self, statu, ex, key):
        self._dispatch_statu[key] = statu

    def receive_measure_info(self, statu, ex, key):
        self._measure_statu[key] = statu


    # 检查存车指令
    def entrance_isOK(self, park_body):
        # 停车表单
        park_table = message.park_table()
        try:
            tf.Parse(park_body, park_table)
        except Exception as e:
            park_table.statu.execute_statu = message.eError
            park_table.statu.statu_description = "设备故障，请联系管理员!" + "(停车表单错误)" + str(e.args)
            return park_table
        # 检查调度状态
        dispatch_key = "dispatch_%d_statu_port" % park_table.unit_id
        if (dispatch_key in self._dispatch_statu) is False or self._dispatch_statu[dispatch_key].timeout():
            park_table.statu.execute_statu = message.eError
            park_table.statu.statu_description = "设备故障，请联系管理员!" + "(调度)"
            return park_table
        # 获取车高信息
        dispatch_node_statu = message.dispatch_node_statu()
        try:
            tf.Parse(self._dispatch_statu[dispatch_key].statu, dispatch_node_statu)
        except Exception:
            park_table.statu.execute_statu = message.eError
            park_table.statu.statu_description = "设备故障，请联系管理员!" + "(调度状态消息错误)"
            return park_table
        # 判断搬运器状态
        if dispatch_node_statu.plc_carrier_status == 0:
            park_table.statu.execute_statu = message.eError
            park_table.statu.statu_description = "设备故障，请联系管理员!" + "(搬运器)"
            return park_table

        dispatch_plc_passway_status = dispatch_node_statu.dispatch_plc_passway_status_vector[park_table.import_id - 1]
        # 检查入口状态
        if dispatch_node_statu.plc_carrier_status == 4 or dispatch_plc_passway_status.plc_passway_enable == 2:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "该单元设备维护中!请前往其他入口！"
            return park_table

        if dispatch_plc_passway_status.car_height == 0:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "未检测到车辆!"
            return park_table
        elif dispatch_plc_passway_status.car_height == 4:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "车辆超高，请退出车库!"
            return park_table
        sensor_1 = dispatch_plc_passway_status.sensor_1


        # if (sensor_1 >> 2) & 0x01 != 1:
        #     park_table.statu.execute_statu = message.eWarning
        #     park_table.statu.statu_description = "车辆超限，请联系现场工作人员！"
        #     return park_table

        if (sensor_1 >> 3) & 0x01 != 1:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "车辆后超界，请往前！"
            return park_table

        if (sensor_1 >> 4) & 0x01 != 1:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "车辆前超界，请往后！"
            return park_table
        #
        # if (sensor_1 >> 5) & 0x01 != 1:
        #     park_table.statu.execute_statu = message.eWarning
        #     park_table.statu.statu_description = "车辆左超界，请往右！"
        #     return park_table
        #
        # if (sensor_1 >> 6) & 0x01 != 1:
        #     park_table.statu.execute_statu = message.eWarning
        #     park_table.statu.statu_description = "车辆右超界，请往左！"
        #     return park_table

        measure_buffer = message.measure_buffer()
        measure_info_to_terminal = message.measure_info()
        measure_info_to_plc_reverse = message.measure_info()
        measure_info_to_plc_forward = message.measure_info()

        measure_key = "measure_%d_statu_port" % park_table.terminal_id
        if (measure_key in self._measure_statu) is False or self._measure_statu[measure_key].timeout():
            park_table.statu.execute_statu = message.eError
            park_table.statu.statu_description = "设备故障，请联系管理员!" + "(雷达)"
            return park_table
        # 获取车高信息
        try:
            tf.Parse(self._measure_statu[measure_key].statu, measure_buffer)
            measure_info_to_terminal.CopyFrom(measure_buffer.measure_info_to_terminal)
            measure_info_to_plc_reverse.CopyFrom(measure_buffer.measure_info_to_plc_reverse)
            measure_info_to_plc_forward.CopyFrom(measure_buffer.measure_info_to_plc_forward)

        except Exception:
            park_table.statu.execute_statu = message.eError
            park_table.statu.statu_description = "设备故障，请联系管理员!" + "(雷达状态消息错误)"
            return park_table
        # 获取雷达信息
        tm = time.time()
        while time.time() - tm < 2:
            park_table.entrance_measure_info.CopyFrom(measure_buffer)
            # 没有超界。车为静止状态。
            # if measure_info.border_statu == MeasureStatu["ok"] and measure_info.ground_status == 0 and measure_info.motion_statu == 1:
            if measure_info_to_terminal.border_statu == Range_status["未超界"] and \
                    measure_info_to_terminal.ground_status == MeasureStatu["ok"] and \
                    measure_info_to_plc_reverse.border_statu == Range_status["未超界"] and \
                    measure_info_to_plc_reverse.ground_status == MeasureStatu["ok"] and \
                    measure_info_to_plc_forward.border_statu == Range_status["未超界"] and \
                    measure_info_to_plc_forward.ground_status == MeasureStatu["ok"]:
                park_table.statu.execute_statu = message.eNormal
                break
            else:
                park_table.statu.execute_statu = message.eError
                if self._measure_statu[measure_key].statu is not None and self._measure_statu[
                    measure_key].timeout() is False:
                    try:
                        measure_buffer = message.measure_buffer()
                        measure_info_to_terminal = message.measure_info()
                        tf.Parse(self._measure_statu[measure_key].statu, measure_buffer)
                        measure_info_to_terminal.CopyFrom(measure_buffer.measure_info_to_terminal)
                        measure_info_to_plc_reverse.CopyFrom(measure_buffer.measure_info_to_plc_reverse)
                        measure_info_to_plc_forward.CopyFrom(measure_buffer.measure_info_to_plc_forward)
                        # print("check measure info again:", measure_info)
                    except:
                        print("parse exception:\n" + self._measure_statu[measure_key].statu)
            time.sleep(0.1)

        if park_table.statu.execute_statu == message.eError:
            if measure_info_to_terminal.ground_status == MeasureStatu["ok"] or \
                    measure_info_to_plc_reverse.ground_status == MeasureStatu["ok"] or \
                    measure_info_to_plc_forward.ground_status == MeasureStatu["ok"]:
                park_table.statu.statu_description = "雷达状态异常！"
            elif measure_info_to_terminal.ground_status == MeasureStatu["终端超界"] or \
                    measure_info_to_plc_reverse.ground_status == MeasureStatu["PLC超界"] or \
                    measure_info_to_plc_forward.ground_status == MeasureStatu["PLC超界"]:
                park_table.statu.statu_description = "请按提示调整！"
            elif measure_info_to_terminal.ground_status == MeasureStatu["失去连接"] or \
                    measure_info_to_plc_reverse.ground_status == MeasureStatu["失去连接"] or \
                    measure_info_to_plc_forward.ground_status == MeasureStatu["失去连接"]:
                park_table.statu.statu_description = "设备故障，请联系管理员! (雷达)"
            else:
                park_table.statu.statu_description = "请检查库内是否有异物！"
                print(" MeasureInfo:\n " + tf.MessageToString(measure_info_to_terminal, as_utf8=True))

            return park_table
        # 填写车高信息
        height = dispatch_plc_passway_status.car_height

        # 赋值唯一码
        uid = str(uuid.uuid1())
        park_table.primary_key = uid
        # 查询黑名单
        print("--------------查询黑名单---------------" + str(datetime.datetime.now()))
        blacklist_res = self.db.query_blacklist_in_car_number(park_table.car_number)
        blacklist_count = len(blacklist_res)
        if blacklist_count > 0:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "车辆 :%s 已在黑名单，不允许存车!" % park_table.car_number
            return park_table

        # 查询车位表和指令表是否有该车
        print("--------------查询车位表---------------" + str(datetime.datetime.now()))
        space_res = self.db.query_space_in_car_number(park_table.car_number)
        space_count = len(space_res)
        if space_count > 0:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "车辆 :%s 已在库内!" % park_table.car_number
            return park_table
        print("--------------查询指令表---------------" + str(datetime.datetime.now()))
        command_res = self.db.query_command_in_car_number(park_table.car_number)
        command_count = len(command_res)
        if command_count > 0:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "指令正在执行中！请稍等！"
            return park_table

        # 车辆不在库内  查询是否有对应大小空车位
        print("--------------查询空车位---------------" + str(datetime.datetime.now()))
        space_empty_res = self.db.query_space_in_height_level_wheel_base_unit_and_empty(height,
                                                                                        measure_info_to_terminal.wheelbase,
                                                                                        park_table.unit_id)
        space_empty_count = len(space_empty_res)
        if space_empty_count <= 0:
            park_table.statu.execute_statu = message.eWarning
            park_table.statu.statu_description = "没有空余的合适车位,车牌号:%s 高度等级:%d 轴距:%.3fm!" % (
                park_table.car_number, height, measure_info_to_terminal.wheelbase)

        return park_table

    # 检查取车指令
    def exit_isOK(self, pick_body):
        pick_table = message.pick_table()
        try:
            tf.Parse(pick_body, pick_table)
        except Exception as e:
            pick_table.statu.execute_statu = message.eError
            pick_table.statu.statu_description = "设备故障，请联系管理员!" + "(取车表单错误)" + str(e.args)
            return pick_table

        if pick_table.primary_key is None or pick_table.primary_key == '':
            pick_table.statu.execute_statu = message.eWarning
            pick_table.statu.statu_description = " 唯一码不能为空！"
        else:
            # 查询车位表和指令表是否有该车
            print("**************查询车位表**************" + str(datetime.datetime.now()))
            space_res = self.db.query_space_in_primary_key(pick_table.primary_key)
            space_count = len(space_res)
            print("**************查询停车指令表**************" + str(datetime.datetime.now()))
            command_res_park = self.db.query_park_command_in_primary_key(pick_table.primary_key)
            command_count_park = len(command_res_park)
            if space_count <= 0 and command_count_park <= 0:
                pick_table.statu.execute_statu = message.eWarning
                pick_table.statu.statu_description = "车辆信息不存在!"
                return pick_table
            print("**************查询取车指令表**************" + str(datetime.datetime.now()))
            command_res = self.db.query_pick_command_in_primary_key(pick_table.primary_key)
            command_count = len(command_res)
            if command_count > 0:
                pick_table.unit_id = space_res[0]['unit']
                t_unit_str = self.get_unit_str(pick_table.unit_id)
                # 重复取车，提示成功，流程失败！
                pick_table.statu.execute_statu = message.eWarning
                pick_table.statu.statu_description = "取车成功！请前往 << %s >> 单元出口等待车辆，观看大屏幕提示取车！" % t_unit_str
                return pick_table
            unit_str = self.get_unit_str(pick_table.unit_id)
            pick_table.statu.execute_statu = message.eNormal
            pick_table.statu.statu_description = "取车成功，请前往 << %s >> 单元出口等待车辆，观看大屏幕提示取车！" % unit_str

            # 完善表单信息
            try:
                try:
                    pick_table.car_number = space_res[0]['car_number']
                    pick_table.unit_id = space_res[0]['unit']
                except Exception as e:
                    pick_table.car_number = command_res_park[0]['car_number']
                    pick_table.unit_id = command_res_park[0]['unit']
                    print("车位表未找到，使用指令表结果")
                pick_table.car_number_info.plate_color = space_res[0]['plate_color']
                pick_table.car_number_info.plate_type = space_res[0]['plate_type']
                pick_table.car_number_info.plate_confidence = space_res[0]['plate_confidence']
                pick_table.car_number_info.recognition_time = space_res[0]['recognition_time']
                pick_table.car_number_info.plate_full_image = ''
                pick_table.car_number_info.plate_clip_image = ''
            except Exception as e:
                print("数据库信息不全，缺失号牌颜色等信息！")
        return pick_table


    def get_unit_str(self, unit):
        if unit == 11:
            return 'A1'
        elif unit == 12:
            return 'A2'
        elif unit == 13:
            return 'A3'
        elif unit == 14:
            return 'A4'
        elif unit == 21:
            return 'B1'
        elif unit == 22:
            return 'B2'
        elif unit == 23:
            return 'B3'
        elif unit == 24:
            return 'B4'
        elif unit == 25:
            return 'B5'
        elif unit == 31:
            return 'C1'
        elif unit == 32:
            return 'C2'
        elif unit == 1:
            return 'A'
        elif unit == 2:
            return 'B'
        elif unit == 3:
            return 'C'
        return ''
