import ctypes
import inspect
import os
import signal

import sys

sys.path.append('..')

import datetime
import json
import threading
import time
import traceback
from functools import partial

import requests
from PyQt5.QtCore import QSize, QDateTime
from PyQt5.QtCore import pyqtSignal, QTimer, Qt
from PyQt5.QtGui import QFont, QIcon, QPixmap, QCursor, QColor
from PyQt5.QtWidgets import QMessageBox, QListWidgetItem, QMainWindow, QMenu, QPushButton, QGridLayout, QListWidget, \
    QLabel, QHeaderView, QTableWidgetItem, QAbstractItemView, QSizePolicy, QApplication

import google.protobuf.text_format as tf
import ui.spaceUi as sui
from window_controller.pickup_passwd_window import PickupWindow, ResultReturn
import message.message_pb2 as message
from window_controller.reparking_window import ReparkingWindow
from window_controller.full_car_window import FullcarWindow

from window_controller.led import Led
import copy
import async_communication as cmt
import mytool.db_helper.db_operation as spmng


class MainWindow(QMainWindow, sui.Ui_MainWindow):
    # # 取车界面信号
    # signal_dict = pyqtSignal(dict)

    def __init__(self, parking_config, mq_config, db_config, parent=None):
        super(MainWindow, self).__init__(parent)

        self.command_dict = {}
        self.unit_space_dict = None
        self.setupUi(self)
        self.parking_config = parking_config
        self.label.setText(self.parking_config['process_title'])
        # 数据存储
        # 全矩阵
        self.btn_positions = [(i, j) for i in range(self.parking_config['row']-1, -1, -1) for j in
                              range(self.parking_config['column'])]
        # # 奇数矩阵
        # self.btn_positions1 = [(i, j) for i in range(self.parking_config['row']-1, -1, -1) for j in
        #                       range(1,self.parking_config['column'],2)]
        # # 偶数矩阵
        # self.btn_positions2 = [(i, j) for i in range(self.parking_config['row']-1, -1, -1) for j in
        #                       range(2,self.parking_config['column']+2,2)]


        self._dispatch_statu = {}
        self.unit_space_is_init = False
        self.process_is_init = False

        self.parking_unit_list = self.parking_config['parking_unit_list']
        self.process_unit_list = self.parking_config['process_unit_list']
        self.db_unit_list = self.parking_config['db_unit_list']


        self.label_dict = {}
        self.list_widget_dict = {}

        self.setWindowTitle(self.parking_config['window_title'])
        # 锁
        self.data_lock = threading.Lock()

        # 配置导入初始化数据库和rabbitmq
        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.rabbitmq = cmt.RabbitAsyncCommunicator(mq_config['mq_ip'], mq_config['mq_port'], mq_config['mq_user'],
                                                    mq_config['mq_password'])
        try:
            self.rabbitmq.Init(None, mq_config['mq_statu_exchange_keys'])
            for ex, key in mq_config['mq_statu_exchange_keys']:
                self.rabbitmq.bind_statu_callback(ex, key, self.receive_dispatch_statu)
            self.rabbitmq.start()
        except Exception as e:
            print('rabbitmq启动失败！' + str(e.args))

        self.out_date = None
        self.in_date = None

        # 拓展功能
        self.action_queryBlacklist.triggered.connect(self.btn_query_blacklist)
        self.action_addBlacklist.triggered.connect(self.btn_add_blacklist)
        self.action_deleteBlacklist.triggered.connect(self.btn_delete_blacklist)

        self.action_queryWhitelist.triggered.connect(self.btn_query_whitelist)
        self.action_addWhitelist.triggered.connect(self.btn_add_whitelist)
        self.action_deleteWhitelist.triggered.connect(self.btn_delete_whitelist)

        # 记录表单元号，流程表单元号，车位表单元号
        self.unit_comboBox.addItems(list(self.parking_unit_list.keys()))
        self.process_comboBox.addItems(list(self.process_unit_list.keys()))
        self.db_comboBox.addItems(list(self.db_unit_list.keys()))

        self.db_unit = self.db_comboBox.currentText()
        self.process_unit = self.process_comboBox.currentText()
        self.parking_unit = self.unit_comboBox.currentText()
        self.updata_record_btn.clicked.connect(self.updata_record)

        # 调度状态指示灯
        self.plc_statu_led = Led()
        self.plc_statu_led.setEnabled(False)  # 设置为不使能状态，如果需要切换可以设置为True。则可以实现点击切换指示灯颜色的效果
        self.plc_statu_led.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.plc_statu_led.setChecked(False)  # 设置状态
        self.dispatch_heart_timer = cmt.TimeStatu(1, 0.1)
        self.horizontalLayout_11.addWidget(self.plc_statu_led)

        self.db_statu_led = Led()
        self.db_statu_led.setEnabled(False)  # 设置为不使能状态，如果需要切换可以设置为True。则可以实现点击切换指示灯颜色的效果
        self.db_statu_led.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.db_statu_led.setChecked(False)  # 设置状态
        self.horizontalLayout_11.addWidget(self.db_statu_led)

        # 是否输入过密码  密码保护默认五分钟
        self.t_time = time.time()
        self.is_pwd = False
        # 数据历史记录默认设置
        self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.tableWidget.itemClicked.connect(self.show_car_image)
        self.tableWidget.setHorizontalHeaderLabels(self.parking_config['record_title'])
        now = datetime.datetime.now()

        zero_today = now - datetime.timedelta(hours=now.hour, minutes=now.minute, seconds=now.second,
                                              microseconds=now.microsecond)
        last_today = zero_today + datetime.timedelta(hours=23, minutes=59, seconds=59)
        self.in_dateTimeEdit.setDateTime(zero_today)
        self.out_dateTimeEdit.setDateTime(last_today)
        self.in_dateTimeEdit_2.setDateTime(zero_today)
        self.out_dateTimeEdit_2.setDateTime(last_today)
        self.db_find_Button.clicked.connect(self.db_record_find)
        # 车位显示模式
        self.show_model = self.car_number_rbtn_2.isChecked()
        # 切换库位按钮关联函数
        self.find_btn.clicked.connect(self.find_btn_click)
        self.update_unit_btn.clicked.connect(self.update_btn_click)
        self.update_unit_btn_2.clicked.connect(self.update_process_unit_btn_click)


        # 初始化显示库位高度
        font = QFont()
        font.setFamily('宋体')
        font.setBold(False)
        font.setPointSize(15)
        self.parking_listWidget.setFont(font)

        # 数据缓存
        self.space_dict = {}
        self.record_all_unit_park_dict = {}
        self.record_all_unit_pick_dict = {}
        self.db_unit_park_dict = {}
        self.db_unit_pick_dict = {}
        self.record_total_unit_park_dict = {11: {}, 12: {}, 13: {}, 14: {}, 21: {}, 22: {}, 23: {}, 24: {}, 25: {},
                                            31: {}, 32: {}}
        self.record_total_unit_pick_dict = {11: {}, 12: {}, 13: {}, 14: {}, 21: {}, 22: {}, 23: {}, 24: {}, 25: {},
                                            31: {}, 32: {}}

        self.last_command_dict = {}

        # 数据库更新时间
        self.db_update_time = time.time() - 3
        self.db_connect_statu = False
        # 数据库查询线程
        self.db_query = threading.Thread(target=self.db_query)
        self.db_query_isClose = False
        self.db_query.start()

        # 启动界面刷新定时器
        self.timer = QTimer()
        self.timer.timeout.connect(self.Switch)
        self.timer.start(200)
        # # 临时
        # self.show_unit_box.setVisible(False)
        # self.groupBox_2.setVisible(False)
        # self.db_unit_label.setVisible(False)
        # self.db_comboBox.setVisible(False)

    def receive_dispatch_statu(self, statu, ex, key):
        # 调度状态接收
        self._dispatch_statu[key] = statu

    def db_query(self):
        while self.db_query_isClose is False:
            # 查询车位
            self.data_lock.acquire()
            self.space_dict = self.db.query_space_in_unit(self.parking_unit_list[self.parking_unit])

            # 查询指令表
            for unit in self.process_unit_list[self.process_unit]:
                self.last_command_dict[unit] = self.db.query_command_all_in_unit_and_sort(unit)

            self.data_lock.release()

            # 数据库更新时间
            self.db_update_time = time.time()

            time.sleep(0.1)

    # 界面刷新定时器
    def Switch(self):
        # 200毫秒刷新一次，同时检查密码定时器是否超过五分钟
        time_now = time.time()
        if self.is_pwd is True and time_now - self.t_time > 300:
            self.is_pwd = False
            self.t_time = time_now
        self.in_date = self.in_dateTimeEdit_2.dateTime().toPyDateTime().strftime("%Y-%m-%d %H:%M:%S")
        self.out_date = self.out_dateTimeEdit_2.dateTime().toPyDateTime().strftime("%Y-%m-%d %H:%M:%S")
        # 更新记录表单元号，流程表单元号，车位表单元号
        self.db_unit = self.db_comboBox.currentText()
        # 检查连接
        self.db_connect_statu = self.check_connect_statu()
        if self.db_connect_statu:
            self.data_lock.acquire()
            unit = self.parking_unit_list[self.parking_unit]
            # 车位管理
            self.parkspace_show(unit, self.parking_config["in_occupy_space"][str(unit)],
                                self.parking_config["out_occupy_space"][str(unit)],
                                self.parking_config["controlroom_occupy_space"][str(unit)])
            # # 流程监控
            self.process_monitoring(self.process_unit_list[self.process_unit])

            self.data_lock.release()

    def updata_record(self):
        # 当前选中时间段内所有单元记录表数据
        self.data_lock.acquire()

        self.record_all_unit_park_dict = self.db.query_park_count_in_time(self.in_date, self.out_date)
        self.record_all_unit_pick_dict = self.db.query_pick_count_out_time(self.in_date, self.out_date)

        # 当前选中时间内指定单元记录数据
        if len(self.db_unit) != 1 and self.db_unit_list[self.db_unit] is not None:
            self.db_unit_park_dict = self.db.query_park_count_in_time_and_unit(self.in_date, self.out_date,
                                                                                   self.db_unit_list[self.db_unit])
            self.db_unit_pick_dict = self.db.query_pick_count_out_time_and_unit(self.in_date, self.out_date,
                                                                                    self.db_unit_list[
                                                                                        self.db_unit])

        # 当前选中时间内指定总单元记录数据
        if len(self.db_unit) == 1:
            for unit in self.db_unit_list[self.db_unit]:
                self.record_total_unit_park_dict[unit] = self.db.query_park_count_in_time_and_unit(self.in_date,
                                                                                                   self.out_date,
                                                                                                   unit)
                self.record_total_unit_pick_dict[unit] = self.db.query_pick_count_out_time_and_unit(self.in_date,
                                                                                                    self.out_date,
                                                                                                    unit)
        # # 停车数量记录
        self.show_parkingData()
        self.data_lock.release()

    # 检查数据库连接
    def check_connect_statu(self):
        # 检查调度连接
        key = "dispatch_%d_statu_port" % self.parking_unit_list[self.parking_unit]
        if (key in self._dispatch_statu) is False or self._dispatch_statu[key].timeout():
            self.plc_statu_led.setChecked(False)
        else:
            statu = self._dispatch_statu[key].statu
            dispatch_node_statu = message.dispatch_node_statu()
            print(dispatch_node_statu)
            try:
                tf.Parse(statu, dispatch_node_statu)
            except Exception:
                pass
            if self.dispatch_heart_timer.statu != dispatch_node_statu.plc_heartbeat:
                self.dispatch_heart_timer = cmt.TimeStatu(dispatch_node_statu.plc_heartbeat)
                self.plc_statu_led.setChecked(True)
            if self.dispatch_heart_timer.timeout():
                self.plc_statu_led.setChecked(False)

        # 检查数据库连接
        if time.time() - self.db_update_time > 3:
            self.db_statu_led.setChecked(False)
        else:
            self.db_statu_led.setChecked(True)
        return self.db_statu_led.isChecked()

    # 车位显示
    def parkspace_show(self, unit, in_occupy_space, out_occupy_space, controlroom_occupy_space):
        self.unit_label.setText(self.get_unit(unit))
        self.pushButton_grade1.setIcon(QIcon(QPixmap("./images/grade1.png")))
        self.pushButton_grade2.setIcon(QIcon(QPixmap("./images/grade2.png")))
        self.pushButton_grade3.setIcon(QIcon(QPixmap("./images/grade3.png")))
        self.pushButton_grade1.setText("车高等级:" + str(self.parking_config['grade1']))
        self.pushButton_grade2.setText("车高等级:" + str(self.parking_config['grade2']))
        self.pushButton_grade3.setText("车高等级:" + str(self.parking_config['grade3']))

        # 绘制车位按钮
        if self.space_dict is None:
            return
        space_dict = copy.deepcopy(self.space_dict)
        is_show_car_number = self.car_number_rbtn_2.isChecked()

        if self.unit_space_dict != space_dict:
            print('有修改')
            if self.unit_space_is_init == False:
                self.unit_space_dict = copy.deepcopy(space_dict)
                self.unit_space_is_init = True

                is_drawIn = False
                is_drawOut = False
                is_drawControlRoom = False
                # 根据下标奇偶数分成两组
                even_space_list = space_dict[::2]
                odd_space_list = space_dict[1::2]


                for park, position in zip(space_dict, self.btn_positions):
                    btn = QPushButton()
                    font, text_str, stylesheet, tool_tip = self.get_btn_show(park)
                    btn.setFont(font)
                    btn.setLayout(QGridLayout())
                    btn.setText(text_str)
                    btn.setStyleSheet(stylesheet)
                    btn.setToolTip(tool_tip)
                    btn.setObjectName(str(park["table_id"]))
                    if text_str == "入   口" and is_drawIn is False:
                        self.unit_gridLayout.addWidget(btn, *position, 1, in_occupy_space)
                        is_drawIn = True
                    elif text_str == "出   口" and is_drawOut is False:
                        self.unit_gridLayout.addWidget(btn, *position, 1, out_occupy_space)
                        is_drawOut = True
                    elif text_str == " 控制室 " and is_drawControlRoom is False:
                        self.unit_gridLayout.addWidget(btn, *position, 1, controlroom_occupy_space)
                        is_drawControlRoom = True
                    elif text_str != "出   口" and text_str != "入   口" and text_str != " 控制室 ":
                        btn.setContextMenuPolicy(Qt.CustomContextMenu)
                        btn.customContextMenuRequested.connect(self.park_btn_right_click)
                        btn.clicked.connect(self.park_btn_left_click)
                        self.unit_gridLayout.addWidget(btn, *position)
            else:
                for park1, park2 in zip(self.unit_space_dict, space_dict):
                    if park1 != park2:
                        font, text_str, stylesheet, tool_tip = self.get_btn_show(park2)
                        results = self.findChild(QPushButton, str(park2["table_id"]))
                        if results is None:
                            return
                        results.setFont(font)
                        results.setText(text_str)
                        results.setStyleSheet(stylesheet)
                        results.setToolTip(tool_tip)
                self.unit_space_dict = copy.deepcopy(space_dict)
        if self.show_model != is_show_car_number:
            self.show_model = is_show_car_number
            for park in self.unit_space_dict:
                if park["statu"] == 2:
                    font, text_str, stylesheet, tool_tip = self.get_btn_show(park)
                    results = self.findChild(QPushButton, str(park["table_id"]))
                    results.setFont(font)
                    results.setText(text_str)
                    results.setStyleSheet(stylesheet)
                    results.setToolTip(tool_tip)

    # 流程监控
    def process_monitoring(self, process_unit_list):
        if self.process_is_init is False:
            for i in process_unit_list:
                self.list_widget_dict[i] = QListWidget(self)
                self.list_widget_dict[i].setContextMenuPolicy(Qt.CustomContextMenu)
                self.list_widget_dict[i].customContextMenuRequested.connect(self.custom_right_menu)
                self.list_widget_dict[i].setStyleSheet("border:5px solid #014F84;")
                self.list_widget_dict[i].setObjectName(('list_widget_%d' % (i + 1)))
                self.process_horizontalLayout.addWidget(self.list_widget_dict[i])

                self.label_dict[i] = QLabel(self)
                # 临时
                # self.label_dict[i].setText(unit_char + "-" + str((i % 10)))
                self.label_dict[i].setText(self.get_unit(i))

                # self.label_dict[i].setText("停取流程")

                self.label_dict[i].setAlignment(Qt.AlignCenter)
                self.label_dict[i].setFont(QFont("华文楷体", 60, QFont.Bold))
                self.command_dict[i] = []
                self.unit_horizontalLayout.addWidget(self.label_dict[i])
            self.process_is_init = True

        for i in process_unit_list:
            if (i in self.last_command_dict.keys()) is False or self.last_command_dict[i] is None:
                return
            else:
                last_command_dict = copy.deepcopy(self.last_command_dict[i])
                if self.command_dict[i] != last_command_dict:
                    self.command_dict[i] = copy.deepcopy(last_command_dict)
                    self.list_widget_dict[i].clear()
                    for dict in self.command_dict[i]:
                        if dict['statu'] != 3:
                            self.list_widget_dict[i].addItem(self.get_listWidget_item(dict))
                    for dict in self.command_dict[i]:
                        if dict['statu'] == 3:
                            self.list_widget_dict[i].addItem(self.get_listWidget_item(dict))

    # 刷新停车数据
    def show_parkingData(self):
        # 有一个数据是空就直接返回
        if self.record_all_unit_park_dict is None or self.record_all_unit_pick_dict is None or self.db_unit_park_dict is None or \
                self.db_unit_pick_dict is None or self.record_total_unit_park_dict is None or self.record_total_unit_pick_dict is None:
            return
        record_all_unit_park_dict, record_all_unit_pick_dict, db_unit_park_dict, db_unit_pick_dict, record_total_unit_park_dict, record_total_unit_pick_dict = \
            copy.deepcopy(self.record_all_unit_park_dict), copy.deepcopy(self.record_all_unit_pick_dict), copy.deepcopy(
                self.db_unit_park_dict), copy.deepcopy(self.db_unit_pick_dict), copy.deepcopy(
                self.record_total_unit_park_dict), copy.deepcopy(self.record_total_unit_pick_dict)
        unit_park_count = unit_pick_count = 0
        all_park_count, all_pick_count = len(record_all_unit_park_dict), len(record_all_unit_pick_dict)

        # 当前选中时间内指定总单元记录数据
        if len(self.db_unit) == 1:
            for unit in self.db_unit_list[self.db_unit]:
                unit_park_count = unit_park_count + len(record_total_unit_park_dict[unit])
                unit_pick_count = unit_pick_count + len(record_total_unit_pick_dict[unit])

        # 当前选中时间内指定单元记录数据
        elif len(self.db_unit) != 1 and self.db_unit_list[self.db_unit] is not None:
            unit_park_count, unit_pick_count = len(db_unit_park_dict), len(db_unit_pick_dict)
        else:
            unit_park_count, unit_pick_count = all_park_count, all_pick_count

        self.unit_park_count_label.setText("该单元停车{value}次".format(value=unit_park_count))
        self.unit_pick_count_label.setText("该单元取车{value}次".format(value=unit_pick_count))
        self.all_park_count_label.setText("所有库停车{value}次".format(value=all_park_count))
        self.all_pick_count_label.setText("所有库取车{value}次".format(value=all_pick_count))

    def show_parking_details(self, park_dict):
        self.parking_listWidget.clear()
        for poit in park_dict.items():
            item = QListWidgetItem()
            item.setSizeHint(QSize(50, 39))
            name = self.get_name(poit[0])
            if name == '未知':
                continue
            value = poit[1]
            if name == '楼层':
                value = value - self.parking_config['floor_minus']
            item.setText(name + "：" + str(value))
            item.setToolTip(str(value))
            self.parking_listWidget.addItem(item)
        res = self.db.query_space_in_car_number(park_dict['car_number'])
        self.plate_full_image_label.setPixmap(QPixmap(""))
        self.plate_clip_image_label.setPixmap(QPixmap(""))
        if len(res) > 0:
            try:
                rep = requests.get(res[0]['plate_full_image'])
                pix = QPixmap()
                pix.loadFromData(rep.content)
                pix = pix.scaled(self.plate_full_image_label.size(), Qt.KeepAspectRatio)
                self.plate_full_image_label.setPixmap(pix)
            except Exception as e:
                print('全景图：' + str(e.args))
            try:
                rep = requests.get(res[0]['plate_clip_image'])
                pix = QPixmap()
                pix.loadFromData(rep.content)
                pix = pix.scaled(self.plate_clip_image_label.size(), Qt.KeepAspectRatio)
                self.plate_clip_image_label.setPixmap(pix)
            except Exception as e:
                print('特写图：' + str(e.args))

    def find_btn_click(self):
        text = self.find_lineEdit.text()
        if text == '':
            QMessageBox.question(None, "提示", "请输入要查询的内容",
                                 QMessageBox.Ok)
            return
        if self.car_number_rbtn.isChecked():
            park_dict = self.db.query_space_in_car_number(text)
            if len(park_dict) > 0:
                self.show_parking_details(park_dict[0])
            else:
                QMessageBox.question(None, "查询结果", "车牌号:" + text + "  未查询到数据！",
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
        elif self.key_rbtn.isChecked():
            park_dict = self.db.query_space_in_primary_key(text)
            if len(park_dict) > 0:
                self.show_parking_details(park_dict[0])
            else:
                QMessageBox.question(None, "查询结果", "唯一码:" + text + "  未查询到数据！",
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
        # elif self.parking_rbtn.isChecked():
        #     park_dict = self.db.query_space_in_unit_and_table_id(self.unit, text)
        #     if len(park_dict) > 0:
        #         self.show_parking_details(park_dict[0])
        #
        #     else:
        #         QMessageBox.question(None, "查询结果", "车位id:" + text + "  未查询到数据！",
        #                              QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

        return

    def update_process_unit_btn_click(self):
        self.process_unit = self.process_comboBox.currentText()
        for i in range(self.process_horizontalLayout.count()):
            self.process_horizontalLayout.itemAt(i).widget().deleteLater()
        for i in range(self.unit_horizontalLayout.count()):
            self.unit_horizontalLayout.itemAt(i).widget().deleteLater()
        self.process_is_init = False

    def update_btn_click(self):
        parking_unit = self.unit_comboBox.currentText()
        if self.parking_unit_list[self.parking_unit] == self.parking_unit_list[parking_unit]:
            return
        self.parking_unit = parking_unit
        unit = self.parking_unit_list[self.parking_unit]
        for i in range(self.unit_gridLayout.count()):
            self.unit_gridLayout.itemAt(i).widget().deleteLater()
        self.data_lock.acquire()
        self.space_dict = self.db.query_space_in_unit(unit)
        self.data_lock.release()

        self.unit_space_is_init = False

    def park_btn_left_click(self):
        if self.db_connect_statu:
            sender = self.sender()
            tool_tip = sender.toolTip()
            dict = json.loads(tool_tip)
            self.show_parking_details(dict)
        else:
            QMessageBox.critical(None, "提示", "数据库连接断开！", QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def park_btn_right_click(self):
        if self.db_connect_statu:
            menu = QMenu(self)
            sender = self.sender()
            tool_tip = sender.toolTip()
            dict = json.loads(tool_tip)
            action = menu.addAction('启用车位')
            action.triggered.connect(partial(self.btn_opeSpace, dict, 0))
            action = menu.addAction('停用车位')
            action.triggered.connect(partial(self.btn_disableSpace, dict, 10))
            action = menu.addAction('清除车位')
            action.triggered.connect(partial(self.btn_clearSpace, dict))
            action = menu.addAction('正常取车')
            action.triggered.connect(partial(self.btn_pickUp, dict, message.PROCESS_NORMAL))
            action = menu.addAction('强制取车')
            action.triggered.connect(partial(self.btn_pickUp, dict, message.PROCESS_ONLY_TO_DISPATCH))
            action = menu.addAction('虚拟取车')
            action.triggered.connect(partial(self.btn_pickUp, dict, message.PROCESS_ONLY_TO_PAY))
            # action = menu.addAction('更换车位')
            # action.triggered.connect(partial(self.btn_replace_parking, dict))
            action = menu.addAction('填充车位')
            action.triggered.connect(partial(self.btn_fill_parking, dict))
            action = menu.addAction('增加备注')
            action.triggered.connect(partial(self.btn_add_remarks, dict))
            menu.exec_(QCursor.pos())
        else:
            QMessageBox.critical(None, "提示", "数据库连接断开！", QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_disableSpace(self, dict, statu):
        if self.is_input_pwd() is True:
            res = self.db.update_space_status_in_space_id(dict["id"], statu)
            if res == 0:
                QMessageBox.question(None, '提示', '更新车位失败！请检查是否点击错误！',
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_opeSpace(self, dict, statu):
        if self.is_input_pwd() is True:
            res = self.db.update_space_status_in_space_id(dict["id"], statu)
            if res == 0:
                QMessageBox.question(None, '提示', '更新车位失败！请检查是否点击错误！',
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_clearSpace(self, dict):
        if self.is_input_pwd() is True:
            res = self.db.clear_space_data(dict["id"])
            if res == 0:
                QMessageBox.question(None, '提示', '更新车位失败！请检查是否点击错误！',
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_pickUp(self, dict, table_process_mod):
        if self.is_input_pwd() is True:
            table = message.pick_table()
            # table.statu = message.table_statu()
            table.statu.table_process_mod = table_process_mod
            a = dict['primary_key']
            table.primary_key = dict["primary_key"]
            self.rabbitmq.publish("command_ex", "user_pick_command_request_port",
                                  tf.MessageToString(table, as_utf8=True))
            QMessageBox.question(None, '提示', '取车消息发送成功！',
                                 QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    # def btn_replace_parking(self, dict):
    #     if self.is_input_pwd() is True:
    #         if dict['car_number'] == 'None' or dict['primary_key'] == 'None':
    #             QMessageBox.question(None, '提示', '没有车牌号或唯一码，不符合更换车位条件！',
    #                                  QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
    #             return
    #         repwind = ReparkingWindow()
    #         repwind.exec()
    #         res = repwind.get_results()
    #         if res is True:
    #             target_parking = self.db.query_parking_in_unit_tableid(dict['unit'], repwind.get_park_tableid())[0]
    #             if target_parking['car_number'] is not None:
    #                 QMessageBox.question(None, '提示', '目标车位不为空！',
    #                                      QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
    #                 return
    #             parking = self.db.query_space_in_car_number(dict['car_number'])[0]
    #
    #             space_info_sql = "NULL"
    #             measure_info_sql = "NULL"
    #             plate_color_sql = "NULL"
    #             plate_type_sql = "NULL"
    #             plate_confidence_sql = "NULL"
    #             recognition_time_sql = "NULL"
    #             plate_full_image_sql = "NULL"
    #             plate_clip_image_sql = "NULL"
    #
    #             if parking['space_info'] is not None:
    #                 space_info_sql = "'%s'" % parking['space_info']
    #
    #             if parking['measure_info'] is not None:
    #                 measure_info_sql = "'%s'" % parking['measure_info']
    #
    #             if parking['plate_color'] is not None:
    #                 plate_color_sql = "'%s'" % parking['plate_color']
    #
    #             if parking['plate_type'] is not None:
    #                 plate_type_sql = "'%s'" % parking['plate_type']
    #
    #             if parking['plate_confidence'] is not None:
    #                 plate_confidence_sql = "%d" % parking['plate_confidence']
    #
    #             if parking['recognition_time'] is not None:
    #                 recognition_time_sql = "'%s'" % parking['recognition_time']
    #
    #             if parking['plate_full_image'] is not None:
    #                 plate_full_image_sql = "'%s'" % parking['plate_full_image']
    #
    #             if parking['plate_clip_image'] is not None:
    #                 plate_clip_image_sql = "'%s'" % parking['plate_clip_image']
    #
    #             sql2 = "update space set car_number='%s', primary_key='%s', statu=%d , space_info=%s , measure_info=%s ,\
    #                     plate_color=%s , plate_type=%s , plate_confidence=%s , recognition_time=%s , plate_full_image=%s , plate_clip_image=%s where id=%d" \
    #                    % (parking['car_number'], parking['primary_key'], parking['statu'], space_info_sql,
    #                       measure_info_sql,
    #                       plate_color_sql, \
    #                       plate_type_sql, plate_confidence_sql, recognition_time_sql, plate_full_image_sql,
    #                       plate_clip_image_sql, target_parking['id'])
    #             # print(sql2)
    #
    #             res = self.db.update(sql2)
    #             if res == 0:
    #                 QMessageBox.question(None, '提示', '执行失败！',
    #                                      QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
    #                 return
    #             res = self.db.clear_space_data(parking['id'])
    #             if res > 0:
    #                 QMessageBox.question(None, '提示', '车位交换成功！',
    #                                      QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_fill_parking(self, dict):
        if self.is_input_pwd() is True:
            fullcar = FullcarWindow()
            fullcar.exec()
            if fullcar.get_results() is True:
                car_number = fullcar.get_text()
                res = self.db.update_space_status_car_number_in_space_id(dict['id'], car_number, 2)
                if res > 0:
                    QMessageBox.question(None, '提示', '车位填充成功！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_query_blacklist(self):
        if self.is_input_pwd() is True:
            res = self.db.query_blacklist()
            if res is not None and len(res) > 0:
                blacklist = ""
                for dict in res:
                    blacklist = blacklist + str(dict) + "\n\n"
                QMessageBox.question(None, '提示', blacklist,
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
            else:
                QMessageBox.question(None, '提示', '没有黑名单！',
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_add_blacklist(self):
        if self.is_input_pwd() is True:
            fullcar = FullcarWindow()
            fullcar.exec()
            if fullcar.get_results() is True:
                car_number = fullcar.get_text()
                res = self.db.add_blacklist_in_car_number(car_number, datetime.datetime.now(), None, None)
                if res is not None and res > 0:
                    QMessageBox.question(None, '提示', '黑名单添加成功！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
                else:
                    QMessageBox.question(None, '提示', '黑名单添加失败！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_delete_blacklist(self):
        if self.is_input_pwd() is True:
            fullcar = FullcarWindow()
            fullcar.exec()
            if fullcar.get_results() is True:
                car_number = fullcar.get_text()
                res = self.db.delete_blacklist_in_car_number(car_number)
                if res is not None and res > 0:
                    QMessageBox.question(None, '提示', '黑名单删除成功！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
                else:
                    QMessageBox.question(None, '提示', '黑名单删除失败！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_query_whitelist(self):
        if self.is_input_pwd() is True:
            res = self.db.query_whitelist()
            if res is not None and len(res) > 0:
                whitelist = ""
                for dict in res:
                    whitelist = whitelist + str(dict) + "\n\n"
                QMessageBox.question(None, '提示', whitelist,
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
            else:
                QMessageBox.question(None, '提示', '没有白名单！',
                                     QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_add_whitelist(self):
        if self.is_input_pwd() is True:
            fullcar = FullcarWindow()
            fullcar.exec()
            if fullcar.get_results() is True:
                car_number = fullcar.get_text()
                res = self.db.add_whitelist_in_car_number(car_number, datetime.datetime.now(), None, None)
                if res is not None and res > 0:
                    QMessageBox.question(None, '提示', '白名单添加成功！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
                else:
                    QMessageBox.question(None, '提示', '黑名单删除失败！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_delete_whitelist(self):
        if self.is_input_pwd() is True:
            fullcar = FullcarWindow()
            fullcar.exec()
            if fullcar.get_results() is True:
                car_number = fullcar.get_text()
                res = self.db.delete_whitelist_in_car_number(car_number)
                if res is not None and res > 0:
                    QMessageBox.question(None, '提示', '白名单删除成功！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
                else:
                    QMessageBox.question(None, '提示', '黑名单删除失败！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def btn_add_remarks(self, dict):
        if self.is_input_pwd() is True:
            fullcar = FullcarWindow()
            fullcar.exec()
            if fullcar.get_results() is True:
                remark = fullcar.get_text()
                res = self.db.update_space_remark_in_space_id(dict['id'], remark)
                if res > 0:
                    QMessageBox.question(None, '提示', '车位添加备注成功！',
                                         QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容

    def get_btn_show(self, park):

        font = QFont()
        font.setFamily('宋体')
        font.setPointSize(21)
        if park["statu"] == 6:
            text_str = "入   口"
            font.setBold(True)
        elif park["statu"] == 7:
            text_str = "出   口"
            font.setBold(True)
        elif park["statu"] == 8:
            text_str = " 控制室 "
            font.setBold(True)
        # elif park["statu"] == 10 and park["remark"] is not None:
        # text_str = park["remark"][0:4]
        # font.setPointSize(20)
        elif (park["statu"] == 2 or park["statu"] == 1 or park["statu"] == 4) and park[
            "car_number"] is not None and self.car_number_rbtn_2.isChecked():
            text_str = park["car_number"]
            font.setPointSize(20)

        else:
            text_str = "车位:%d\n楼层:%d" % (park["table_id"], (park["floor"] - self.parking_config['floor_minus']))
            font.setPointSize(10)

        background_color = ""
        background_image = ""



        # 设置背景图
        if park["height_level"] == self.parking_config['grade1']:
            background_image = "background-image: url(./images/grade1.png);"
        elif park["height_level"] == self.parking_config['grade2']:
            background_image = "background-image: url(./images/grade2.png);"
        elif park["height_level"] == self.parking_config['grade3']:
            background_image = "background-image: url(./images/grade3.png);"
        elif park["height_level"] == self.parking_config['grade4']:
            background_image = "background-image: url(./images/grade1.png);"

        # 故障
        if park["statu"] == 10:
            background_color = "background-color:rgb(255,130,130);"
        # 空闲
        elif park["statu"] == 0:
            background_color = "background-color:rgb(195,195,195);"
        # 存车中
        elif park["statu"] == 1:
            background_color = "background-color:rgb(140,100,220);"
        # 占用
        elif park["statu"] == 2:
            background_color = "background-color:rgb(248,239,71);"
        # 取车中
        elif park["statu"] == 4:
            background_color = "background-color:rgb(102,255,255);"
        # 出入口
        elif park["statu"] == 6 or park["statu"] == 7 or park["statu"] == 8:
            background_color = "background-color:rgb(0,162,232);"
            background_image = ""
        # elif park["statu"] == 0 and park["remark"] is not None:
        #     background_color = "background-color:rgb(255,130,130);"
        stylesheet = background_color + "pressed{padding-top:2px;padding-left:2px;};" + background_image + "background-repeat:no-repeat;"
        for key in park.keys():
            if park[key] is None:
                park[key] = ''
        tool_tip = json.dumps(park)
        return font, text_str, stylesheet, tool_tip

    # 显示车辆图片
    def show_car_image(self, Item):
        try:
            row = Item.row()  # 获取行数
            col = self.tableWidget.columnCount()  # 获取列数 注意是column而不是col哦
            plate_full_image = self.tableWidget.item(row, col - 2)
            plate_clip_image = self.tableWidget.item(row, col - 1)
            self.plate_full_image_label_2.setPixmap(QPixmap(""))
            self.plate_clip_image_label_2.setPixmap(QPixmap(""))
            if plate_full_image is not None:
                rep = requests.get(plate_full_image.text())
                pix = QPixmap()
                pix.loadFromData(rep.content)
                pix = pix.scaled(self.plate_full_image_label_2.size(), Qt.KeepAspectRatio)
                self.plate_full_image_label_2.setPixmap(pix)
            if plate_clip_image is not None:
                rep = requests.get(plate_clip_image.text())
                pix = QPixmap()
                pix.loadFromData(rep.content)
                pix = pix.scaled(self.plate_clip_image_label_2.size(), Qt.KeepAspectRatio)
                self.plate_clip_image_label_2.setPixmap(pix)
        except Exception as e:
            traceback.print_exc()

    # 查询历史记录
    def db_record_find(self):
        if self.db_connect_statu is False:
            QMessageBox.critical(None, "提示", "数据库连接断开！", QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
            return
        if self.db_unit_list[self.db_unit] == 0:
            unit_sql = ""
        elif type(self.db_unit_list[self.db_unit]) != int:
            unit_sql = "and ("
            for i in self.db_unit_list[self.db_unit]:
                unit_sql = unit_sql + "unit_id=%d or " % i
            unit_sql = unit_sql[:-3] + ")"
        else:
            unit_sql = "and (unit_id = %s)" % self.db_unit_list[self.db_unit]

        in_datatime = self.in_dateTimeEdit.dateTime().toPyDateTime()
        out_datatime = self.out_dateTimeEdit.dateTime().toPyDateTime()
        car_number = self.car_number_lineEdit.text()
        in_time_sql = "(in_time_start >= '%s' and in_time_start <= '%s') " % (in_datatime, out_datatime)
        out_time_sql = "(out_time_start >= '%s' and out_time_start <= '%s') " % (in_datatime, out_datatime)
        in_and_out_time_sql = "(" + in_time_sql + " or " + out_time_sql + ")"
        if self.park_radioButton.isChecked():
            time_sql = in_time_sql
        elif self.pick_radioButton.isChecked():
            time_sql = out_time_sql
        else:
            time_sql = in_and_out_time_sql

        car_number_sql = ""
        if car_number != "":
            car_number_sql = "and car_number like '%{}%'".format(car_number)

        sql = "select * from record where %s  %s  %s " % (time_sql, unit_sql, car_number_sql)
        print(sql)
        results = self.db.query(sql)
        self.tableWidget.clearContents()
        self.tableWidget.setRowCount(0)
        for i in range(len(results)):
            row_count = self.tableWidget.rowCount()  # 返回当前行数(尾部)
            self.tableWidget.insertRow(row_count)  # 尾部插入一行
            for j, value in zip(range(0, len(results[i])), results[i].values()):
                self.tableWidget.setItem(i, j, QTableWidgetItem(str(value)))

        # print(results)

    def custom_right_menu(self, pos):
        sender = self.sender()
        menu = QMenu()
        opt1 = menu.addAction("恢复排队")
        opt2 = menu.addAction("设为故障")
        opt3 = menu.addAction("删除任务")

        try:
            hitIndex = sender.indexAt(pos).row()
            # print(hitIndex)
            if hitIndex > -1:
                # 获取item内容
                car_number = sender.item(hitIndex).toolTip()
                action = menu.exec_(sender.mapToGlobal(pos))
                if action is None:
                    return
                if self.is_input_pwd() is True:
                    self.is_pwd = False
                    if self.is_input_pwd('该操作存在风险，请再次输入密码！') is True:
                        if action == opt1:
                            res = self.db.update_command_status_in_car_number(car_number, 0)
                        if action == opt2:
                            res = self.db.update_command_status_in_car_number(car_number, 3)
                        if action == opt3:
                            res = self.db.delete_command(car_number)
                        if res > 0:
                            QMessageBox.question(None, '提示', '指令修改成功！',
                                                 QMessageBox.Ok)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
        except Exception as e:
            pass

    def is_input_pwd(self, tipstr=None):
        if self.is_pwd is False:
            # 组装显示信息
            # 实例取车窗口,并以模态窗口形式显示
            pickup_window = PickupWindow(tipstr)
            pickup_window.exec_()

            res = pickup_window.getResult()
            if res is ResultReturn.OK:
                self.is_pwd = True
                self.t_time = time.time()
                return True
            else:
                return False
        return True

    def get_listWidget_item(self, dict):
        item = QListWidgetItem()
        item.setFont(QFont('微软雅黑', 14, QFont.Bold))
        item.setToolTip(dict['car_number'])
        parkspace = message.parkspace_info()
        try:
            tf.Parse(dict['space_info'], parkspace)
        except Exception:
            parkspace.table_id = -1

        show_str = ""
        if dict['type'] == 1:  # 存车指令
            item.setBackground(QColor(185, 240, 240))
            if (dict['statu'] == 0):  # 排队
                item.setForeground(QColor(80, 80, 80))
                show_str = dict['car_number'] + " 排队中"
            elif (dict['statu'] == 1):  # 工作
                item.setForeground(QColor('blue'))
                show_str = dict['car_number'] + " 存车中"
            elif (dict['statu'] == 2):  # 已完成
                item.setForeground(QColor('green'))
                show_str = dict['car_number'] + " 已完成"
            elif (dict['statu'] == 3):  # 已完成
                item.setForeground(QColor('red'))
                show_str = dict['car_number'] + " 故障！"
            show_str = "存 %d入 %d出 %d号车位 %s %s " % (
            dict["import_id"], dict["export_id"], parkspace.table_id, show_str, str(dict["queue_time"].time()))

        elif dict['type'] == 2:  # 取车指令
            item.setBackground(QColor(250, 240, 200))
            if (dict['statu'] == 0):  # 排队
                item.setForeground(QColor(80, 80, 80))
                show_str = dict['car_number'] + " 排队中"
            elif (dict['statu'] == 1):  # 工作
                item.setForeground(QColor('blue'))
                show_str = dict['car_number'] + " 取车中"
            elif (dict['statu'] == 2):  # 已完成
                item.setForeground(QColor('green'))
                show_str = dict['car_number'] + " 已完成"
            elif (dict['statu'] == 3):  # 已完成
                item.setForeground(QColor('red'))
                show_str = dict['car_number'] + " 故障！"
            show_str = "取 %d入 %d出 %d号车位 %s %s " % (
            dict["import_id"], dict["export_id"], parkspace.table_id, show_str, str(dict["queue_time"].time()))
        item.setText(show_str)
        return item

    def closeEvent(self, event):
        results = QMessageBox.question(self, '退出', '你确定要退出吗?', QMessageBox.Yes | QMessageBox.No,
                                       QMessageBox.No)  # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
        if results == QMessageBox.Yes:
            self.db_query_isClose = True
            self.db_query.join()
            self.rabbitmq.close()
            event.accept()  # 接受关闭事件
            # 强制结束进程
            pid = os.getpid()
            os.kill(pid, signal.SIGTERM)
        else:
            event.ignore()  # 忽略关闭事件

    def get_name(self, key):
        if key == 'id':
            return '总车位号'
        elif key == 'table_id':
            return '表编号'
        elif key == 'floor':
            return '楼层'
        elif key == 'height_level':
            return '限高等级'
        elif key == 'height':
            return '限高'
        elif key == 'wheel_base_level':
            return '限制轴距等级'
        elif key == 'wheel_base':
            return '限制轴距'
        elif key == 'car_number':
            return '车牌号'
        elif key == 'statu':
            return '车位状态'
        elif key == 'plate_color':
            return '号牌颜色'
        elif key == 'plate_type':
            return '号牌类型'
        elif key == 'plate_confidence':
            return '号牌可信度'
        elif key == 'recognition_time':
            return '识别时间'
        elif key == 'primary_key':
            return '唯一码'
        elif key == 'plate_full_image':
            return '号牌全景图'
        elif key == 'plate_clip_image':
            return '号牌特写图'
        elif key == 'remark':
            return '备注'
        else:
            return '未知'

    def get_unit(self, unit):
        if unit == 1:
            return 'A'
        elif unit == 2:
            return 'B'
        elif unit == 11:
            return 'A'
        elif unit == 12:
            return 'A2'
        elif unit == 13:
            return 'A3'
        elif unit == 14:
            return 'A4'
        elif unit == 21:
            return 'B'
        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'
        return '未知'
