# I - IMPORT AND INITIALIZE
import pygame, BreakSprites, time
pygame.init()
screen = pygame.display.set_mode((640, 480))

def main():
    '''This function defines the 'mainline logic' for our pyPong game.'''

    # DISPLAY
    pygame.display.set_caption("Super Break-out!")

    # ENTITIES
    background = pygame.image.load('dirt.png')
    background = background.convert()
    cover = pygame.image.load('cover.png')
    cover = cover.convert()
    screen.blit(background, (0, 0))
    mySystemFont = pygame.font.Font("The Goldsmith_Vintage.ttf", 50)
    labelstart = mySystemFont.render("PRESS SPACE", 1, (0, 0, 0))
    label1 = mySystemFont.render("Good Game!", 1, (0, 0, 0))

    #pygame.mixer.music.load("music.mp3")
    #pygame.mixer.music.set_volume(0.3)
    #pygame.mixer.music.play(-1)

    # Sprites for: ScoreKeeper label, End Zones, Ball, and Players
    score_keeper = BreakSprites.ScoreKeeper()
    ball = BreakSprites.Ball(screen)
    player = BreakSprites.Player(screen,'bed.png')
    left_endzone = BreakSprites.EndZone(screen,(19,240),"endzone.png")
    right_endzone = BreakSprites.EndZone(screen,(621,240),"endzone.png")
    top_endzone = BreakSprites.EndZone(screen,(320,20),"topendzone.png")
    bricks = []
    for row in range(18):
        bricks.append(BreakSprites.Brick(screen, "purple.png", 42, 42+31*row, 6))
        bricks.append(BreakSprites.Brick(screen, "red.png", 57, 42+31*row, 5))
        bricks.append(BreakSprites.Brick(screen, "yellow.png", 72, 42+31*row, 4))
        bricks.append(BreakSprites.Brick(screen, "orange.png", 87, 42+31*row, 3))
        bricks.append(BreakSprites.Brick(screen, "green.png", 102, 42+31*row, 2))
        bricks.append(BreakSprites.Brick(screen, "blue.png", 117, 42+31*row, 1))
    bricksGroup = pygame.sprite.Group(bricks)
    allSprites = pygame.sprite.OrderedUpdates(left_endzone, \
                                     right_endzone, top_endzone, ball, player, bricks, score_keeper)

    # ASSIGN
    clock = pygame.time.Clock()
    keepGoing = True
    gg = False
    start = False
    add = 0
    bricks_remain = 108
    once = True

    # Hide the mouse pointer
    pygame.mouse.set_visible(False)

    # LOOP
    while keepGoing:

        # TIME
        clock.tick(30)

        # EVENT HANDLING
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
            elif event.type == pygame.KEYDOWN:
                if start:
                    if event.key == pygame.K_LEFT:
                        player.moveleft()

                    if event.key == pygame.K_RIGHT:
                        player.moveright()
                if not start:
                    if event.key == pygame.K_SPACE:
                        start = True
                        labelstart = mySystemFont.render(" ", 1, (0, 0, 0))
                        ball.start()
            elif event.type == pygame.KEYUP:
                player.stop()

        # Check if ball hits left or right endzone
        if ball.rect.colliderect(left_endzone) or ball.rect.colliderect(right_endzone):
            ball.change_x()

        # Check if ball hits Player or top endzone
        if ball.rect.colliderect(player):
            ball.start()
        if ball.rect.colliderect(top_endzone):
            ball.change_y()
        if pygame.sprite.spritecollide(ball, bricksGroup, False):
            ball.change_y()

        for hitbrick in pygame.sprite.spritecollide(ball, bricksGroup, True):
            score_keeper.scored(hitbrick.get_point())
            bricks_remain -= 1

        if ball.dead():
            start = False
            #lives - 1
            ball.reset()
            player.stop()
            player.reset()
            score_keeper.died()
        if bricks_remain <= 54:
            player.half(once)
            once = False
        if bricks_remain == 0 or score_keeper.checkalive():
            gg = True

        # REFRESH SCREEN

        if not gg:
            screen.blit(labelstart, (220,220))
            if start:
                screen.blit(cover, (163,181))
            allSprites.clear(screen, background)
            allSprites.update()
            allSprites.draw(screen)

        if gg:

            screen.blit(labelstart, (220,220))
            if start:
                screen.blit(cover, (163,181))
            allSprites.clear(screen, background)
            allSprites.update()
            allSprites.draw(screen)
            keepGoing = False
            screen.blit(label1, (220,220))
        pygame.display.flip()

    # Unhide the mouse pointer
    pygame.mouse.set_visible(True)

    # Close the game window
    if gg:
        time.sleep(3)
    pygame.quit()

# Call the main function
main()


#%%
import os
import numpy as np
import tensorflow as tf
import cv2
import matplotlib.pyplot as plt
from keras.models import load_model, Model
from keras.datasets import cifar10
from keras.preprocessing.image import ImageDataGenerator
from scipy.spatial.distance import cosine, euclidean

(x_train, y_train), (x_test, y_test) = cifar10.load_data()

datagen_train = ImageDataGenerator(featurewise_center=True,
                                   featurewise_std_normalization=True)

datagen_train.fit(x_train)

def extract_features(img):
    img = np.expand_dims(img, 0)
    img = datagen_train.flow(img, batch_size=1).next()
    ft = model.predict(img)[0]
    return ft

model = load_model('model_cifarv4')
model = Model(model.input, model.get_layer('global_average_pooling2d_1').output)

features = []
for img in x_train:
    feature = extract_features(img)
    features.append(feature)
features = np.array(features)

dir = 'image_retrieval'
images = []
for path in os.listdir(dir):
    image = cv2.imread(os.path.join(dir, path))
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    images.append(image)
images = np.array(images)

axes = []
fig = plt.figure(figsize=(10, 10))
for i in range(len(images)):
    feature = extract_features(images[i])
    dist = [cosine(features[i], feature) for i in range(len(features))]
    #dist = [np.linalg.norm(features[i] - feature) for i in range(len(features))]
    ids = np.argsort(dist)[:5]
    for j in range(len(ids) + 1):
        axes.append(fig.add_subplot(10, len(ids) + 1, 6 * i + j + 1))
        if j == 0:
            plt.axis('off')
            plt.imshow(images[i])
        else:
            id = ids[j-1]
            plt.axis('off')
            plt.imshow(x_train[id])

plt.savefig('images_retrieved_cosine.png')
plt.show()


#!/usr/bin/env python
"""
pytest script for testing utils folder
"""
import typing
from pathlib import Path
import numpy as np

from hydrogels.utils import *
from hydrogels.utils import simulation
from hydrogels.utils import system
from hydrogels.utils import topology

import pytest

FOLDER = Path(__file__).absolute().parent
OUT = FOLDER / '_out.h5'

def test_topology():
    top = topology.Topology('polymer')
    assert top.is_valid

    top.add_names('Hello')
    top.add_names(['Goodbye'])
    with pytest.raises(SystemError):
        top.add_names(111)

    top.names = ['A', 'B', 'C']

    top = topology.Topology(
        'polymer',
        sequence=['A', 'A', 'A'],
        positions=np.array([
            [0., 0., 0.],
            [0., 0., 1.],
            [0., 0., 2.],
        ]),
        edges=[(0, 1), (1, 2), (2, 0)]
    )
    assert top.connected
    xyz_path = Path(__file__).parent / 'test.xyz'
    top.export_xyz(xyz_path)
    xyz_path.unlink()

def test_system():
    sys = system.System([10., 10., 10.,])
    sys.insert_species('a', 1.0, np.array([[1.0, 0.0, 0.0], [2.0, 0.0, 0.0]]))
    sys.manager.add('lj', 'all', 'all', epsilon=1.0, sigma=1.0, cutoff=2.0)
    print(sys.potential_list)
    simulation = sys.initialise_simulation(fout=str(OUT))
    # create checkpoint
    simulation.make_checkpoints(1, output_directory=str(FOLDER), max_n_saves=1)

    # run
    simulation.run(10, 0.1)

    # load from checkpoint
    simulation = sys.initialise_simulation(checkpoint_directory=FOLDER)

    # run
    simulation.run(10, 0.1)

    # load from checkpoint
    simulation = sys.initialise_simulation(checkpoint=FOLDER / 'checkpoint_10.h5')

    # run
    simulation.run(10, 0.1)

    # delete output file
    OUT.unlink()
    for target in FOLDER.glob('checkpoint_*'):
        target.unlink()

if __name__=='__main__':
    test_topology()
    test_system()


from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone
from django.core import serializers
from results.models import Result, ResultManual, ResultStage, Race
from results.slackbot import slackbot
from results.s3connection import s3_connection
import os

def generate_json(electiondate_arg, model_arg):

    message = 'Model:\t\t\t%s' % (model_arg)
    slackbot(message)

    ## path where files are saved
    file_path = os.environ['SAVER_PATH']

    ## get and output the number of races
    race_list = Race.objects.filter(electiondate=electiondate_arg)
    number_of_races = race_list.count()

    message = 'Number of races:\t\t' + str(number_of_races)
    slackbot(message)

    ## loop thru the races
    for race in race_list:

        message = '\n' + str(race) + '\n'
        slackbot(message)

        ## filename based on electiondate, statepostal, raceid
        filename = str(race.electiondate).replace('-', '') + '-' + race.statepostal + '-' + str(race.raceid) + '.json'

        ## local file to use for storing json until copied to S3
        json_file = file_path + '/tmp/' + filename

        ## filter object set for the given model by election date, raceid and level
        if model_arg == 'result' or model_arg == 'Result':
            objects = Result.objects.filter(electiondate=electiondate_arg, raceid=race.raceid, level="state")

        elif model_arg == 'resultmanual' or model_arg == 'ResultManual':
            objects = ResultManual.objects.filter(electiondate=electiondate_arg, raceid=race.raceid, level="state")

        elif model_arg == 'resultstage' or model_arg == 'ResultStage':
            objects = ResultStage.objects.filter(electiondate=electiondate_arg, raceid=race.raceid, level="state")

        # elif model_arg == 'race' or model_arg == 'Race':
        #     objects = Race.objects.filter(electiondate=electiondate_arg, raceid=race.raceid)#, level="state")

        ## get and output the number of objects
        number_of_objects = objects.count()

        # message = 'Number of objects:\t\t%s' % (str(number_of_objects))
        # slackbot(message)

        ## serialize as json
        json_output = serializers.serialize('json', objects)

        ## create file for each
        with open(json_file, 'wb') as file:
            file.write(json_output)

        ## construct a new filename for S3
        filename_formatted = filename.replace('-', '/')
        filename_s3 = 'elections/results/' + filename_formatted

        # ## save the file to s3
        with open(json_file,'rb') as file_to_upload:
            s3_connection().upload(filename_s3, file_to_upload)

        # ## delete the file
        os.remove(json_file)

class Command(BaseCommand):
    help = 'Generate JSON based on a model.'

    def add_arguments(self, parser):
        parser.add_argument('electiondate',
            help='Specify the election date as YYYY-MM-DD'
        )

        parser.add_argument('model',
            help='Specify the model (result, resultstage, resultmanual, etc) you want to grab and load'
        )

    def handle(self, *args, **options):
        electiondate_arg = options['electiondate']
        model_arg = options['model']

        start_time = timezone.localtime(timezone.now())

        start_message = '\nStarted generating:\t\t' + str(unicode(start_time)) + '\n'

        message = start_message
        slackbot(message)

        generate_json(electiondate_arg, model_arg)

        end_time = timezone.localtime(timezone.now())

        end_message = '\nFinished generating:\t\t' + str(unicode(end_time)) + '\n\n'
        generate_length = str(unicode(end_time - start_time))

        message = end_message
        slackbot(message)

        message = 'Generate length:\t\t' + generate_length
        slackbot(message)
        message = '--------------------------------------------------\n'
        slackbot(message)


#!/usr/bin/env python3

from pypresence import Presence
import psutil
import time
import sys

"""
Check README.md if you need help to change the code
"""

client_id = "356875221078245376"
RPC = Presence(client_id=client_id)
RPC.connect()

RPC.update(start=int(time.time()))

while True:
    if any(map(lambda x: (x.name().lower() == "overwatch.exe"), psutil.process_iter())) == False:
        RPC.clear()
        RPC.close()
        sys.exit()

    time.sleep(15)


#!/usr/bin/env python3
'''
Author: qiupengfei@rxthinking.com
Date: 2021-04-22 11:48:55

'''
import copy
import json
import random
import re
from queue import PriorityQueue
from datetime import timedelta

import pandas as pd
import sys
from collections import defaultdict
import logging
from typing import Dict, List

import requests.structures
from google.protobuf.json_format import MessageToDict
from qcdbmodel.qcdbmodel.models.qcaudit import SampleFilter, SampleTask
from sqlalchemy import and_

from qcaudit.application.applicationbase import ApplicationBase
from qcaudit.common.const import AUDIT_TYPE_DEPARTMENT, AUDIT_TYPE_EXPERT, AUDIT_TYPE_FIRSTPAGE, AUDIT_TYPE_HOSPITAL, \
    SAMPLE_BY_DICT, SAMPLE_BY_TAG, SAMPLE_BY_TAG_ALL, CASE_LIST_PROBLEM_COUNT
from qcaudit.domain.audit.auditrecord import AuditRecord
from qcaudit.domain.case.req import GetCaseListRequest
from qcaudit.domain.dict import CaseTagRepository, DepartmentRepository
from qcaudit.domain.dict.department import Department
from qcaudit.domain.dict.dim_dept_statis import DimDeptStatisRepository
from qcaudit.domain.dict.ward import Ward
from qcaudit.domain.dict.ward_doctor import WardDoctor
from qcaudit.domain.req import ListRequestBase, SortField
from qcaudit.domain.case.case import Case
from qcaudit.domain.case.caserepository import CaseRepository
from qcaudit.domain.sample.expertuser import ExpertUser
from qcaudit.domain.sample.expertuserrepository import ExpertUserRepository
from qcaudit.domain.sample.req import GetSampleRecordRequest, GetSampleDetailRequest
from qcaudit.domain.sample.sampleoperation import SampleOperation
from qcaudit.domain.sample.samplerecord import SampleRecord
from qcaudit.domain.sample.samplerecorditem import SampleRecordItem
from qcaudit.domain.sample.samplerecordrepository import SampleRecordRepository
from qcaudit.domain.sample.samplerecordsvc import SampleRecordService

import arrow

from qcaudit.domain.sample.sampletask import SampleFilterModel, SampleTaskModel
from qcaudit.domain.user.user import User
from qcaudit.utils.towebconfig import SAMPLE_HISTORY_EXPORT_DATA

class SampleStatData(object):

    def __init__(self):
        # 病历等级统计
        self.rateStat = {'甲': 0, '乙': 0, '丙': 0}
        # 标签统计
        self.tagStat: Dict[str, int] = defaultdict(int)
        self.totalCount = 0

    def add(self, case: Case):
        """计算抽样结果中的统计信息

        Args:
            case ([type]): [description]
        """
        self.totalCount += 1
        for tag in case.Tags:
            self.tagStat[tag] += 1
        # if case.caseRating:
        #     self.rateStat[case.caseRating] += 1
        return self

class SampleApplication(ApplicationBase):
    # 根据科室抽取
    SAMPLE_BY_DEPARTMENT = 'dept'
    # 根据病区抽取
    SAMPLE_BY_WARD = 'ward'
    # 根据责任医生抽取
    SAMPLE_BY_ATTENDING = 'attending'
    # 根据院区抽取
    SAMPLE_BY_BRANCH = 'branch'
    # 按总量抽取
    SAMPLE_BY_NUM = 'num'
    # 根据诊疗组抽取
    SAMPLE_BY_GROUP = "group"
    # 根据重点病历标签抽取
    SAMPLE_BY_TAG = "tag"

    def __init__(self, app, auditType):
        super().__init__(app, auditType)
        self.sampleRepo = SampleRecordRepository(app, auditType)
        self.sampleSvc = SampleRecordService(app, auditType)
        self.expertRepo = ExpertUserRepository(app, auditType)
        self.caseRepo = CaseRepository(app, auditType)
        self.caseTag = CaseTagRepository(app, auditType)
        self.dimDeptRepo = DimDeptStatisRepository(app, auditType)
        self.DeptRepo = DepartmentRepository(app, auditType)

    def getSampleCase(self, req: GetCaseListRequest, sampleBy=None, sampleNum=0, limit=1000,
                      existedCaseIds: List[str] = []):
        """根据筛选和排序条件抽取病历
        Args:
            req (ListRequestBase): 列表筛选和排序条件
            sampleBy ([type], optional): 根据那个字段抽取.
                None: 按总量抽取
                TODO: 其他类型待定义: 科室/院区/病区/责任医生
            sampleNum (int, optional): sampleBy字段对应的每种类型抽取多少份病历. Defaults to 0.
            limit (int, optional): 总量最多抽取多少份
            existedCaseIds (list): 已经存在的caseId. 将会和此次抽取的病历合并
        Return:
            返回抽取到的病历的列表
            返回统计信息.  TODO: 也可以考虑前端统计
        """
        existedCaseIdSet = set(existedCaseIds)
        if sampleBy == self.SAMPLE_BY_NUM and sampleNum == 0:
            sampleNum = limit
        total = len(existedCaseIdSet)
        req.size = sys.maxsize
        statData = SampleStatData()
        with self.app.mysqlConnection.session() as session:
            sampledCase = defaultdict(list)
            tags = {t.code: t for t in self.expunge(session, self.caseTag.getList(session))}
            getCaseList = self.caseRepo.getList(session, req)
            logging.info("getCaseList len is : %s" % len(getCaseList))
            for c in getCaseList:
                # print(c)
                sampleField = None
                c.convertTagToModel(tags)
                if sampleBy == self.SAMPLE_BY_BRANCH:
                    sampleField = c.branch
                elif sampleBy == self.SAMPLE_BY_ATTENDING:
                    sampleField = c.attendCode
                elif sampleBy == self.SAMPLE_BY_DEPARTMENT:
                    sampleField = c.departmentId if not c.outDeptName else c.outDeptId
                elif sampleBy == self.SAMPLE_BY_WARD:
                    sampleField = c.wardId
                elif sampleBy == self.SAMPLE_BY_GROUP:
                    sampleField = c.medicalGroupName or c.medicalGroupCode
                else:
                    sampleField = ''

                # 按照重点病历标签抽取，要求每个重点病历标签尽可能抽取到要求的数量
                if sampleBy == self.SAMPLE_BY_TAG:
                    for reqtag in req.sampleByTags:
                        if reqtag in c.tags and len(sampledCase[reqtag]) < sampleNum:
                            sampleField = reqtag
                            break
                    else:
                        continue

                if sampleField is None:
                    continue
                # print("sampleField is : %s" % sampleField)
                if len(sampledCase[sampleField]) >= sampleNum:
                    continue
                # 已经被别的项目抽取到, 忽略
                if c.sampleRecordItem is not None:
                    continue
                if c.caseId not in existedCaseIdSet:
                    total += 1
                else:
                    existedCaseIdSet.remove(c.caseId)
                c.expunge(session)
                # print("sampleField value is : %s" % len(sampledCase[sampleField]))
                sampledCase[sampleField].append(c)
                statData.add(c)
                # print("total is : %s, limit is  : %s" % (total, limit) )
                if total >= limit:
                    break
            result = []
            for _, value in sampledCase.items():
                result.extend(value)
            logging.info("result len is : %s" % len(result))
            # 把已经存在的caseId加入
            for caseId in existedCaseIdSet:
                case = self.caseRepo.getByCaseId(session, caseId)
                if case is not None:
                    case.expunge(session)
                    case.convertTagToModel(tags)
                    result.append(case)
                    statData.add(case)
                else:
                    raise ValueError(f'unknow caseId {caseId}')
            # if result:
            #     self.extraProcessCaseList(result)
        return result, statData

    def submitSampleResult(self, caseIds: List[str], auditType: str, caseType: str, operatorId: str,
                           operatorName: str, sampleId: int = 0) -> SampleRecord:
        """提交抽取结果

        Args:
            caseIds (List[str]): 本次抽取的全部病历id
            auditType (str): 抽取类型
            caseType (str): 病历类型
            operatorId (str): 抽取操作人员id
            operatorName (str): 抽取操作人员姓名
            sampleId: 抽取记录id

        Return:
            抽取历史记录
        """
        now = arrow.utcnow().to('+08:00').naive
        with self.app.mysqlConnection.session() as session:
            # 先发送生成快照的消息
            if caseType == 'running':
                if not self.sendSnapshotMessage(caseIds, self.auditType):
                    raise ValueError('发送创建快照的消息失败')
            # 创建sample_record
            sample = self.sampleRepo.getById(session, sampleId)
            if sample and sample.submit_flag:
                return None
            if not sample:
                sample = SampleRecord.newObject(self.app, operatorId=operatorId, operatorName=operatorName, isAssigned=1,
                                                auditType=auditType, caseType=caseType, createdAt=now, sampledCount=0)
                self.sampleRepo.add(session, sample)
                session.commit()
            recordId = sample.id

            # 插入sample_record_item
            count = 0
            for caseId in caseIds:
                originCaseId = None
                if caseType == 'running':
                    originCaseId = caseId
                    caseId = "{}_{}".format(caseId, self.auditType)
                if not self.sampleRepo.getItemByCaseId(session, auditType, caseId):
                    item = SampleRecordItem.newObject(self.app, caseId=caseId, auditType=self.auditType,
                                                      recordId=recordId, originCaseId=originCaseId)
                    self.sampleRepo.addItem(session, item)
                    count += 1
            sample.setSampledCount(count)
            sample.submit()
            session.commit()

            sample = self.sampleRepo.getById(session, sampleId)
            sample.expunge(session)
            return sample

    def sendSnapshotMessage(self, caseIds: List[str], auditType):
        """发送生成快照的消息

        Args:
            caseIds (List[str]): [description]
            auditType ([type]): [description]
        """
        try:
            for caseId in caseIds:
                self.app.mq.publish(
                    {
                        'type': 'qc.snapshot',
                        'body': {
                            'crawlFirst': True,
                            'caseId': caseId,
                            'patientId': None,
                            'auditType': auditType
                        }
                    }
                )
        except Exception as e:
            logging.exception(e)
            return False
        else:
            return True

    def getSampleRecordHistory(self, req: GetSampleRecordRequest):
        """获取抽取历史
        """
        with self.app.mysqlConnection.session() as session:
            result = []
            count = self.sampleRepo.getCount(session, req)
            for item in self.sampleRepo.getList(session, req):
                item.expunge(session)
                result.append(item)
            return result, count

    def getSampleDetail(self, req: GetSampleDetailRequest):
        """获取抽取病历详情
        """
        with self.app.mysqlConnection.session() as session:
            result = []
            count = self.sampleRepo.getItemCount(session, req)
            itemList = self.sampleRepo.getItemListByQuery(session, req)
            for SampleRecordItem in itemList:
                SampleRecordItem.expunge(session)
                result.append(SampleRecordItem)
            return result, count

    def assignExpert(self, sampleRecordId, caseType, assignType, auditType="", noSameDept=False, users=[]):
        """给抽取结果分配专家

        Args:
            sampleRecordId (int): [description]
            caseType :
            assignType ([type]): 平均分配或自动分配
            auditType ([type]): 平均分配时需读取该属性增加判断
            noSameDept ([bool]): 分配时病历和专家不能是同一个科室
            users ([list]): 指定的用户数组, list[ExpertUser]
        """
        with self.app.mysqlConnection.session() as session:
            if assignType == SampleRecord.ASSIGN_TYPE_AVG:
                # 获取统计科室 科室名称归一
                dept_map = {item.deptname: item.statis_name for item in self.dimDeptRepo.getList(session)}
                if not users:
                    # 获取所有的专家
                    users = list(self.expertRepo.getList(session, caseType))
                userCount = len(users)
                if userCount == 0:
                    raise ValueError('没有可分配的专家')

                # 专家优先级队列，已分配病历数少的专家优先被分配
                experts = PriorityQueue()
                user_map = {}
                for u in users:
                    if not u.department:
                        u.setDepartment(User.getUserDepartment(self.app.mongo, u.userId))
                    experts.put((0, u.userId))
                    user_map[u.userId] = u

                items = list(self.sampleRepo.getItemList(session, sampleRecordId, auditType))
                items = [x for x in items if x.isMannalAssigned not in (1, 2)]  # 1-指定分配, 2-病区分配
                random.shuffle(items)  # 病历顺序先打乱
                for i in range(0, len(items)):
                    # 决定哪个专家审核
                    item = items[i]
                    triedUser = []
                    while not experts.empty():
                        count, userid = experts.get()
                        expert = user_map.get(userid)
                        logging.info("assignExpert, expert.userName: %s", expert.userName)
                        # 判断是否允许病历和专家是同一个科室
                        logging.info("assignExpert, noSameDept: %s, expert.department: %s", noSameDept, expert.department)
                        if noSameDept and expert.department:
                            caseDepartment = item.caseModel.outDeptName or item.caseModel.department
                            if expert.department == caseDepartment or expert.department == dept_map.get(caseDepartment):
                                triedUser.append((count, userid))
                                continue
                        logging.info("assign")
                        item.assignExpert(userid, expert.userName)
                        experts.put((count+1, userid))
                        break
                    for count, userid in triedUser:
                        experts.put((count, userid))

                    if i % 100 == 0:
                        # 中途提交, 防止数量太多
                        session.commit()
            else:
                self.sampleSvc.assignExpertAuto(sampleRecordId)

            sampleModel = self.sampleRepo.getRecordById(session, sampleRecordId)
            # 修改抽取记录分配状态
            if sampleModel:
                sampleModel.model.isAssigned = 2
            session.commit()
            logging.info("assignExpert, end.")

    def assginExpertToItem(self, sampleRecordItemId, sampleRecordItemIds, expertId, expertName, many=0, isMannalAssigned=1):
        """为某一份或多份病历指定审核专家
        """
        with self.app.mysqlConnection.session() as session:
            if many:
                items = self.sampleRepo.getItemById(session, sampleRecordItemIds, many)
                # 人工批量分配
                for item in items:
                    recordId = item.assignExpert(expertId, expertName, isMannalAssigned=isMannalAssigned)
                return recordId
            else:
                # 人工单独分配
                item = self.sampleRepo.getItemById(session, sampleRecordItemId, many)
                recordId = item.assignExpert(expertId, expertName, isMannalAssigned=isMannalAssigned)
                return recordId

    def ward_assign(self, sample_item_ids, expert_id, expert_name, isMannalAssigned):
        """
        病区/科室 批量分配
        :return:
        """
        ids = ",".join([str(item) for item in sample_item_ids])
        with self.app.mysqlConnection.session() as session:
            update_sql = '''update sample_record_item set expertId = "{expertId}", expertName = "{expertName}", isMannalAssigned = "{isMannalAssigned}" where id in ({ids})'''.format(
                expertId=expert_id, expertName=expert_name, isMannalAssigned=isMannalAssigned, ids=ids)
            session.execute(update_sql)
            # print("ward_assign, update_sql:", update_sql)
            isAssigned = 2 if expert_name and expert_id else 1
            update_sample_record_isAssigned_sql = '''update sample_record set isAssigned = {isAssigned} where sample_record.id in (select recordId from sample_record_item where sample_record_item.id in ({ids}))'''.format(
                isAssigned=isAssigned, ids=ids)
            session.execute(update_sample_record_isAssigned_sql)
            # print("ward_assign, update_sample_record_isAssigned_sql:", update_sample_record_isAssigned_sql)

    def addExpert(self, expertId, expertName, caseType):
        """添加一个质控人员到当前审核环节

        Args:
            expertId ([type]): [description]
        """
        user = ExpertUser.newObject(self.app)
        user.setModel(
            userId=expertId, userName=expertName,
            auditType=self.auditType,
            caseType=caseType
        )
        with self.app.mysqlConnection.session() as session:
            self.expertRepo.add(session, user)

    def removeExpert(self, expertId, caseType):
        """将一个质控人员从当前审核环节排除

        Args:
            expertId ([type]): [description]
        """
        with self.app.mysqlConnection.session() as session:
            self.expertRepo.delete(session, expertId, caseType)

    def getExpertList(self, caseType) -> List[ExpertUser]:
        """获取当前环节所有可用的专家
        """
        with self.app.mysqlConnection.session() as session:
            result = []

            for item in self.expertRepo.getList(session, caseType):
                item.expunge(session)
                result.append(item)

            return result

    def removeSampleRecord(self, recordId: int):
        """删除抽取历史

        Args:
            recordId (int): [description]
        """
        with self.app.mysqlConnection.session() as session:
            self.sampleRepo.delete(session, recordId)

    def removeTask(self, taskId):
        """废除任务

        Args:
            expertId ([type]): [description]
        """
        with self.app.mysqlConnection.session() as session:
            self.sampleRepo.deleteItem(session, taskId)

    def extraProcessCaseList(self, caseList):
        # 额外添加分数等级，数据库中不存储等级
        for item in caseList:
            print(item.caseRating)
            print(item.caseScore)
            if float(item.caseScore) >= 90:
                item.caseRating = "甲"
            elif float(item.caseScore) >= 80:
                item.caseRating = "乙"
            else:
                item.caseRating = "丙"

    def writeSampleExcel(self, sampleList, request, caseTagDict, patient_id_name="病历号"):
        """
        抽取历史列表写入excel
        :return:
        """
        title = ["重点病历", "问题数", patient_id_name, "姓名", "科室", "病区", "入院日期", "出院日期", "住院天数", "责任医生", "分配医生",
                 "质控医生", "质控日期"]
        problem_dict = {}
        if request.isExportDetail == 1:
            title += ["问题描述", "病案扣分", "首页扣分"]
            case_id_list = [item.caseModel.caseId for item in sampleList]
            self.get_problem_dict(case_id_list, problem_dict, request)

        row_data = []
        for x in sampleList:
            tag_list = []
            if x.caseModel.tags:
                for tag in x.caseModel.tags:
                    t = caseTagDict.get(tag, None) or None
                    name = t.name if t else ""
                    if name:
                        tag_list.append(name)
            tags = ','.join(tag_list) or ""
            problemCount = AuditRecord(x.auditRecord).getProblemCount(request.auditType) if x.auditRecord else 0
            patientId = x.caseModel.patientId
            name = x.caseModel.name or ""
            dischargeDept = x.caseModel.outDeptName or ""
            department = dischargeDept or x.caseModel.department or ""
            ward = x.caseModel.wardName or ""
            admitTime = x.caseModel.admitTime.strftime('%Y-%m-%d') if x.caseModel.admitTime else ""
            dischargeTime = x.caseModel.dischargeTime.strftime('%Y-%m-%d') if x.caseModel.dischargeTime else ""
            inpDays = x.caseModel.inpDays or 0
            attendDoctor = x.caseModel.attendDoctor or ""
            distributeDoctor = x.model.expertName or ""
            reviewer = getattr(x.auditRecord,
                               AuditRecord.getOperatorFields(auditType=request.auditType).reviewerNameField) or ""
            ar_review_time = getattr(x.auditRecord,
                                     AuditRecord.getOperatorFields(auditType=request.auditType).reviewTimeField)
            reviewTime = ar_review_time.strftime('%Y-%m-%d %H:%M:%S') if ar_review_time else ""

            tmp = [tags, problemCount, patientId, name, department, ward, admitTime, dischargeTime, inpDays,
                   attendDoctor, distributeDoctor, reviewer, reviewTime]
            if request.isExportDetail == 1:
                problem_list = problem_dict.get(x.caseModel.caseId, [])
                if not problem_list:
                    tmp += ["", "", ""]
                    row_data.append(tmp)
                for item in problem_list:
                    tmp1 = copy.deepcopy(tmp)
                    tmp1 += item
                    row_data.append(tmp1)
            else:
                row_data.append(tmp)

        df = pd.DataFrame(row_data, columns=title)
        return df

    def format_sample_history_export_data(self, sampleList, request, caseTagDict, patient_id_name="病历号"):
        """
        格式化抽取历史导出数据
        :return:
        """
        problem_dict = {}
        if request.isExportDetail == 1:
            case_id_list = [item.caseModel.caseId for item in sampleList]
            self.get_problem_dict(case_id_list, problem_dict, request)
        row_data = []
        if not sampleList:
            tmp = dict(SAMPLE_HISTORY_EXPORT_DATA, **{patient_id_name: ""})
            row_data.append(tmp)
        for x in sampleList:
            tag_list = []
            if x.caseModel.tags:
                for tag in x.caseModel.tags:
                    t = caseTagDict.get(tag, None) or None
                    name = t.name if t else ""
                    if name:
                        tag_list.append(name)
            tags = ','.join(tag_list) or ""
            problemCount = AuditRecord(x.auditRecord).getProblemCount(request.auditType) if x.auditRecord else 0
            patientId = x.caseModel.patientId
            name = x.caseModel.name or ""
            dischargeDept = x.caseModel.outDeptName or ""
            department = dischargeDept or x.caseModel.department or ""
            ward = x.caseModel.wardName or ""
            group = x.caseModel.medicalGroupName or ""
            admitTime = x.caseModel.admitTime.strftime('%Y-%m-%d') if x.caseModel.admitTime else ""
            dischargeTime = x.caseModel.dischargeTime.strftime('%Y-%m-%d') if x.caseModel.dischargeTime else ""
            inpDays = x.caseModel.inpDays or 0
            attendDoctor = x.caseModel.attendDoctor or ""
            distributeDoctor = x.model.expertName if x.model else ""
            reviewer = getattr(x.auditRecord,
                               AuditRecord.getOperatorFields(auditType=request.auditType).reviewerNameField) if x.auditRecord else ""
            ar_review_time = getattr(x.auditRecord,
                                     AuditRecord.getOperatorFields(auditType=request.auditType).reviewTimeField) if x.auditRecord else ""
            reviewTime = ar_review_time.strftime('%Y-%m-%d %H:%M:%S') if ar_review_time else ""

            tmp = {"重点病历": tags, "问题数": problemCount, patient_id_name: patientId, "姓名": name, "科室": department,
                   "病区": ward, "诊疗组": group, "入院日期": admitTime, "出院日期": dischargeTime, "住院天数": inpDays, "责任医生": attendDoctor,
                   "分配医生": distributeDoctor, "质控医生": reviewer, "质控日期": reviewTime}
            if request.isExportDetail == 1:
                problem_list = problem_dict.get(x.caseModel.caseId, [])
                if not problem_list:
                    tmp["问题描述"] = ""
                    tmp["病案扣分"] = ""
                    tmp["首页扣分"] = ""
                    row_data.append(tmp)
                for item in problem_list:
                    tmp1 = copy.deepcopy(tmp)
                    tmp1["问题描述"] = item[0]
                    tmp1["病案扣分"] = item[1]
                    tmp1["首页扣分"] = item[2]
                    row_data.append(tmp1)
            else:
                row_data.append(tmp)
        return row_data

    def get_problem_dict(self, case_id_list, problem_dict, request):
        """
        根据caseId查询问题
        :return:
        """
        if not case_id_list:
            return
        case_ids = ','.join(['"%s"' % item for item in case_id_list])
        with self.app.mysqlConnection.session() as session:
            query_problem_score_sql = '''select cp.caseId, cp.reason, cp.score, cp.problem_count, df.score, cp.comment,
            ei.documentName, ei.first_save_time, cp.docId from caseProblem cp
            inner join `case` c on c.audit_id = cp.audit_id left join dim_firstpagescore df on cp.qcItemId = df.qcitemid
            left join emrInfo ei on cp.caseId = ei.caseId and cp.docId = ei.docId
            where cp.is_deleted = 0 and cp.score != 0 and cp.caseId in (%s) and cp.auditType = "%s"''' % (case_ids, request.auditType)
            query = session.execute(query_problem_score_sql)
            queryset = query.fetchall()
            for item in queryset:
                if not problem_dict.get(item[0], None):
                    problem_dict[item[0]] = []
                score = item[2] or 0
                problem_count = item[3] or 1
                fp_score = item[4] or 0
                reason = item[1] or ""
                comment = item[5] or ""
                doc_name = item[6] or ""
                doc_save_time = item[7] or None
                doc_info = ""
                if str(item[8]) != "0":
                    if doc_name:
                        doc_info += "【" + doc_name
                    if doc_info:
                        if doc_save_time:
                            doc_info += doc_save_time.strftime("%Y-%m-%d") + "】"
                        else:
                            doc_info += "】"
                else:
                    doc_info = "【缺失文书】"
                reason_comment = doc_info + reason + "。" + comment
                problem_dict[item[0]].append([reason_comment, score * problem_count or "",
                                              fp_score * problem_count or ""])

    def checkSampleAssigned(self, sampleRecordId, auditType):
        with self.app.mysqlConnection.session() as session:
            sample_obj = self.sampleSvc.repo.getRecordById(session, sampleRecordId)
            items = self.sampleSvc.repo.getItemList(session, sampleRecordId, auditType)
            for item in items:
                if not item.expertId:
                    return
            sample_obj.model.isAssigned = 2

    def query_wardDoctor_from_ward(self, assign_flag=2):
        """
        从ward基础表查询ward信息
        :return:
        """
        if str(assign_flag) == "1":
            wardModel = Department.getModel(self.app)
        else:
            wardModel = Ward.getModel(self.app)
        with self.app.mysqlConnection.session() as session:
            query = session.query(wardModel).order_by(wardModel.sort_no)
        return query.all()

    def query_wardDoctor_from_ward_doctor(self, doctor_id, assign_flag=0):
        """
        从ward_doctor表查询已保存过的病区分配医生
        :return:
        """
        if assign_flag == 1:
            wardModel = Department.getModel(self.app)
        else:
            wardModel = Ward.getModel(self.app)
        wardDoctorModel = WardDoctor.getModel(self.app)
        with self.app.mysqlConnection.session() as session:
            query = session.query(wardDoctorModel).join(wardModel, wardDoctorModel.ward == wardModel.name).filter(
                wardDoctorModel.user_id == doctor_id).order_by(wardModel.sort_no)
        return query.all()

    def update_wardDoctor(self, doctor_id, ward_doctor, assign_flag=2):
        """
        更新ward_doctor数据
        :return:
        """
        wardDoctorModel = WardDoctor.getModel(self.app)
        if assign_flag == 1:
            wardModel = Department.getModel(self.app)
        else:
            wardModel = Ward.getModel(self.app)
        with self.app.mysqlConnection.session() as session:
            query_doctor_id_is_exist = session.query(wardDoctorModel).filter(wardDoctorModel.user_id == doctor_id).first()
            if query_doctor_id_is_exist:
                for item in ward_doctor:
                    ward_doctor_obj = session.query(wardDoctorModel).filter(
                        wardDoctorModel.user_id == doctor_id, wardDoctorModel.ward == item["ward"]).first()
                    if ward_doctor_obj:
                        ward_doctor_obj.doctorName = item["doctorName"]
                        ward_doctor_obj.doctorId = item["doctorId"]
            else:
                ward_data = session.query(wardModel).all()
                insert_sql = '''insert into ward_doctor (ward, user_id) values '''
                for item in ward_data:
                    insert_sql += '("%s", "%s"),' % (item["name"], doctor_id)
                insert_sql = insert_sql[:-1]
                session.execute(insert_sql)
                session.commit()
                for item in ward_doctor:
                    ward_doctor_obj = session.query(wardDoctorModel).filter(
                        and_(wardDoctorModel.user_id == doctor_id, wardDoctorModel.ward == item["ward"])).first()
                    if ward_doctor_obj:
                        ward_doctor_obj.doctorName = item["doctorName"]
                        ward_doctor_obj.doctorId = item["doctorId"]

    def get_ward_doctor_dict(self, doctor_id, assign_flag):
        """
        获取病区分配医生字典
        :return:
        """
        data = self.query_wardDoctor_from_ward_doctor(doctor_id, assign_flag)
        return {item.ward: {"doctorId": item.doctorId or "", "doctorName": item.doctorName or ""} for item in data}

    @classmethod
    def verify_ward_doctor(cls, data, ward_doctor_dict):
        """
        验证待分配数据是否均有分配医生信息
        :return:
        """
        for ward, sample_item_ids in data.items():
            expert_id = ward_doctor_dict.get(ward, {}).get("doctorId", "")
            expert_name = ward_doctor_dict.get(ward, {}).get("doctorName", "")
            if not expert_id or not expert_name:
                return False
        return True

    def record_sample_operation(self, sampleId, caseType, caseIds, operatorId=None, operatorName=None, sampleBy=None, sampleCount=0, existedCaseIds=[], sampleFilter=None):
        """记录抽取操作日志
        """
        now = arrow.utcnow().to('+08:00').naive
        with self.app.mysqlConnection.session() as session:
            sample = self.sampleRepo.getById(session, sampleId)
            if sample and sample.submit_flag:
                return None
            if not sample:
                sample = SampleRecord.newObject(self.app, operatorId=operatorId, operatorName=operatorName, isAssigned=1,
                                                auditType=self.auditType, caseType=caseType, createdAt=now, sampledCount=0)
                self.sampleRepo.add(session, sample)
                session.commit()

            sample.setSampledCount(len(caseIds))
            sample_dict = {"dept": "科室", "ward": "病区", "attending": "责任医生", "branch": "院区",
                           "num": "总量", "group": "诊疗组", "tag": "重点病历", "tags": "重点病历"}
            sample.addSampleBy(sample_dict.get(sampleBy))

            action = "抽取"
            content = f"按{sample_dict.get(sampleBy)}抽取，每个{sample_dict.get(sampleBy)}至少抽取{sampleCount}份"
            if sampleCount >= 1000000:
                content = f"按{sample_dict.get(sampleBy)}抽取，抽取全部"
            count = len(caseIds) - (len(existedCaseIds) or 0)
            # 新增加操作日志
            operation = SampleOperation.newObject(self.app, sample_id=sample.id, name=action, content=content,
                                                  sample_by=sampleBy, conditions=','.join(sampleFilter),
                                                  sampled_count=count, sampled_case=','.join(caseIds), submit_flag=0,
                                                  operator=operatorName, operate_time=now)
            self.sampleRepo.addOperation(session, operation)
            session.commit()
            sample.setLastOperationId(operation.id)
            return sample.id

    def update_sample_case(self, sampleId, caseType, caseIds, operatorId=None, operatorName=None):
        """记录抽取历史记录，添加病历和删除病历 两种操作
        如果与之前的操作是同一种类型，不新增操作日志
        """
        now = arrow.utcnow().to('+08:00').naive
        with self.app.mysqlConnection.session() as session:
            sample = self.sampleRepo.getById(session, sampleId)
            if sample and sample.submit_flag:
                return None
            if not sample:
                sample = SampleRecord.newObject(self.app, operatorId=operatorId, operatorName=operatorName, isAssigned=1,
                                                auditType=self.auditType, caseType=caseType, createdAt=now, sampledCount=0)
                self.sampleRepo.add(session, sample)
                session.commit()

            # 根据抽取病历号数量判断是添加还是删除
            action = "删除" if len(caseIds) < sample.sampledCount else "添加"
            count = abs(len(caseIds) - sample.sampledCount)
            content = f'{action}病历{count}份'

            # 在sampleRecord中缓存已抽取病历数和抽取规则
            sample.setSampledCount(len(caseIds))
            sample.addSampleBy("自定义")

            # 相同的操作日志合并
            last_operation = self.sampleRepo.getSampleOperationById(session, sample.lastOperation)
            if last_operation and last_operation.name == action:
                last_operation.setSampledCase(caseIds)
                count += int(re.search(r'\d+', f'{last_operation.content}默认0份').group())
                last_operation.model.content = f'{action}病历{count}份'
                return sample.id
            # 新增加操作日志
            operation = SampleOperation.newObject(self.app, sample_id=sample.id, name=action, content=content,
                                                  sample_by="custom", conditions="", sampled_count=0,
                                                  sampled_case=','.join(caseIds), submit_flag=0,
                                                  operator=operatorName, operate_time=now)
            self.sampleRepo.addOperation(session, operation)
            session.commit()
            sample.setLastOperationId(operation.id)
            return sample.id

    def getSampleOperations(self, sampleId):
        with self.app.mysqlConnection.session() as session:
            sample = self.sampleRepo.getRecordById(session, sampleId)
            sample.expunge(session)
            result = [item for item in self.expunge(session, self.sampleRepo.getSampleOperations(session, sampleId))]
        return sample, result

    def getSampleFilterList(self, request):
        """
        获取抽取条件列表
        :return:
        """
        with self.app.mysqlConnection.session() as session:
            query = session.query(SampleFilter).filter(SampleFilter.is_delete == 0)
            if request.name:
                query = query.filter(SampleFilter.name.like("%{}%".format(request.name)))
            if request.auditType:
                query = query.filter(SampleFilter.auditType == request.auditType)
            if request.startTime:
                query = query.filter(SampleFilter.create_time >= request.startTime)
            if request.endTime:
                query = query.filter(SampleFilter.create_time <= request.endTime)
            if request.caseType:
                query = query.filter(SampleFilter.caseType == request.caseType)
            res = []
            total = query.count()
            start = request.start or 0
            size = request.size or 15
            query = query.slice(start, start + size)
            for item in query.all():
                session.expunge(item)
                res.append(item)
            return res, total

    def saveSampleFilter(self, request, all_tags=[]):
        """
        抽取条件保存
        :return:
        """
        with self.app.mysqlConnection.session() as session:
            if request.id:
                query = session.query(SampleFilter).filter(SampleFilter.id == request.id)
                if request.deleteFlag == 1:
                    query.update({"is_delete": 1}, synchronize_session=False)
                    return True, ""
                if request.name:
                    query.update({"name": request.name}, synchronize_session=False)
                if request.filter:
                    # filter_data = MessageToDict(request.filter)
                    filter_data = request.filter
                    sample_by = SAMPLE_BY_DICT.get(request.filter.get("sampleBy")) or ""
                    sample_num = request.filter.get("sampleCount") or 0
                    describe = f"按{sample_by}抽取"
                    sample_range = "全部"
                    if sample_num and sample_num != 1000000:
                        describe += f"，每个{sample_by}至少抽取{sample_num}份。"
                    if sample_by == "重点病历":
                        sample_range = "全部" if len(all_tags) == len(request.filter.tags) else json.dumps(list(request.filter.tags))
                    elif sample_by == "诊疗组":
                        sample_range = "全部" if request.filter.get("group", "") == "all" else request.filter.get("group", "")
                    query.update({"filter": json.dumps(filter_data), "range": sample_range, "describe": describe}, synchronize_session=False)
                return True, ""
            query = session.query(SampleFilter).filter(SampleFilter.name == request.name, SampleFilter.auditType == request.auditType, SampleFilter.caseType == request.caseType, SampleFilter.is_delete == 0)
            if query.first():
                logging.info("sample filter name: %s is exist.", request.name)
                return False, "名称已存在"
            if not request.name:
                return False, "名称不能为空"
            # filter_data = MessageToDict(request.filter)
            filter_data = request.filter
            sample_by = SAMPLE_BY_DICT.get(request.filter.get("sampleBy")) or ""
            sample_num = request.filter.get("sampleCount") or 0
            describe = f"按{sample_by}抽取"
            sample_range = "全部"
            if sample_num and sample_num != 1000000:
                describe += f"，每个{sample_by}至少抽取{sample_num}份。"
            if sample_by == "重点病历":
                sample_range = "全部" if len(all_tags) == len(request.filter.get("tags", [])) else json.dumps(list(request.filter.get("tags", [])))
            elif sample_by == "诊疗组":
                sample_range = "全部" if request.filter.get("group") == "all" else request.filter.get("group", "")
            obj_dict = {"name": request.name, "auditType": request.auditType, "filter": json.dumps(filter_data),
                        "describe": describe, "range": sample_range, "is_delete": 0, "create_time": arrow.utcnow().to('+08:00').naive,
                        "caseType": request.caseType}
            obj = SampleFilterModel.newObject(self.app, **obj_dict)
            self.sampleRepo.add(session, obj)
            return True, ""

    def getSampleTaskList(self, request):
        """
        抽取定时任务列表
        :return:
        """
        with self.app.mysqlConnection.session() as session:
            query = session.query(SampleTask).filter(SampleTask.is_delete == 0, SampleTask.status.in_([1, 2]))
            if request.name:
                query = query.filter(SampleTask.name.like("%{}%".format(request.name)))
            if request.auditType:
                query = query.filter(SampleTask.auditType == request.auditType)
            if request.startTime:
                query = query.filter(SampleTask.create_time >= request.startTime)
            if request.endTime:
                query = query.filter(SampleTask.create_time <= request.endTime)
            if request.caseType:
                query = query.filter(SampleTask.caseType == request.caseType)
            total = query.count()
            start = request.start or 0
            size = request.size or 15
            query = query.slice(start, start + size)
            res = []
            for item in query.all():
                session.expunge(item)
                res.append(item)
            return res, total

    def saveSampleTask(self, request):
        """
        抽取定时任务保存
        :return:
        """
        with self.app.mysqlConnection.session() as session:
            if request.id:
                query = session.query(SampleTask).filter(SampleTask.id == request.id)
                if request.deleteFlag == 1:
                    query.update({"is_delete": 1}, synchronize_session=False)
                    return 0, True, ""
                if request.name:
                    query.update({"name": request.name}, synchronize_session=False)
                if request.status:
                    query.update({"status": request.status}, synchronize_session=False)
                if request.sampleFilter and request.sampleFilter.sampleBy:
                    # filter_data = MessageToDict(request.sampleFilter)
                    filter_data = request.sampleFilter
                    query.update({"sample_filter": json.dumps(filter_data)}, synchronize_session=False)
                if request.days:
                    query.update({"days": request.days}, synchronize_session=False)
                if request.firstSampleTime:
                    query.update({"first_sample_time": request.firstSampleTime}, synchronize_session=False)
                if request.queryFilter:
                    # filter_data = MessageToDict(request.queryFilter)
                    filter_data = request.queryFilter
                    if filter_data:
                        query.update({"query_filter": json.dumps(filter_data)}, synchronize_session=False)
                if request.assignDoctor:
                    # filter_data = [MessageToDict(item) for item in request.assignDoctor]
                    filter_data = request.assignDoctor
                    if filter_data:
                        query.update({"assign_doctor": json.dumps(filter_data, ensure_ascii=False)}, synchronize_session=False)
                if request.taskType:
                    query.update({"type": request.taskType}, synchronize_session=False)
                if request.notCurrentDeptFlag != query.first().notCurrentDeptFlag:
                    query.update({"notCurrentDeptFlag": request.notCurrentDeptFlag}, synchronize_session=False)
                if request.firstSampleTime:
                    query.update({"first_sample_time": request.firstSampleTime}, synchronize_session=False)
                    query.update({"next_run_time": request.firstSampleTime}, synchronize_session=False)
                return 0, True, ""
            query = session.query(SampleTask).filter(SampleTask.name == request.name, SampleTask.auditType == request.auditType, SampleTask.caseType == request.caseType, SampleTask.is_delete == 0)
            if query.first():
                logging.info("sample task name: %s is exist.", request.name)
                return 0, False, "名称已存在"
            if not request.name:
                return 0, False, "名称不能为空"
            obj_dict = {"name": request.name, "auditType": request.auditType,
                        "type": request.taskType, "notCurrentDeptFlag": request.notCurrentDeptFlag,
                        "is_delete": 0, "create_time": arrow.utcnow().to('+08:00').naive, "days": request.days or 0,
                        "caseType": request.caseType, "status": 1}
            if request.firstSampleTime:
                obj_dict["first_sample_time"] = request.firstSampleTime
                obj_dict["next_run_time"] = request.firstSampleTime
            else:
                next_run_time = self.get_next_run_time()
                obj_dict["next_run_time"] = next_run_time.strftime("%Y-%m-%d %H:%M:%S")
            if request.queryFilter:
                # obj_dict["query_filter"] = json.dumps(MessageToDict(request.queryFilter), ensure_ascii=False)
                obj_dict["query_filter"] = json.dumps(request.queryFilter, ensure_ascii=False)
            if request.sampleFilter:
                # obj_dict["sample_filter"] = json.dumps(MessageToDict(request.sampleFilter), ensure_ascii=False)
                obj_dict["sample_filter"] = json.dumps(request.sampleFilter, ensure_ascii=False)
            if request.assignDoctor:
                assign_doctors = request.assignDoctor
                # assign_doctors = []
                # for item in request.assignDoctor:
                #     assign_doctors.append(MessageToDict(item))
                obj_dict["assign_doctor"] = json.dumps(assign_doctors, ensure_ascii=False)
            obj = SampleTaskModel.newObject(self.app, **obj_dict)
            self.sampleRepo.add(session, obj)
            session.commit()
            return obj.id, True, ""

    @classmethod
    def get_next_run_time(cls):
        import datetime
        now = arrow.utcnow().to("+08:00").naive
        year = now.year
        month = now.month + 1
        if month == 13:
            month = 1
            year += 1
        return datetime.date(year=year, month=month, day=1)

    def queryRunTask(self):
        """
        查询需执行的抽取任务
        :return:
        """
        with self.app.mysqlConnection.session() as session:
            now = arrow.utcnow().to("+08:00").naive
            query = session.query(SampleTask).filter(SampleTask.status == 1, SampleTask.is_delete == 0, SampleTask.next_run_time <= now)
            res = []
            for item in query.all():
                session.expunge(item)
                res.append(item)
            return res

    def run_task(self, task: SampleTask):
        """
        执行抽取任务
        1. 生成GetCaseListRequest请求对象req, sampleBy: task.sample_filter.sampleBy, sampleNum: task.sample_filter.sampleNum
        2. 执行self.getSampleCase(req, sampleBy=, sampleNum=)
            得到caseList、caseIds
        3. 执行self.record_sample_operation(sampleId, caseType, caseIds, operatorId=, operatorName=, sampleBy=, sampleCount=, sampleFilter=conditions)
            得到sampleId
        4. 执行self.submitSampleResult(caseIds, auditType, caseType, operatorId, operatorName, sampleId)
        5. 根据 task.type==分配
            task.assign_doctor 生成 list[ExpertUser]
            判断是否执行 self.assignExpert(sampleId, caseType, assignType=avg, auditType, avoidSameDept=task.notCurrentDeptFlag, users=)
        6. 全部执行完成后将task.next_run_time 设置成 task.days 天后
        :return:
        """
        sample_filter = json.loads(task.sample_filter)
        req = self.get_run_task_case_req(task)
        caseList, total = self.getSampleCase(req, sampleBy=sample_filter["sampleBy"], sampleNum=sample_filter["sampleCount"])
        caseIds = [caseInfo.caseId for caseInfo in caseList]
        conditions = ["全部"]
        sampleBy = sample_filter["sampleBy"]
        if sampleBy == SAMPLE_BY_TAG:
            with self.app.mysqlConnection.session() as session:
                all_tags = self.caseTag.getList(session) or []
            if len(all_tags) > len(sample_filter["tags"]):
                conditions = sample_filter["tags"]
            else:
                sampleBy = SAMPLE_BY_TAG_ALL
        sampleId = self.record_sample_operation(-1, task.caseType, caseIds, operatorId="AI", operatorName="AI", sampleBy=sampleBy,
                                                sampleCount=sample_filter["sampleCount"], sampleFilter=conditions)
        self.submitSampleResult(caseIds, task.auditType, task.caseType, "system", "task", sampleId)
        if "分配" in task.type:
            users = []
            if task.assign_doctor:
                for item in json.loads(task.assign_doctor):
                    user_dict = {"userId": item["code"], "userName": item["name"]}
                    user = ExpertUser.newObject(self.app, **user_dict)
                    user.setDepartment(item["department"])
                    users.append(user)
            self.assignExpert(sampleId, task.caseType, assignType="avg", auditType=task.auditType, noSameDept=task.notCurrentDeptFlag, users=users)
        self.updateTaskNextRunTime(task)

    @classmethod
    def get_run_task_case_req(cls, task):
        """
        获取case list的req对象
        :return:
        """
        now = arrow.utcnow().to("+08:00").naive
        last_time = now - timedelta(days=int(task.days))
        query_filter = json.loads(task.query_filter)
        query_filter["auditType"] = task.auditType
        query_filter["caseType"] = task.caseType
        # sample_filter = json.loads(task.sample_filter)
        # tags = sample_filter["tags"]
        # query_filter["sampleByTags"] = tags
        # query_filter["tags"] = [tag for tag in tags.split(',') if tag]
        timeType = 5 if task.caseType == "running" else 1
        query_filter["timeType"] = timeType
        query_filter["startTime"] = last_time.strftime("%Y-%m-%d %H:%M:%S")
        if query_filter.get("sortField"):
            # 抽取顺序
            FIELD_MAP = {
                'department': 'outDeptName',
                'ward': 'wardName',
                'attending': 'attendDoctor',
                'branch': 'branch',
                'problems': CASE_LIST_PROBLEM_COUNT,
                'tags': 'tags',
                'receiveTime': 'receiveTime',
                'admitTime': 'admitTime',
                'dischargeTime': 'dischargeTime',
                "group": "medicalGroupName",
            }
            query_filter['sortFields'] = []
            for sf in query_filter["sortField"]:
                if FIELD_MAP.get(sf["field"]):
                    if sf["field"] == 'receiveTime':
                        sort_field = SortField(field=FIELD_MAP.get(sf["field"], sf["field"]), way=sf.get("way", ""),
                                               table='audit_record', extParams=sf.get("extParams"))
                    elif sf["field"] == "problems":
                        sort_field = SortField(field=FIELD_MAP.get(sf["field"])[task.auditType], way=sf.get("way", ""),
                                               extParams=sf.get("extParams"))
                    else:
                        sort_field = SortField(field=FIELD_MAP.get(sf["field"], sf["field"]), way=sf.get("way", ""),
                                               extParams=sf.get("extParams"))
                    query_filter['sortFields'].append(sort_field)
            del query_filter["sortField"]
        if query_filter.get("tag"):
            query_filter["tags"] = [tag for tag in query_filter["tag"].split(',') if tag]
            del query_filter["tag"]
        logging.info("get_run_task_case_req, query_filter: %s", query_filter)
        return GetCaseListRequest(**query_filter)

    def updateTaskNextRunTime(self, task):
        """
        将任务的下次执行时间更新
        :return:
        """
        next_time = task.next_run_time + timedelta(days=task.days)
        with self.app.mysqlConnection.session() as session:
            session.query(SampleTask).filter(SampleTask.id == task.id).update({"next_run_time": next_time}, synchronize_session=False)

class DepartmentSampleApplication(SampleApplication):

    def __init__(self, app):
        super().__init__(app, AUDIT_TYPE_DEPARTMENT)

class HospitalSampleApplication(SampleApplication):

    def __init__(self, app):
        super().__init__(app, AUDIT_TYPE_HOSPITAL)

class FirstpageSampleApplication(SampleApplication):

    def __init__(self, app):
        super().__init__(app, AUDIT_TYPE_FIRSTPAGE)

class ExpertSampleApplication(SampleApplication):

    def __init__(self, app):
        super().__init__(app, AUDIT_TYPE_EXPERT)


from random import choice, randint

from sqlalchemy import Column, Integer, ForeignKey, Date
from sqlalchemy.orm import relationship

import statistics
from model import Base, session
from model.worker_base import FirmName, FirmRating
from settings import get_anno, POSITION_CAP

class Firm(Base):
    session = None
    __tablename__ = 'firms'
    id = Column(Integer, primary_key=True)
    firmname_id = Column(Integer, ForeignKey('firmnames.id'))
    last_rating = Column(Integer)
    open_date = Column(Date)
    close_date = Column(Date)
    ratings = relationship('FirmRating', backref='firms')
    firmname = relationship('FirmName', back_populates="firm_with_name", uselist=False, innerjoin=True)
    recent_emploees = relationship('People', back_populates='recent_firm')
    people = relationship('PeopleFirm', back_populates='firm_conn')

    obj_people = None

    def __init__(self, n):
        self.firmname_id = n
        self.last_rating = 24
        self.open_date = get_anno()
        self.director = None
        self.rating_multiplier = 1.0

    def initial_assign_director(self, director: 'People'):
        self.director = director
        self.new_rating()
        director.migrate(firm_id=self.id)
        director.status.set_status_employed()
        director.migrate_record()
        director.pos.become_director()
        director.change_position_record()

    def assign_new_director(self):
        candidats = [i for i in Firm.obj_people if i.current_firm_id == self.id]
        # Если в фирме не сталось ни одного сотрудника, закрываем её
        if len(candidats) < 1:
            self.close()
            return
        candidats.sort(key = lambda x: 2*x.pos.position + x.talent, reverse=True)
        print('========================')
        print(f'в фриме {self.id} {self.firmname.name} смена руководства')
        print(f'Всего сотрудников в фирме: {len(candidats)}')
        print('Кандидаты на пост директора:')
        for i in candidats:
            print(f'id: {i.id:3d} position:{i.pos.position:3d} talent: {i.talent:3d}')
        self.director = candidats[0]
        print(f'Новый директор: {self.director}')
        self.director.pos.become_director()
        self.director.change_position_record()

    @staticmethod
    def operating_firms_list()->list[int]:
        '''
        возвращает список id фирм, у которых не проставлена дата закрытия, то есть работающих фирм
        '''
        pool = session.query(Firm.id).filter(Firm.close_date.is_(None)).all()
        pool = [i.id for i in pool]
        return pool

    @staticmethod
    def get_rand_firm_id()->int:
        '''
        Возвращает случайный идентификатор работающей(не закрытой) фирмы
        '''
        return choice(Firm.operating_firms_list())

    @staticmethod
    def get_used_firmname_ids_pool()->list[int]:
        '''
        Возвращает список идетнтификаторов имен фирм, которые уже заняты существующими фирмами
        '''
        pool = session.query(FirmName.id).filter(FirmName.used==True).all()
        return pool

    @staticmethod
    def get_unused_firmname_id()->int:
        '''
        Возвращает случайный идентификатор имени фирмы из списка незанятых
        '''
        pool = session.query(FirmName.id).filter(FirmName.used==False).all()
        assert len(pool) > 0, 'нет свободных названий фирм'
        new_id = choice(pool)[0]
        return new_id

    @staticmethod
    def firm_to_migrate_ids(firm_id)->list[int]:
        pool = Firm.operating_firms_list()
        if firm_id in pool:
            pool.remove(firm_id)
        return pool

    @staticmethod
    def mark_firmname_as_used( new_id):
        '''
        В таблицу firmname добавляется отметка, что такое имя фирмы занято после создания новой фирмы
        '''
        session.query(FirmName).filter(FirmName.id == new_id).update({'used':True})

    def update_old(self):
        '''
        В первый день года обновляется рейтинг фирмы
        А так же проверяется, есть ли у фирмы деректор. Если нет, назначается новый
        '''
        if get_anno().day == 1 and get_anno().month in [3, 6, 9, 12]:
            self.update_rating()
        if self.director is None:
            self.assign_new_director()

    def update(self):
        '''
        В первый день года обновляется рейтинг фирмы
        А так же проверяется, есть ли у фирмы деректор. Если нет, назначается новый
        '''
        if self.director is None:
            self.assign_new_director()

    def  new_rating(self)->int:
        '''
        Новое значение рейтинга фирмы генерится случайно
        '''
        self.last_rating = self.director.talent * POSITION_CAP
        session.add(FirmRating(firm_id=self.id, rating=self.last_rating, workers_count=1,rate_date=get_anno()))

    def close(self):
        print(f'Фирма {self.firmname.name} закрылась')
        for i in Firm.obj_people:
            if i.current_firm_id == self.id:
                i.get_unemployed()
        self.close_date = get_anno()

    def update_rating(self):
        '''
        Изменение рейтинга генерится случайно, и делается запись об изменении рейтинга.
        '''
        workers_rating = [i.pos.position*i.talent for i in Firm.obj_people if i.current_firm_id == self.id]
        if self.rating_multiplier > 0:
            self.rating_multiplier *= 0.8
        if self.rating_multiplier < .05:
            self.rating_multiplier = 0
        self.last_rating  = statistics.mean(workers_rating)* (1 + self.rating_multiplier)
        session.add(FirmRating(firm_id=self.id, rating=self.last_rating, rate_date=get_anno()))

    def __repr__(self):
        return f'<id:{self.id} "{self.firmname.name}"  рейтинг: {self.last_rating}>'


from rest_framework import serializers
from api.models import *

def update_instance(instance, validated_data):
	"""Update all the instance's fields specified in the validated_data"""
	for key, value in validated_data.items():
		setattr(instance, key, value)
	return instance.save()

class AddressSerializer(serializers.ModelSerializer):
	class Meta:
		model = Address
		fields = ['person', 'country','state', 'city', 'street', 'postal_code', 'complement']
		read_only_fields = ('person', )

class PersonSerializer(serializers.ModelSerializer):
	address = AddressSerializer()

	class Meta:
		model = Person
		fields = ['first_name', 'last_name', 'date_of_birth', 'email', 'address']

	def create(self, validated_data):
		address_data = validated_data.pop('address')
		person = Person.objects.create(**validated_data)
		address = Address.objects.create(person=person, **address_data)

		return person

class EnrollSerializer(serializers.ModelSerializer):
	enrolled_at = serializers.DateTimeField(format="%d-%m-%Y %H:%M:%S", read_only=True)

	class Meta:
		model = Enroll
		fields = ['course', 'student', 'enrolled_at']

class StudentSerializer(serializers.ModelSerializer):
	person = PersonSerializer()
	courses_enrolled = EnrollSerializer(many=True, read_only=True)
	courses_enrolled_count = serializers.SerializerMethodField()

	class Meta:
		model = Student
		fields = ['id', 'person', 'courses_enrolled_count', 'courses_enrolled']

	def create(self, validated_data):
		person_data = validated_data.pop('person')
		person = PersonSerializer(data=person_data)

		if person.is_valid():
			person_inst = person.save()

		student = Student.objects.create(person=person_inst)
		return student

	def update(self, instance, validated_data):
		"""
		Update method: an expansable method so that any new Student/Person/Address field will be updated
		Reused in `ProfessorSerializer` class
		"""
		person_data = validated_data.pop('person')
		address_data = person_data.pop('address')

		update_instance(instance, validated_data)
		update_instance(instance.person, person_data)
		update_instance(instance.person.address, address_data)

		return instance

	def get_courses_enrolled_count(self, obj):
		return obj.courses_enrolled_count()

class CourseSerializer(serializers.ModelSerializer):
	course_instances = EnrollSerializer(many=True, read_only=True)
	students_count = serializers.SerializerMethodField()

	class Meta:
		model = Course
		fields = ['id', 'name', 'description', 'professor', 'students_count', 'course_instances']

	def get_students_count(self, obj):
		return obj.students_count()

class ProfessorSerializer(StudentSerializer):
	"""PersonSerializer: inherits the `.update()` method and the `person` variable from StudentSerializer"""
	courses_taught = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
	courses_taught_count = serializers.SerializerMethodField()

	class Meta:
		model = Professor
		fields = ['id', 'person', 'salary', 'entry_year', 'courses_taught_count', 'courses_taught']

	def create(self, validated_data):
		person_data = validated_data.pop('person')
		person = PersonSerializer(data=person_data)

		if person.is_valid():
			person_inst = person.save()

		professor = Professor.objects.create(person=person_inst, **validated_data)
		return professor

	def get_courses_taught_count(self, obj):
		return obj.courses_taught_count()


"""
URL configuration for EMS project.

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.2/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.urls import path
from ems_app import views as v

urlpatterns = [
    path('', v.empList, name='list-emp'),
    path('create-emp/', v.createEmp, name='create-emp'),
    path('del-emp/<int:id>/', v.delEmp, name='del-emp'),
    path('update-emp/<int:id>/', v.updateEmp, name='update-emp'),
    path('contact/', v.contact, name='contact'),
]


import asyncio
import requests
async def request():
    url='https://www.baidu.com'
    status=requests.get(url)
    return status
def callback(task):
    print(task.result())

task=asyncio.ensure_future(request())
task.add_done_callback(callback)
print(task)
print(1)
loop=asyncio.get_event_loop()
print(2)
loop.run_until_complete(task)
print(task)


# -*- coding: utf-8 -*-
"""Base UDP Multicast.
Relaying only on pure Python socket API
"""

__author__ = 'douglasvinter'
__version__ = '0.1'

import socket
import struct
import select
import netifaces
from logging import getLogger
from collections import namedtuple

# udp_pkg used to return datagram status
# Class-like declaration
UdpPackage = namedtuple('udp_pkg', ('data', 'host', 'port'))

class ProtocolError(Exception):
    """ Exception base class for datagram network errors

    Args:
        msg (str): Human readable string describing the exception.

    Attributes:
        msg (str): Human readable string describing the exception.
    """

    def __init__(self, msg):
        super(ProtocolError, self).__init__(msg)

class MulticastException(ProtocolError):
    """ Exception subclass for multicast error"""
    pass

class UnicastException(ProtocolError):
    """ Exception subclass for unicast error"""
    pass

class JoinGroupError(ProtocolError):
    """ Exception subclass for join group operation"""
    pass

class NetworkConfigurationError(ProtocolError):
    """ Exception subclass for network configuration errors"""
    pass

class SocketSelector(object):
    """"""

    # select.select timeout
    SOCKET_TIMEOUT = 0.1
    _instance = None
    sockets = []

    def __new__(cls, *args, **kwargs):
        """"""
        if cls._instance is None:
            cls._instance = super(SocketSelector, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    @staticmethod
    def add_handler(klaas):
        if klaas is not None:
            SocketSelector.sockets.append(klaas)

    @staticmethod
    def get_instance():
        """Gets class instance."""
        if not SocketSelector._instance:
            SocketSelector._instance = SocketSelector()
        return SocketSelector._instance

    @staticmethod
    def select_all():
        """Simple I/O selector

        Returns:
            List of ready sockets to be read
        """

        sockets = []
        socks_ready = []
        for cls in SocketSelector.get_instance().sockets:
            sockets.append(cls.transport)
        try:
            socks_ready, _, _ = select.select(sockets, [], [], SocketSelector.SOCKET_TIMEOUT)
        except (socket.error, TypeError):
            pass
        return socks_ready

    @staticmethod
    def select_protocol(protocol):
        """Simple I/O selector

        Args:
            :param protocol: Protocol name to hook up on sub classes

        Returns:
            List of ready sockets to be read
        """

        sockets = []
        socks_ready = []
        for cls in SocketSelector.get_instance().sockets:
            if cls.implemented_protocol == protocol:
                sockets.append(cls.transport)
        try:
            socks_ready, _, _ = select.select(sockets, [], [], SocketSelector.SOCKET_TIMEOUT)
        except (socket.error, TypeError):
            pass
        return socks_ready

class DatagramSocket(object):
    """A pure python Class for Networking datagram packages

    This class was based in some extent of Twisted networking mechanism but much simpler.
    It basically provides the bases of multicast enabling you to join into IGMP groups.

    You can also perform unicast using this class, you have just to avoid listening and binding
    it in the same address you wish to use your protocols.

    Note:
        If you're thinking on use this class to bind into multiple IGMP groups you've joined,
        feel free to, but check your max_memberships flag first.
        (Linux - /proc/sys/net/ipv4/igmp_max_memberships)
    """
    # Public constants
    CLIENT = 0x554e4943415354
    SERVER = 0x4d554c544943415354

    def __init__(self, socket_type, implemented_protocol, logger_name, group, port, ttl=None, recv_size=1024):
        """DatagramSocket constructor

        Args:
            :param socket_type: unicast or multicast constant value
            :param implemented_protocol: Protocol name that you're implementing
            :param logger_name: Valid logger name.
            :param group: multicast address.
            :param port: multicast port.
            :param ttl: time to live, datagram package hops.
            :param recv_size: size in bytes to be received.
                Max UDP package is 64Kb = 65536
        Note:
            Please make sure to chose the correct socket_type:
                - If you want a MUSTICAST litener ONLY, chose the socket type to be SERVER.
                - If you want a socket to send MULTICAST and UNICAST but not listening, chose CLIENT.
        """
        assert (255 >= ttl >= 1 or ttl is None), "TTL of {} is invalid".format(ttl)
        assert (65536 >= recv_size >= 8), "Receive size of {} is invalid".format(recv_size)
        self.__socket_type = socket_type
        self.implemented_protocol = implemented_protocol
        self.logging = getLogger(logger_name)
        self.group = group
        self.port = port
        self.sock_ttl = ttl or 1
        self.recv_size = recv_size
        self.transport = None
        self._build_socket()
        SocketSelector.add_handler(self)

    def _build_socket(self):
        """Builds the socket accordly to its type

        Note:
            You're still free to call another methods if needed
        """
        if self.__socket_type == DatagramSocket.CLIENT:
            self.build_protocol()
        elif self.__socket_type == DatagramSocket.SERVER:
            self.build_protocol()
            self.join_group()
            self.listen()
        else:
            raise ProtocolError("Unkown protocol type")

    def build_protocol(self):
        """Builds UDP protocol supporting the bases of multicast

        Note:
            If you set a TTL larger than 4 and cannot listen/forward
            packages to another subnet, check your LAN settings.
        """
        # Avoid error on class re-use for new connections or dead connections
        if isinstance(self.transport, socket.socket):
            raise MulticastException("A protocol is already defined, you need to destroy it first")
        self.transport = socket.socket(socket.AF_INET, socket.SOCK_DGRAM,
                                       socket.IPPROTO_UDP)
        self.transport.settimeout(1)
        # NOTE: Set the TTL according to the protocol you're implementing
        # Check RFC/Protocol documentation before setting a HUGE TTL,
        # Some routers/switch may decrease the hops.
        self.transport.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL,
                                  self.sock_ttl)
        try:
            self.transport.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        except AttributeError:
            self.logging.warning('Re-use address is not supported')

    def join_group(self):
        """Joins the target multicast group

        Note:
            We're using INADDR_ANY
        """
        if not isinstance(self.transport, socket.socket):
            raise MulticastException("Build a protocol before call join group method")
        try:
            host = struct.pack('4sl', socket.inet_aton(self.group), socket.INADDR_ANY)
            self.transport.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.INADDR_ANY)
            self.transport.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, host)
        except (socket.error, AttributeError, TypeError, NetworkConfigurationError) as error:
            error_msg = 'Could not join multicast group {}:{} \n{}' \
                .format(self.group, self.port, error)
            self.logging.error(error_msg)
            # Force file descriptor closure
            self.destroy()
            raise JoinGroupError(error_msg)

    def send_multicast(self, msg):
        """Multicast a message over the group.

        Args:
            :param msg - String containing udp message to be sent.

        Raises:
            MulticastException - Socket level errors for multicasting

        """
        if not isinstance(self.transport, socket.socket):
            raise MulticastException("Cant send, not connected")
        if len(msg) > 0:
            self.logging.debug('Sending data for target {}:{}:\n{}'
                               .format(self.group, self.port, msg))
            try:
                self.transport.sendto(msg, (self.group, self.port))
            except (socket.error, AttributeError) as mcast_error:
                error_msg = 'Error while sending multicast, reason:{}' \
                    .format(mcast_error)
                self.logging.error(error_msg)
                # Force file descriptor closure
                self.destroy()
                raise MulticastException(error_msg)

    def send_unicast(self, msg, *address):
        """Unicast sender
        Args:
            :param msg: message to be sent
            :param address: ip and port target
        Raises:
            UnicastException - Socket level errors for multicasting
        """
        if not isinstance(self.transport, socket.socket) and len(msg) > 0:
            raise UnicastException("Cant send, not connected")
        try:
            self.transport.sendto(msg, address)
            self.logging.debug('Send to {}:{} data: \n{}'.format(address[0], address[1], msg))
        except (socket.error, AttributeError) as mcast_error:
            error_msg = 'Error while sending unicast, reason:{}' \
                .format(mcast_error)
            self.logging.error(error_msg)
            # Force file descriptor closure
            self.destroy()
            raise UnicastException(error_msg)

    def listen(self):
        """Bind socket to start listen the multicast group

        Raises:
            MulticastException - Protocol not created
        """
        if not isinstance(self.transport, socket.socket):
            raise MulticastException("A protocol is not defined, cannot bind")
        # Using INADDR_ANY
        self.transport.bind(('0.0.0.0', self.port))

    def recv_dgram(self):
        """Receives a datagram, if any available.

        Returns:
            UdpPackage: A class-like object built on top of namedtuple (read-only)
            Attributes:
                data - Returned data from package (empty if time-out)
                host - sender host
                port - sender port
        """
        data = host = port = ''

        if not isinstance(self.transport, socket.socket):
            raise MulticastException("Cannot recv, not connected")

        try:
            data, (host, port) = self.transport.recvfrom(self.recv_size)
        except socket.timeout as mcast_time_out:
            data = '{}'.format(mcast_time_out)
        except (socket.error, AttributeError) as mcast_error:
            # We won't close the socket file descriptor
            # as we're working with time-out UDP multicast sockets
            error_msg = 'Error receiving socket data: {}' \
                .format(mcast_error)
            self.logging.error(error_msg)
            # Force file descriptor closure
            self.destroy()
            raise UnicastException(error_msg)
        self.logging.debug('Received MCAST:\n\n******* PACKAGE DATA *******\n\n{}\n******* END OF PACKAGE DATA *******\nFROM: {}:{}\n'
                           .format(data, host, port))
        return UdpPackage(data, host, port)

    def destroy(self):
        """Performs graceful shut-down on socket.

        shuts-down both read/write on the file descriptor.
        """
        self.logging.debug('Closing RDWR for socket')
        try:
            self.transport.shutdown(socket.SHUT_RDWR)
        except (socket.error, AttributeError):
            pass
        self.transport = None

def get_host_address(network_interface=None):
    """Gets your active IP Address"""
    try:
        if network_interface not in netifaces.interfaces():
            network_interface = netifaces.gateways()['default'][netifaces.AF_INET][1]
        address = netifaces.ifaddresses(network_interface)[netifaces.AF_INET][0]['addr']
    except (ValueError, KeyError):
        raise NetworkConfigurationError("There's a problem on your network configuration, operation cannot proceed")
    return address


import matplotlib

# matplotlib.use('TkAgg')
matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42
import matplotlib.pyplot as plt
import csv
import os

print(matplotlib.get_backend())

# plt.interactive(True)
# http://ksrowell.com/blog-visualizing-data/2012/02/02/optimal-colors-for-graphs/
MY_BLUE = (56, 106, 177)
MY_RED = (204, 37, 41)
MY_ORANGE = (218, 124, 48)
MY_GREEN = (62, 150, 81)
MY_BLACK = (83, 81, 84)
MY_GOLD = (148, 139, 61)

def get_color(COLOR_TUPLE_255):
    return [x / 255 for x in COLOR_TUPLE_255]

# fontsize=20
fontsize = 30
legend_size = 30
title_size = 30
font = {'size': fontsize}
matplotlib.rc('font', **font)

dir_path = os.path.dirname(os.path.realpath(__file__))
print("dir path: ", dir_path)

GPU_MEM_SIZE = 16280

def read_columns(dataset, columns=5):
    file_name = dir_path + "/" + dataset + ".csv"
    with open(file_name) as csvfile:
        data = csv.reader(csvfile, delimiter=",", quotechar='|')
        cols = []
        for column in range(columns):
            cols.append([])

        for i, row in enumerate(data):
            if i > 0:  # skip header
                for column in range(columns):
                    cols[column].append(float(row[column]))
    return cols

ylabel = "ylabel"
xlabel = "xlabel"
title = "title"
legend_pos = "center_pos"
bbox = "bbox"
file_name = "file_name"
column_nr = "column_nr"
labels = "labels"
legend_cols = "legend_cols"
ylim = "ylim"
xlim = "xlim"

cifar_compress = {ylabel: "Accuracy (%)",
                  xlabel: "Compression rate (%)",
                  file_name: "cifar-compress",
                  title: "accuracy",
                  legend_pos: "upper left",
                  bbox: (0.0, 1.05),
                  column_nr: 4,
                  legend_cols: 3,
                  labels: ["", "FC", 'CD', "SVD"],
                  xlim: (0, 90),
                  ylim: (30, 100),
                  title: "CIFAR-10"}

cifar_noise = {ylabel: "Accuracy (%)",
               xlabel: "Epsilon (strength of the noise)",
               file_name: "cifar-noisy",
               title: "accuracy",
               legend_pos: "upper left",
               bbox: (0.0, 1.05),
               column_nr: 4,
               legend_cols: 3,
               labels: ["", "Gauss", "Uniform", "Laplace"],
               xlim: (0, 0.1),
               ylim: (30, 100),
               title: "CIFAR-10"}

imagenet_compress = {ylabel: "Accuracy (%)",
                  xlabel: "Compression rate (%)",
                  file_name: "imagenet-compress",
                  title: "accuracy",
                  legend_pos: "upper left",
                  bbox: (0.0, 1.05),
                  column_nr: 4,
                  legend_cols: 3,
                  labels: ["", "FC", 'CD', "SVD"],
                  xlim: (0, 90),
                  ylim: (0, 90),
                  title: "ImageNet"}

imagenet_noise = {ylabel: "Accuracy (%)",
               xlabel: "Epsilon (strength of the noise)",
               file_name: "imagenet-noisy",
               title: "accuracy",
               legend_pos: "upper left",
               bbox: (0.0, 1.05),
               column_nr: 4,
               legend_cols: 3,
               labels: ["", "Gauss", "Uniform", "Laplace"],
               xlim: (0, 0.1),
               ylim: (0, 90),
               title: "ImageNet"}

colors = [get_color(color) for color in
          ["", MY_GREEN, MY_BLUE, MY_ORANGE, MY_RED, MY_BLACK, MY_GOLD]]
markers = ["+", "o", "v", "s", "D", "^", "+"]
linestyles = ["", "-", "--", ":", "-", "--", ":", "-"]

datasets = [cifar_compress, cifar_noise, imagenet_compress, imagenet_noise]

# width = 12
# height = 5
# lw = 3

width = 30
height = 7
lw = 4

fig = plt.figure(figsize=(width, len(datasets) * height))

for j, dataset in enumerate(datasets):
    plt.subplot(len(datasets) // 2, 2, j + 1)
    print("dataset: ", dataset)
    columns = dataset[column_nr]
    cols = read_columns(dataset[file_name], columns=columns)

    print("col 0: ", cols[0])
    print("col 1: ", cols[1])

    for i in range(columns):
        if i > 0:  # skip first column with the epoch number
            plt.plot(cols[0], cols[i], label=f"{dataset[labels][i]}", lw=lw,
                     color=colors[i], linestyle=linestyles[i],
                     marker=markers[i], markersize=15)

    plt.grid()
    plt.legend(loc=dataset[legend_pos], ncol=dataset[legend_cols],
               frameon=False,
               prop={'size': legend_size},
               # bbox_to_anchor=dataset[bbox]
               )
    plt.xlabel(dataset[xlabel])
    plt.title(dataset[title], fontsize=title_size)
    plt.ylabel(dataset[ylabel])
    plt.ylim(dataset[ylim])
    # plt.xscale('log', basex=2)
    plt.xlim(dataset[xlim])

# plt.gcf().autofmt_xdate()
# plt.xticks(rotation=0)
# plt.interactive(False)
# plt.imshow()
plt.subplots_adjust(hspace=0.3)
format = "pdf"  # "pdf" or "png"
destination = dir_path + "/" + "noisyChannelsMaxAccuracy." + format
print("destination: ", destination)
fig.savefig(destination,
            bbox_inches='tight',
            # transparent=True
            )
# plt.show(block=False)
# plt.interactive(False)
plt.close()


from django.shortcuts import render
from django.http import HttpResponse, Http404, JsonResponse

def index(request):
    if 'course' in request.GET and 'coursecurrency' in request.GET and 'input' in request.GET and 'from' in request.GET\
            and 'to' in request.GET:
        course = float(request.GET['course'])
        courseCurrency = request.GET['coursecurrency']
        inputConverter = float(request.GET['input'])
        fromConverter = request.GET['from']
        toConverter = request.GET['to']

        if fromConverter == courseCurrency:
            result = {'result': str(inputConverter/course)}

        elif toConverter == courseCurrency:
            result = {'result': str(inputConverter*course)}
        else:
            result = {'result': 'error'}

    else:
        result = {'result': 'error'}

    return JsonResponse(result)

# Create your views here.


from flask import Flask, request, render_template, flash, redirect, session, jsonify
from flask_debugtoolbar import DebugToolbarExtension
from boggle import Boggle

boggle_game = Boggle()
app = Flask(__name__, static_folder='./static')
app.config['SECRET_KEY'] = "nichen"
debug = DebugToolbarExtension(app)
high_score = 0
times_played = 0

@app.route('/')
def homepage():
    session['board'] = boggle_game.make_board()
    session.setdefault('times_played', 0)
    session.setdefault('high_score', 0)
    return render_template("index.html", board=session['board'])

@app.route('/guess', methods=["POST"])
def guess():
    data = request.json
    guess = data['guess']
    result = boggle_game.check_valid_word(session['board'],guess)
    return jsonify({"result":result})

@app.route('/update-score', methods=["POST"])
def update_score():
    data = request.json
    score = data['score']
    if score > session['high_score']:
        session['high_score'] = score
    session['times_played'] += 1
    return jsonify({
        "high_score": session['high_score'],
        "times_played": session['times_played']
    })