import base64
import csv
import hashlib
import os
import pathlib
import tempfile
import time
from typing import Optional, Union

import gridfs
import pydicom
import pymongo
import requests
from PySide2.QtCore import QByteArray
from PySide2.QtGui import *
from PySide2.QtWidgets import *

import vmi

client = pymongo.MongoClient('mongodb://skyward:Yw309309@med-3d.top:27018/skyward', 27017)
database = client.skyward
case_db = database.get_collection('case')
order_db = database.get_collection('order')
user_db = database.get_collection('user')
role_customer_db = database.get_collection('role_customer')
role_sales_worker_db = database.get_collection('role_sales_worker')
role_product_designer_db = database.get_collection('role_product_designer')
role_quality_inspector_db = database.get_collection('role_quality_inspector')
role_machine_operator_db = database.get_collection('role_machine_operator')
role_admin_db = database.get_collection('role_admin')
dicom_fs = gridfs.GridFS(database, collection='dicom')
vti_fs = gridfs.GridFS(database, collection='vti')
vtp_fs = gridfs.GridFS(database, collection='vtp')
stl_fs = gridfs.GridFS(database, collection='stl')


def ask_user() -> Optional[dict]:
    ok, find_user = True, {}
    while ok:
        text, ok = QInputDialog.getText(None, '请输入', '手机号：', QLineEdit.Normal)
        if not ok:
            return None

        find_user = user_db.find_one({'telephone': text})
        if not find_user:
            vmi.askInfo('手机号未注册')
            ok = True
            continue

        ok = False

    ok = True
    while ok:
        text, ok = QInputDialog.getText(None, '请输入', '密码：', QLineEdit.Password)
        if not ok:
            return None

        if find_user['password'] != hashlib.md5(text.encode()).hexdigest():
            vmi.askInfo('密码错误')
            ok = True
            continue

        ok = False
    return find_user


def ask_customer_id() -> Optional[dict]:
    sizep = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

    dialog = QDialog()
    dialog.setSizePolicy(sizep)
    dialog.setWindowTitle('选择顾客')
    dialog.setLayout(QVBoxLayout())
    dialog.setMinimumWidth(200)

    customer_combo = QComboBox()
    dialog.layout().addWidget(customer_combo)

    for i in role_customer_db.find():
        customer_combo.addItem('{} {} {}'.format(i['_id'], i['name'], i['organization']), i['_id'])

    ok_cancel = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dialog)
    ok_cancel.setSizePolicy(sizep)
    ok_cancel.accepted.connect(dialog.accept)
    ok_cancel.rejected.connect(dialog.reject)
    dialog.layout().addWidget(ok_cancel)

    if dialog.exec_() == QDialog.Accepted:
        return customer_combo.currentData()
    else:
        return None


def ask_sales_worker_id() -> Optional[dict]:
    sizep = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

    dialog = QDialog()
    dialog.setSizePolicy(sizep)
    dialog.setWindowTitle('选择销售')
    dialog.setLayout(QVBoxLayout())
    dialog.setMinimumWidth(200)

    sales_worker_combo = QComboBox()
    dialog.layout().addWidget(sales_worker_combo)

    for i in role_sales_worker_db.find():
        sales_worker_combo.addItem('{} {} {}'.format(i['_id'], i['name'], i['organization']), i['_id'])

    ok_cancel = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dialog)
    ok_cancel.setSizePolicy(sizep)
    ok_cancel.accepted.connect(dialog.accept)
    ok_cancel.rejected.connect(dialog.reject)
    dialog.layout().addWidget(ok_cancel)

    if dialog.exec_() == QDialog.Accepted:
        return sales_worker_combo.currentData()
    else:
        return None


def dicom_kw_value(f: str) -> dict:
    kw_value = {}
    with pydicom.dcmread(f) as ds:
        for e in ds.iterall():
            if e.value.__class__ in [None, bool, int, float, str]:
                kw_value[e.keyword] = e.value
            elif e.value.__class__ in [bytes]:
                kw_value[e.keyword] = '{} bytes'.format(len(e.value))
            else:
                kw_value[e.keyword] = str(e.value)
    return {kw: kw_value[kw] for kw in sorted(kw_value)}


def case(product_name: str, product_model: str, product_specification: str,
         order_uid: str, order_files: list,
         patient_name: str, patient_sex: str, patient_age: str,
         dicom_files: dict, vti_files: dict, vtp_files: dict, stl_files: dict,
         snapshot_list: list, **kwargs) -> Optional[dict]:
    """
    构造本地案例
    :param product_model: 产品型号
    :param order_uid: 产品序列号
    :param order_files: 产品文件列表
    :param patient_name: 患者姓名
    :param patient_sex: 患者性别
    :param patient_age: 患者年龄
    :param dicom_files: 原始DICOM文件，每个关键词索引一个文件列表
    :param vti_files: vtkXMLImageData格式文件，每个关键词索引一个文件
    :param vtp_files: vtkXMLPolyData格式文件，每个关键词索引一个文件
    :param stl_files: STL格式文件，每个关键词索引一个文件
    :param kwargs: 其它相关信息，每个关键词索引一个支持数据库直接录入的对象
    :return: 案例信息
    """
    case_data = {}

    # 上传原始DICOM文件
    for kw in dicom_files:
        sop_uids = []
        for f in dicom_files[kw]:
            sop_uid = pydicom.dcmread(f).SOPInstanceUID
            sop_uids.append(sop_uid)

            if not dicom_fs.exists({'SOPInstanceUID': sop_uid}):
                dicom_fs.put(open(f, 'rb').read(), **dicom_kw_value(f))
        case_data[kw] = sop_uids

    # 上传其它格式文件
    files = [vti_files, vtp_files, stl_files]
    fs = [vti_fs, vtp_fs, stl_fs]
    for i in range(len(files)):
        for kw in files[i]:
            f_bytes = open(files[i][kw], 'rb').read()
            md5 = hashlib.md5(f_bytes).hexdigest()

            if fs[i].exists({'md5': md5}):
                case_data[kw] = fs[i].find_one({'md5': md5})._id
            else:
                case_data[kw] = fs[i].put(f_bytes)

    # 上传其它信息
    case_data['product_name'] = product_name
    case_data['product_model'] = product_model
    case_data['product_specification'] = product_specification
    case_data['order_uid'] = order_uid
    case_data['order_files'] = order_files
    case_data['patient_name'] = patient_name
    case_data['patient_sex'] = patient_sex
    case_data['patient_age'] = patient_age
    case_data['snapshot'] = snapshot_list

    for kw in kwargs:
        case_data[kw] = kwargs[kw]
    return case_data


def case_sync(case: dict, ukw: list) -> Union[dict, bool]:
    """
    同步案例
    :param case: 本地案例信息
    :param ukw: 特征键列表，用于判断相同案例
    :return: 同步后的案例信息
    """
    ukw_value = {kw: case[kw] for kw in ukw}

    # 清理相同无效案例
    for c in case_db.find(ukw_value):
        if 'case_uid' not in c:
            case_db.delete_one({'_id': c['_id']})

    # 查找相同有效案例
    find = case_db.find_one(ukw_value)

    if find and 'case_uid' in find:
        if find['order_released']:
            vmi.askInfo('生产单已发布')
            r = vmi.askButtons(['下载案例'])
        elif find['customer_confirmed']:
            vmi.askInfo('顾客已确认')
            r = vmi.askButtons(['上传案例', '下载案例', '发布生产单'])
        else:
            r = vmi.askButtons(['上传案例', '下载案例'])
    else:
        r = vmi.askButtons(['创建案例'])

    if r == '创建案例':
        user = ask_user()
        if not user:
            return False

        role_product_designer_id = user['role_product_designer_id']
        print(role_product_designer_id)
        if not role_product_designer_db.find_one({'_id': role_product_designer_id}):
            vmi.askInfo('错误：只有产品设计师可以创建案例')
            return False

        customer_uid = ask_customer_id()
        if not customer_uid:
            return False

        sales_worker_uid = ask_sales_worker_id()
        if not sales_worker_uid:
            return False

        case['role_product_designer_id'] = role_product_designer_id
        case['role_customer_id'] = customer_uid
        case['role_sales_worker_id'] = sales_worker_uid
        case['role_quality_inspector_id'] = None
        case['customer_confirmed'] = False
        case['order_released'] = False
        case['order_inspected'] = False
        case['order_completed'] = False

        _id = case_db.insert_one({kw: case[kw] for kw in sorted(case)}).inserted_id
        try:
            case_uid = vmi.convert_base(round(time.time() * 100))
            response = requests.post(url='http://med-3d.top:2334/sys/caseCreate',
                                     headers={'_id': str(_id), 'case_uid': case_uid})
            if response.text == 'true':
                find = case_db.find_one({'_id': _id})
                if 'case_uid' in find:
                    return True
                else:
                    case_db.delete_one({'_id': _id})
                    vmi.askInfo('错误：云端未分配编号')
            else:
                case_db.delete_one({'_id': _id})
                vmi.askInfo('错误：' + response.text)
        except Exception as e:
            case_db.delete_one({'_id': _id})
            vmi.askInfo('错误：' + str(e))
    elif r == '上传案例':
        user = ask_user()
        if not user:
            return False

        role_product_designer_id = user['role_product_designer_id']
        if not role_product_designer_db.find_one({'_id': role_product_designer_id}):
            vmi.askInfo('错误：只有产品设计师可以上传案例')
            return False

        case['role_product_designer_id'] = role_product_designer_id
        case['customer_confirmed'] = False
        case['order_released'] = False
        case['order_inspected'] = False
        case['order_completed'] = False

        try:
            case_uid = vmi.convert_base(round(time.time() * 100))
            response = requests.post(url='http://med-3d.top:2334/sys/caseUpdate',
                                     headers={'_id': str(find['_id']), 'case_uid': case_uid})
            if response.text == 'true':
                case_db.find_one_and_update({'_id': find['_id']}, {'$set': case})
                return True
            else:
                vmi.askInfo('错误：' + response.text)
        except Exception as e:
            vmi.askInfo('错误：' + str(e))
    elif r == '下载案例':
        return case_db.find_one({'_id': find['_id']})
    elif r == '发布生产单':
        user = ask_user()
        if not user:
            return False

        role_product_designer_id = user['role_product_designer_id']
        if not role_product_designer_db.find_one({'_id': role_product_designer_id}):
            vmi.askInfo('错误：只有产品设计师可以发布生产单')
            return False

        case_set = {'role_product_designer_id': role_product_designer_id, 'order_released': True}

        try:
            case_uid = vmi.convert_base(round(time.time() * 100))
            response = requests.post(url='http://med-3d.top:2334/sys/caseUpdate',
                                     headers={'_id': str(find['_id']), 'case_uid': case_uid})
            if response.text == 'true':
                case_db.find_one_and_update({'_id': find['_id']}, {'$set': case_set})
                return True
            else:
                vmi.askInfo('错误：' + response.text)
        except Exception as e:
            vmi.askInfo('错误：' + str(e))


def order_inspect_docx(order_uid: str, file: str):
    case = case_db.find_one({'order_uid': order_uid})

    with tempfile.TemporaryDirectory() as p:
        doc = vmi.docx_document('生产单')
        vmi.docx_section_landscape_A4(doc.sections[0])
        vmi.docx_section_margin_middle(doc.sections[0])
        # vmi.docx_section_header(doc.sections[0])

        s_title = vmi.docx_style(doc, '影为标题', 'Normal', size=26, alignment='CENTER')
        s_header = vmi.docx_style(doc, '影为页眉', 'Header', size=10)
        s_body_left = vmi.docx_style(doc, '影为正文', 'Body Text')
        s_body_left_indent = vmi.docx_style(doc, '影为正文首行缩进', 'Body Text', first_line_indent=2)
        s_body_center = vmi.docx_style(doc, '影为正文居中', 'Body Text', alignment='CENTER')
        s_table = vmi.docx_style(doc, '影为表格', 'Table Grid', alignment='CENTER')

        def add_row_text(table, texts, styles, merge=None):
            r = len(table.add_row().table.rows) - 1
            if merge is not None:
                table.cell(r, merge[0]).merge(table.cell(r, merge[1]))
            for c in range(min(len(table.columns), len(texts))):
                table.cell(r, c).paragraphs[0].text = texts[c]
                table.cell(r, c).paragraphs[0].style = styles[c]

        def add_row_picture(table, text, styles, pic_file):
            r = len(table.add_row().table.rows) - 1
            table.cell(r, 1).merge(table.cell(r, 3))
            table.cell(r, 0).paragraphs[0].text = text
            table.cell(r, 0).paragraphs[0].style = styles[0]
            table.cell(r, 1).paragraphs[0].style = styles[1]

            with open(pic_file, 'rb') as pic:
                table.cell(r, 1).paragraphs[0].add_run().add_picture(pic, width=table.cell(r, 1).width * 0.7)

        body_table = doc.add_table(1, 4, s_table)
        body_table.autofit = True
        body_table.alignment = vmi.docx.enum.table.WD_TABLE_ALIGNMENT.CENTER

        body_table.cell(0, 0).merge(body_table.cell(0, 3))
        body_table.cell(0, 0).paragraphs[0].text = '生产单\nProduction order'
        body_table.cell(0, 0).paragraphs[0].style = s_title

        add_row_text(body_table, ['产品名称\nProduct name', case['product_name'],
                                  '型号\nModel', case['product_model']], [s_body_center] * 4)
        add_row_text(body_table, ['生产单号\nOrder UID', case['order_uid'],
                                  '规格\nSpecification', case['product_specification']], [s_body_center] * 4)

        design_time = time.localtime(vmi.convert_base_inv(order_uid[-8:].lower()) / 100)
        design_time = time.strftime('%Y/%m/%d %H:%M:%S', design_time)
        designer = role_product_designer_db.find_one({'_id': case['role_product_designer_id']})['name']

        add_row_text(body_table, ['产品设计师\nProduct designer', designer,
                                  '设计时间\nDesign time', design_time], [s_body_center] * 4)

        info = case['pelvis_dicom_info']
        text = ''
        for kw in info:
            text += '\n{}: {}'.format(kw, info[kw])
        add_row_text(body_table, ['影像输入\nRadiological input', text[1:]], [s_body_center, s_body_left], [1, 3])

        text = '髋臼杯半径：{:.0f} mm'.format(case['cup_radius'])
        text += '\n影像学前倾角：{:.1f}°\n影像学外展角：{:.1f}°'.format(case['cup_RA'], case['cup_RI'])
        add_row_text(body_table, ['临床输入\nClinical input', text], [s_body_center, s_body_left], [1, 3])

        text = '主体方位：{:.0f}°，主体长径：{:.0f} mm，主体短径：{:.0f} mm，旋臂长度：{:.0f} mm，匹配方式：{}'.format(
            case['body_angle'], case['body_xr'], case['body_yr'], case['arm_length'], case['match_style'])
        add_row_text(body_table, ['造型输入\nModeling input', text], [s_body_center, s_body_left], [1, 3])

        png = pathlib.Path(p) / '.png'
        for i in range(len(case['snapshot'])):
            png.write_bytes(case['snapshot'][i])
            add_row_picture(body_table, '快照（{}/{}）\nSnapshot'.format(i + 1, len(case['snapshot'])),
                            [s_body_center, s_body_center], png)

        try:
            doc.save(file)
        except PermissionError as e:
            vmi.askInfo(str(e))


def order_inspect():
    combo = QComboBox()
    for case in case_db.find():
        if case['customer_confirmed']:
            if case['order_released'] and not case['order_inspected'] and not case['order_completed']:
                t = case['last_update_time'][:14]
                t = [t[:4], t[4:6], t[6:8], t[8:10], t[10:12], t[12:14]]
                t = '-'.join(t)
                combo.addItem(case['order_uid'] + ' ' + t, case['order_uid'])

    if not combo.count():
        vmi.askInfo('无待检生产单')
        return

    sizep = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
    dialog = QDialog()
    dialog.setSizePolicy(sizep)
    dialog.setWindowTitle('选择待检生产单')
    dialog.setLayout(QVBoxLayout())
    dialog.setMinimumWidth(200)
    dialog.layout().addWidget(combo)

    ok_cancel = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dialog)
    ok_cancel.setSizePolicy(sizep)
    ok_cancel.accepted.connect(dialog.accept)
    ok_cancel.rejected.connect(dialog.reject)
    dialog.layout().addWidget(ok_cancel)

    if dialog.exec_() != QDialog.Accepted:
        return

    r = vmi.askButtons(['下载生产单', '接受生产单', '驳回生产单'])
    if r == '下载生产单':
        user = ask_user()
        if not user:
            return False

        role_quality_inspector_id = user['role_quality_inspector_id']
        if not role_quality_inspector_db.find_one({'_id': role_quality_inspector_id}):
            vmi.askInfo('错误：只有质量检验员可以下载生产单')
            return False

        order_uid = combo.currentData()

        p = vmi.askDirectory('设计文件夹')
        if not p:
            return

        f = '{} {}.pdf'.format(order_uid, time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime()))
        f = pathlib.Path(p) / f
        order_inspect_docx(order_uid, str(f))
    elif r == '接受生产单':
        user = ask_user()
        if not user:
            return False

        role_quality_inspector_id = user['role_quality_inspector_id']
        if not role_quality_inspector_db.find_one({'_id': role_quality_inspector_id}):
            vmi.askInfo('错误：只有质量检验员可以接受生产单')
            return False

        case_set = {'role_quality_inspector_id': role_quality_inspector_id,
                    'order_released': True,
                    'order_inspected': True,
                    'order_completed': False}

        try:
            find = case_db.find_one({'order_uid': combo.currentData()})
            case_uid = vmi.convert_base(round(time.time() * 100))
            response = requests.post(url='http://med-3d.top:2334/sys/caseUpdate',
                                     headers={'_id': str(find['_id']), 'case_uid': case_uid})
            if response.text == 'true':
                case_db.find_one_and_update({'_id': find['_id']}, {'$set': case_set})
                vmi.askInfo('同步完成')
                return True
            else:
                vmi.askInfo('错误：' + response.text)
        except Exception as e:
            vmi.askInfo('错误：' + str(e))
    elif r == '驳回生产单':
        user = ask_user()
        if not user:
            return False

        role_quality_inspector_id = user['role_quality_inspector_id']
        if not role_quality_inspector_db.find_one({'_id': role_quality_inspector_id}):
            vmi.askInfo('错误：只有质量检验员可以驳回生产单')
            return False

        case_set = {'role_quality_inspector_id': role_quality_inspector_id,
                    'order_released': False,
                    'order_inspected': False,
                    'order_completed': False}

        try:
            find = case_db.find_one({'order_uid': combo.currentData()})
            case_uid = vmi.convert_base(round(time.time() * 100))
            response = requests.post(url='http://med-3d.top:2334/sys/caseUpdate',
                                     headers={'_id': str(find['_id']), 'case_uid': case_uid})
            if response.text == 'true':
                case_db.find_one_and_update({'_id': find['_id']}, {'$set': case_set})
                vmi.askInfo('同步完成')
                return True
            else:
                vmi.askInfo('错误：' + response.text)
        except Exception as e:
            vmi.askInfo('错误：' + str(e))


def order_download():
    combo = QComboBox()
    for case in case_db.find():
        if case['customer_confirmed']:
            if case['order_released'] and case['order_inspected'] and not case['order_completed']:
                t = case['last_update_time'][:14]
                t = [t[:4], t[4:6], t[6:8], t[8:10], t[10:12], t[12:14]]
                t = '-'.join(t)
                combo.addItem(case['order_uid'] + ' ' + t, case['order_uid'])

    if not combo.count():
        vmi.askInfo('无在产生产单')
        return

    sizep = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
    dialog = QDialog()
    dialog.setSizePolicy(sizep)
    dialog.setWindowTitle('选择在产生产单')
    dialog.setLayout(QVBoxLayout())
    dialog.setMinimumWidth(200)
    dialog.layout().addWidget(combo)

    ok_cancel = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dialog)
    ok_cancel.setSizePolicy(sizep)
    ok_cancel.accepted.connect(dialog.accept)
    ok_cancel.rejected.connect(dialog.reject)
    dialog.layout().addWidget(ok_cancel)

    if dialog.exec_() != QDialog.Accepted:
        return

    r = vmi.askButtons(['下载设计文件'])
    if r == '下载设计文件':
        user = ask_user()
        if not user:
            return False

        role_machine_operator_id = user['role_machine_operator_id']
        if not role_machine_operator_db.find_one({'_id': role_machine_operator_id}):
            vmi.askInfo('错误：只有设备操作员可以下载设计文件')
            return False

        order_uid = combo.currentData()

        p = vmi.askDirectory('设计文件夹')
        if not p:
            return

        case = case_db.find_one({'order_uid': order_uid})

        for f in case['order_files']:
            if f.endswith('stl'):
                if not stl_fs.find_one({'_id': case[f]}):
                    vmi.askInfo('错误：设计文件不存在 {}'.format(f))
                    return

        p = pathlib.Path(p) / (order_uid + ' ' + time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime()))
        os.mkdir(p)

        for f in case['order_files']:
            if f.endswith('stl'):
                b = stl_fs.find_one({'_id': case[f]}).read()
                (pathlib.Path(p) / (f + '.stl')).write_bytes(b)

        vmi.askInfo('下载完成')


def order_complete():
    combo = QComboBox()
    for case in case_db.find():
        if case['customer_confirmed']:
            if case['order_released'] and case['order_inspected'] and not case['order_completed']:
                t = case['last_update_time'][:14]
                t = [t[:4], t[4:6], t[6:8], t[8:10], t[10:12], t[12:14]]
                t = '-'.join(t)
                combo.addItem(case['order_uid'] + ' ' + t, case['order_uid'])

    if not combo.count():
        vmi.askInfo('无在产生产单')
        return

    sizep = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
    dialog = QDialog()
    dialog.setSizePolicy(sizep)
    dialog.setWindowTitle('选择在产生产单')
    dialog.setLayout(QVBoxLayout())
    dialog.setMinimumWidth(200)
    dialog.layout().addWidget(combo)

    ok_cancel = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, dialog)
    ok_cancel.setSizePolicy(sizep)
    ok_cancel.accepted.connect(dialog.accept)
    ok_cancel.rejected.connect(dialog.reject)
    dialog.layout().addWidget(ok_cancel)

    if dialog.exec_() != QDialog.Accepted:
        return

    r = vmi.askButtons(['完成生产单'])
    if r == '完成生产单':
        user = ask_user()
        if not user:
            return False

        role_quality_inspector_id = user['role_quality_inspector_id']
        if not role_quality_inspector_db.find_one({'_id': role_quality_inspector_id}):
            vmi.askInfo('错误：只有质量检验员可以完成生产单')
            return False

        case_set = {'role_quality_inspector_id': role_quality_inspector_id,
                    'order_released': True,
                    'order_inspected': True,
                    'order_completed': True}

        try:
            find = case_db.find_one({'order_uid': combo.currentData()})
            case_uid = vmi.convert_base(round(time.time() * 100))
            response = requests.post(url='http://med-3d.top:2334/sys/caseUpdate',
                                     headers={'_id': str(find['_id']), 'case_uid': case_uid})
            if response.text == 'true':
                case_db.find_one_and_update({'_id': find['_id']}, {'$set': case_set})
                vmi.askInfo('同步完成')
                return True
            else:
                vmi.askInfo('错误：' + response.text)
        except Exception as e:
            vmi.askInfo('错误：' + str(e))


def csv_update(db: str):
    user = ask_user()
    if not user:
        return False

    role_admin_id = user['role_admin_id']
    if not role_admin_db.find_one({'_id': role_admin_id}):
        vmi.askInfo('错误：只有管理员可以更新角色信息')
        return False

    f = vmi.askOpenFile('*.csv', db)
    if f is None:
        return

    db = database.get_collection(db)

    with open(f, newline='') as f:
        kw = []
        for row in csv.reader(f):
            if len(kw):
                kw[0] = '_id'
                i = dict(zip(kw, row))
                db.find_one_and_update({'_id': i['_id']}, {'$set': i}, upsert=True)
            else:
                kw = row.copy()


if __name__ == '__main__':
    vmi.app.setApplicationName('Skyward')
    vmi.app.setApplicationVersion('1.0')
    vmi.app.setQuitOnLastWindowClosed(False)


    def csv_update_role_customer():
        csv_update('role_customer')


    def csv_update_role_sales_worker():
        csv_update('role_sales_worker')


    def csv_update_role_product_designer():
        csv_update('role_product_designer')


    def csv_update_role_quality_inspector():
        csv_update('role_quality_inspector')


    def csv_update_role_machine_operator():
        csv_update('role_machine_operator')


    tray_icon_menu = QMenu()
    tray_icon_menu.addSection('质量检验员')
    tray_icon_menu.addAction('检验生产单').triggered.connect(order_inspect)
    tray_icon_menu.addSection('设备操作员')
    tray_icon_menu.addAction('下载设计文件').triggered.connect(order_download)
    tray_icon_menu.addSection('质量检验员')
    tray_icon_menu.addAction('完成生产单').triggered.connect(order_complete)
    tray_icon_menu.addSection('系统')
    admin_menu = QMenu('管理')
    admin_menu.addAction('更新顾客').triggered.connect(csv_update_role_customer)
    admin_menu.addAction('更新销售人员').triggered.connect(csv_update_role_sales_worker)
    admin_menu.addAction('更新产品设计师').triggered.connect(csv_update_role_product_designer)
    admin_menu.addAction('更新质量检验员').triggered.connect(csv_update_role_quality_inspector)
    admin_menu.addAction('更新设备操作员').triggered.connect(csv_update_role_machine_operator)
    tray_icon_menu.addMenu(admin_menu)
    tray_icon_menu.addAction('关于').triggered.connect(vmi.app_about)
    tray_icon_menu.addAction('退出').triggered.connect(vmi.app.quit)

    tray_icon = QSystemTrayIcon()
    tray_icon.setIcon(QWidget().style().standardIcon(QStyle.SP_ComputerIcon))
    tray_icon.setToolTip('{} {}'.format(vmi.app.applicationName(), vmi.app.applicationVersion()))
    tray_icon.setContextMenu(tray_icon_menu)
    tray_icon.show()

    vmi.app.exec_()
    vmi.appexit()
