from khl import Bot,Message
import json
import logging
import random
import split
import playerInfo
from check import check

with open('config.json','r',encoding='utf8') as f:
    config = json.loads(f.read())

max_su = 5
max_fu = 5

bot = Bot(token=config['token'])

#角色卡dict
playerDict = playerInfo.readInfo()

#用户绑定角色dict
userPc = {}

#检定函数模式
checkmode = 1

def updatePlayerInfo(dict):
    playerInfo.input(dict)

#切换检定函数模式
@bot.command(name="setmode")
async def main(msg: Message, num: str):
    try:
        chat = int(num)
        str1 = ''

        if chat == 1:
            str1 = "已切换房规至：模式1\n1~5为大成功，96~100为大失败"
        elif chat == 2:
            str1 = "已切换房规至：模式2\n1为大成功，100为大失败"
        else:
            raise Exception("输入格式有误，仅可输入1或2切换房规")
        checkmode = chat
        await msg.reply(str1)
    except Exception as e:
        await msg.reply(str(e))

@bot.command(name="getmode")
async def main(msg:Message):
    str1 = ''
    try:
        chat = checkmode
        if(chat == 1):
            str1 = "当前房规为：模式"+str(chat)+"\n1~5为大成功，96~100为大失败"
        else:
            str1 = "当前房规为：模式"+str(chat)+"\n1为大成功，100为大失败"
    except Exception as e:
        await msg.reply("格式有误,检查输入格式")
        print(e)

@bot.command(name="r")
async def main(msg: Message, chat: str = ''):
    try:
        input_text = msg.content
        player = msg.author_id
        input_split = split.strSplit(input_text)
        print(input_split)

        if len(input_split) == 2 and input_split[0] == '/' and input_split[1] == 'r' and 'd' not in input_split:
            print("s1")
            num_rolls = 1
            die_sides = 100
        elif len(input_split) == 4 and input_split[0] == '/' and input_split[1] == 'r' and input_split[2] == 'd':
            print("s2")
            num_rolls = 1
            die_sides = int(input_split[3])
        elif 'd' in input_split:
            print("s3")
            d_index = input_split.index('d')

            if input_split[d_index - 1].isdigit():
                print("p1")
                num_rolls = int(input_split[d_index - 1])
                die_sides = int(input_split[d_index + 1])
            else:
                raise ValueError("格式有误，请检查输入格式1")
        else:
            raise ValueError("格式有误，请检查输入格式2")

        rolls = [random.randint(1, die_sides) for _ in range(num_rolls)]
        roll_str = ','.join(map(str, rolls))
        total_sum = sum(rolls)
        await msg.reply(f"掷出了{num_rolls}个D{die_sides}={total_sum}({roll_str})")
    except Exception as e:
        await msg.reply(str(e))

@bot.command(name="ra")
async def main(msg:Message,chat:str):
    try:
        input = msg.content
        player = msg.author_id
        #取得/ra 后描述的技能名称
        skill = playerDict[player][chat]
        print(skill)
        d = random.randint(1,100)
        str1 = check(d,int(skill),checkmode)
        await msg.reply("投掷出了D100="+str(d)+",结果为："+str1)
    except Exception as e:
        print(e)
        await msg.reply("格式有误,检查输入格式")

#pc命令：角色卡相关内容
@bot.command(name="pc")
async def main(msg:Message,command1:str,command2:str=''):
    try:
        player = msg.author_id
        playerDict = playerInfo.readInfo()

        #用户第一次使用时创建数据
        if player not in playerDict:
            print("第一次")
            tempDict = {}
            tempDict[player] = {}
            playerInfo.input(tempDict)

        #new
        if(command1 == "new"):
            if(command2 == ''):
                msg.reply("角色名不能为空！")
            else:
                pc = {}
                pc[command2]={}
                playerInfo.inputPlayerInfo(player,pc)
                await msg.reply("创建角色：“"+command2+"”成功!")
        elif(command1 == "tag"):
            if command2 in playerDict[player]:
                userPc[player]=command2
                await msg.reply("绑定角色“"+command2+"”成功!")
            else:
                await msg.reply("绑定角色失败,角色不存在!")
        elif(command1 == "list"):
            tempStr = "角色列表：\n"
            for key in playerDict[player].keys():
                tempStr += key
                try:
                    if(key == userPc[player]):
                        tempStr +="[当前角色]"
                except:
                    tempStr +="[未绑定]"
                    print("list命令出错")
                tempStr += " "
            await msg.reply(tempStr)
            print(key)

    except Exception as e:
        print(e)
        await msg.reply("操作失败!")

#st命令：录入属性
@bot.command(name="st")
async def main(msg:Message,chat:str):
    #每次录卡更新预读取字典
    playerDict = playerInfo.readInfo()
    try:
        input = msg.content
        player = msg.author_id
        #查询功能
        if(chat == "info"):
            replyChat = ''
            for key,value in playerDict[player][userPc].items():
                replyChat += key + ":" + value + "\n"
            await msg.reply(replyChat)
        #录卡
        else:
            #读入属性
            tempList = split.strSplit(input)
            print(tempList)
            #内容不成对则格式错误
            if(len(tempList)%2!=0):
                raise Exception
            else:
                pc = userPc[player]
                print(playerDict,player,userPc)
                playerInfo.getStDict(playerDict,player,pc,tempList)
                playerInfo.input(playerDict)
                await msg.reply("属性写入成功!")

    except Exception as e:
        print(e)
        await msg.reply("格式有误,检查输入格式")

logging.basicConfig(level='INFO')

bot.run()


import time
import math
import numpy as np
import torch
from torch import nn, optim
import torch.nn.functional as F
import d2lzh_pytorch as d2l

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

## Read data.
(corpus_indices, char_to_idx, idx_to_char, vocab_size) = d2l.load_data_jay_lyrics()

## Init model params.
num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
print("PyTorch will use", device)

def get_params():
    def _one(shape):
        ts = torch.tensor(np.random.normal(0, 0.01, size=shape),
                          device=device, dtype=torch.float32)
        return torch.nn.Parameter(ts, requires_grad=True)

    ## Hidden layer params
    W_xh = _one((num_inputs, num_hiddens))
    W_hh = _one((num_hiddens, num_hiddens))
    b_h = torch.nn.Parameter(torch.zeros(num_hiddens, device=device, requires_grad=True))
    ## Output layer params
    W_hq = _one((num_hiddens, num_outputs))
    b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, requires_grad=True))
    return nn.ParameterList([W_xh, W_hh, b_h, W_hq, b_q])

## Define model.
def init_rnn_state(batch_size, num_hiddens, device):
    return ( torch.zeros((batch_size, num_hiddens), device=device), )

def rnn(inputs, state, params):
    W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    ## H = \phi(XW_xh + HW_hh + b_h)
    ## Y = HW_hq + b_q
    for X in inputs:
        H = torch.tanh(torch.matmul(X, W_xh) + torch.matmul(H, W_hh) + b_h)
        Y = torch.matmul(H, W_hq) + b_q
        outputs.append(Y)
    return outputs, (H, )

params = get_params()

num_epochs, num_steps, batch_size, lr, clipping_theta = 250, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 50, 50, ['分开', '不分开']

d2l.train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,
                          vocab_size, device, corpus_indices, idx_to_char,
                          char_to_idx, False, num_epochs, num_steps, lr,
                          clipping_theta, batch_size, pred_period, pred_len,
                          prefixes)


import unittest
from src.core import Request, BuffStream, BaseStream, DummyMetadata
from src.io import CsvOutput
import json
import time
from pathlib import Path

async def pprint(session, url, headers, timeout):
    async with session.get(url, headers=headers, timeout=timeout) as response:
        if response.status == 200:
            r = await response.json()
            r = json.loads(r)
            return CsvOutput(r, url, basepath=Path('tmp'))
        else:
            return CsvOutput([], url, basepath=Path('tmp'))

class TestBuffStream(unittest.TestCase):

    def test_request(self):
        buff = BuffStream(stream=BaseStream(["http://localhost:8080/1", "http://localhost:8080/2",
                                             "http://localhost:8080/3"]))
        #start = time.time()
        #request = Request(buff=buff, metadata=DummyMetadata(Path('tmp')))
        #output = request.output(request.get(callback=pprint), sep='|', header=False)
        #tasks = request.run(output)
        #end = time.time()
        #print(tasks, end-start)

    def test_badresponse(self):
        buff = BuffStream(stream=BaseStream(["http://localhost:8080/4"]))
        request = Request(buff=buff, metadata=DummyMetadata(Path('tmp')))
        output = request.output(request.get(callback=pprint))
        tasks = request.run(output)

    def test_longresponse(self):
        buff = BuffStream(stream=BaseStream(["http://localhost:8080/long"]))
        request = Request(buff=buff, metadata=DummyMetadata(Path('tmp')))
        output = request.output(request.get(callback=pprint, timeout=1))
        tasks = request.run(output)

if __name__ == '__main__':
    unittest.main()


import math
import rospy
import mapHelper as mh
import time
import cv2
import os
from timeit import default_timer as timer

def FindSmallest(arr1):
    index = [0][0]
    minn = arr1[0][0]

    for i in range(len(arr1)):
        for j in range(len(arr1[i])):
            if arr1[i][j] < minn:
                minn = arr1[i][j]
                index[0] = i
                index[1] = j
    return index

def FindBiggest(arr1):
    index = [0, 0]
    maxi = arr1[0][0]

    for i in range(len(arr1)):
        for j in range(len(arr1[i])):
            if arr1[i][j] > maxi:
                maxi = arr1[i][j]
                index[0] = i
                index[1] = j
    return index

def distan(x1, y1, x2, y2):  # Compute distance between points
    dist = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
    return dist

def createBids(robots, tasks, method,bmap=[],smap=[],currentTimeStump=0,tras=None):  # To do
    bids = []
    if method=='Euc':
        for robot in robots:
            rbids = []
            for task in tasks:
                bid = computeBid(robot, task, method,bmap,smap)
                rbids.append(bid)
            bids.append(rbids)
        return bids
    elif method=='Path':
        trajectories=[]
        for i,robot in enumerate(robots):
            rbids = []
            rtra=[]
            for j,task in enumerate(tasks):
                if tras is None:
                    bid,tra = computeBid(robot, task, method,bmap,smap,currentTimeStump)
                else:
                    bid,tra = computeBid(robot, task, method,bmap,smap,currentTimeStump,tras[i][j])
                rbids.append(bid)
                rtra.append(tra)
            bids.append(rbids)
            trajectories.append(rtra)
        return bids,trajectories

    else:
        trajectories=[]
        for i,robot in enumerate(robots):
            rbids = []
            rtra=[]
            for j,task in enumerate(tasks):
                if tras is None:
                    bid,tra,costArray = computeBid(robot, task, method,bmap,smap,currentTimeStump)
                else:
                    bid,tra,costArray = computeBid(robot, task, method,bmap,smap,currentTimeStump,tras[i][j])
                rbids.append(bid)
                rtra.append(tra)
            bids.append(rbids)
            trajectories.append(rtra)
        return bids,trajectories,costArray

def saveMethod(method,t):
    cwd = os.getcwd()
    dir = cwd + '/'+method+'AllTimes'
    os.system('mkdir '+ dir)
    text=str(t)

    files = os.listdir(dir)
    n = len(files)

    dir=dir+'/a'+str(n)+'.txt'
    f = open(dir, "a")
    f.write(text)
    f.close()

def computeBid(robot, task, method,bmap=[],smap=[],currentTimeStump=0,tra = None):

    if method=='Euc':
        startTime = timer()
        bid =  distan(robot.x, robot.y, task[0], task[1])
        endTime = timer()
        #saveMethod(method,endTime-startTime)
        return bid
    elif method=='Path':
        if tra is None:
            tra = mh.globalPlanner(robot.x, robot.y, 0.5 * math.pi - robot.direction, task[0], task[1], 0, bmap.info, smap)
        startTime = timer()
        bid=0
        for i in range(len(tra)-1):
            bid = bid+distan(tra[i][0],tra[i][1],tra[i+1][0],tra[i+1][1])
        endTime = timer()
        #saveMethod(method,endTime-startTime)
        return bid,tra
    elif method=='Novel':
        if tra is None:
            tra = mh.globalPlanner(robot.x, robot.y, 0.5 * math.pi - robot.direction, task[0], task[1], 0, bmap.info, smap)
        startTime = timer()
        costArray=[]
        bid=0
        path = os.getcwd() +'/predicted_binary_img2'
        r = currentTimeStump%600
        t=currentTimeStump-r
        #r = currentTimeStump%1800
        #t=currentTimeStump-r+334
        name = str(time.ctime(t+28800+3600 ))+".png"
        #print(name)
    #print(name)
    #print(bid)
        img=cv2.imread(path+'/'+name,0)
        for i in range(len(tra)-1):
            punish,pro1,pro2 = probabilityParmameter(tra[i],tra[i+1],img,bmap.info,bid)
            dista=distan(tra[i][0],tra[i][1],tra[i+1][0],tra[i+1][1])
            bid = bid+dista*punish
            costa = [dista,(pro1+pro2)/2]
            costArray.append(costa)
        endTime = timer()
        #saveMethod(method,endTime-startTime)
        return bid,tra,costArray

def probabilityParmameter(point1,point2,img,mapinfo,bid): #TO DO
    #print(currentTimeStump)
    w5=[9.29980536, 0.02222327, 1.00558889]
    #path = os.getcwd() +'/predicted_binary_img2'
    #r = currentTimeStump%600
    #t=currentTimeStump-r
    #r = currentTimeStump%600
    #t=currentTimeStump-r
    #name = str(time.ctime(t+28800+3600 ))+".png"
    #print(name)
    #print(bid)
    #img=cv2.imread(path+'/'+name,0)
    y,x=mh.from_real_point_to_index(point1[0], point1[1], mapinfo)
    x=650-x
    pro1=math.ceil(float(img[x][y])*100/255)
    #print(pro1)
    y,x=mh.from_real_point_to_index(point2[0], point2[1], mapinfo)
    x=650-x
    pro2=math.ceil(float(img[x][y])*100/255)
    #print(pro2)
    #input('222')
    probability = (pro1+pro2)/200
    panish = w5[2]+w5[1] * ((math.exp(probability * w5[0])))
    #if probability>0.19:
    #    print('---------')
    #    print(probability)
     #   print(panish)
    return panish,pro1,pro2

def auction(bids):
    tl = len(bids[0])
    index = 0
    out = [-1] * tl
    while True:
        flag = False
        copyOfVotes = crossOut(bids, out)
        while True:
            i = FindBiggest(copyOfVotes)
            if nonZeroElementsCol(copyOfVotes, i[1]) == 1:
                index = FindBiggestCol(copyOfVotes, i[1])
                out[i[1]] = index
                break
            if nonZeroElementsRow(copyOfVotes, i[0]) == 1:
                index = FindBiggestRow(copyOfVotes, i[0])
                out[index] = i[0]
                break

            copyOfVotes[i[0]][i[1]] = 0

        if (contains(out, -1) == 0):
            break
        # for i in range(len(out)):
        # if out[i] == -1:
        #   bids[index][i] = computeBid(robots[index], tasks[i], method)
    return out

def FindBiggestCol(arr1, col):
    index = 0
    maxd = arr1[index][col]
    for j in range(len(arr1)):
        if (arr1[j][col] > maxd):
            maxd = arr1[j][col]
            index = j

    return index

def FindBiggestRow(arr1, row):
    index = 0
    maxd = arr1[row][0]
    for j in range(len(arr1)):
        if (arr1[row][j] > maxd):
            maxd = arr1[row][j]
            index = j

    return index

def contains(array, v):
    result = 0
    for i in array:
        if i == v:
            result = result + 1
    return result

def nonZeroElementsCol(votes, index):
    result = 0
    for i in range(len(votes)):
        if votes[i][index] != 0:
            result = result + 1
    return result

def nonZeroElementsRow(votes, index):
    result = 0
    for i in range(len(votes)):
        if votes[index][i] != 0:
            result = result + 1
    return result

def crossOut(bids, outd):
    cross = [[bids[x][y] for y in range(len(bids[0]))] for x in range(len(bids))]
    for i in range(len(bids)):
        for j in range(len(bids[i])):
            if (outd[j] != -1):
                cross[i][j] = 0
                cross[outd[j]][i] = 0
    return cross


# -*- coding: utf-8 -*-
import json
import os
import sys

def analyze(name):
	directory = sys.argv[1]
	with open(os.path.join(directory, f'{name}_signal.csv'), 'r') as signal_fp:
		with open(os.path.join(directory, f'{name}.json'), 'r') as iperf_fp:
			iperf_data = json.load(iperf_fp)
			total_time = iperf_data['end']['sum_sent']['end']
			signal_fp.readline()
			signal_data = [tuple(float(value) for value in line.split(',')) for line in signal_fp.readlines()]
			last_signal_time = signal_data[-1][0]
			time_compensation = total_time - last_signal_time
			signal_data = [(line[0] + time_compensation,) + line[1:] for line in signal_data]
			with open(os.path.join(directory, f'{name}_analyze.csv'), 'w') as analyze_fp:
				analyze_fp.write('time,speed,line,level\n')
				for interval in iperf_data['intervals']:
					interval = interval['sum']
					interval_signal_data = [line for line in signal_data if line[0] >= interval['start'] and line[0] <= interval['end']]
					time = interval['start']
					speed = interval['bits_per_second'] / 1024**2
					line_quality = sum(line[1] for line in interval_signal_data) / len(interval_signal_data)
					link_level = sum(line[2] for line in interval_signal_data) / len(interval_signal_data)
					analyze_fp.write(f'{time},{speed},{line_quality},{link_level}\n')

def main():
	if len(sys.argv) != 2:
		sys.stderr.write(f'Usege {sys.argv[0]} directory\n')
		sys.exit(-1)
	analyze('download')
	analyze('upload')

if __name__ == "__main__":
	main()


from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import (Base, Pet, Owner, Handler, Job)
# from faker import Faker

if __name__ == "__main__":
  # fake = Faker()
  print("Seeding ðŸŒ±...")
  print("Connecting to DB....")
  engine = create_engine('sqlite:///pet_app.db')
  Base.metadata.create_all(engine)

  Session = sessionmaker(bind=engine)
  session = Session()
  print("Session Created...")

  session.query(Pet).delete()
  session.query(Owner).delete()
  session.query(Handler).delete()
  session.query(Job).delete()
  session.commit()

  print("CREATING OWNERS....")
  holden = Owner(name="Holden", email="h@h.com", phone="1234", address="13 Elm Street")
  connor = Owner(name="Connor", email="c@c.com", phone="5678", address="14 Elm Street")

  session.add(holden)
  session.add(connor)
  session.commit()

  print("CREATING PETS....")
  p1 = Pet(name="fake.name()", species="Dog", breed="Mutt", temperament="bad", owner_id=holden.id)
  p2 = Pet(name="chauncy", species="Dog", breed="Golden", temperament="good", owner_id=holden.id)
  p3 = Pet(name="Hank", species="Cat", breed="Orange", temperament="really bad", owner_id=holden.id)
  p4 = Pet(name="Derby", species="Aligator", breed="Croc", temperament="snuggly", owner_id=connor.id)

  # seeding_pets = []
  # species_types = ["dog", 'cat', 'aligator']

  # for pet in range(0,100):
  #     seeding_pets.append(Pet(name=fake.name(), species="Dog", breed="Mutt", temperament="bad", owner_id=holden.id))
  # session.add_all(seeding_pets)

  session.add_all([p1,p2,p3,p4])
  session.commit()

  print("CREATING HANDLERS...")
  h1 = Handler(name="wally", email="w@w.com", phone=4321, hourly_rate=1.0)
  h2 = Handler(name="shelbs", email="s@s.com", phone=5432, hourly_rate=4.5)
  h3 = Handler(name="bill", email="b@b.com", phone=4231, hourly_rate=5.7)

  session.add_all([h1,h2, h3])
  session.commit()

  print("CREATING JOBS...")

  j1 = Job(date="Feb 1st", request="Walks", fee=55.0, pet_id=p1.id, handler_id=h1.id)
  j2 = Job(date="Feb 2nd", request="Runs", fee=23.50, pet_id=p1.id, handler_id=h2.id)
  j3 = Job(date="Feb 3rd", request="Sleep", fee=5.6, pet_id=p1.id, handler_id=h3.id)
  j4 = Job(date="April 1st", request="Meds", fee=1.0, pet_id=p3.id, handler_id=h1.id)

  session.add_all([j1, j2, j3, j4])
  session.commit()

  print("DONE!")


import collections
from typing import List

def findShortestSubArray(nums: List[int]) -> int:
    record = 0
    remain = collections.defaultdict(list)
    for i, num in enumerate(nums):
        if num in remain:
            remain[num][0] += 1
            remain[num][2] = i
        else:
            remain[num] = [1, i, i]
        record = max(record, remain[num][0])

    result = 50001
    for count, start, end in remain.values():
        if count == record:
            result = min(result, end - start + 1)

    return result

if __name__ == "__main__":
    print(findShortestSubArray([1]))


# from re import I
# from socket import if_indextoname
import numpy as np
from copy import deepcopy
import random
from random import choice
from dispatch_alg import LD
from math import radians, sin, atan2,cos,acos
from config import *
import math
import pickle
import osmnx as ox
from tqdm import tqdm
import pandas as pd
import sys
from collections import Counter
import pymongo
import time
import scipy.stats as st
from scipy.stats import skewnorm
"""
Here, we load the information of graph network from graphml file.
"""
G = ox.load_graphml('./input/graph.graphml')
gdf_nodes, gdf_edges = ox.graph_to_gdfs(G)
lat_list = gdf_nodes['y'].tolist()
lng_list = gdf_nodes['x'].tolist()
node_id = gdf_nodes.index.tolist()
node_id_to_lat_lng = {}
node_coord_to_id = {}
for i in range(len(lat_list)):
    node_id_to_lat_lng[node_id[i]] = (lat_list[i], lng_list[i])
    node_coord_to_id[(lng_list[i], lat_list[i])] = node_id[i]

center = (
(env_params['east_lng'] + env_params['west_lng']) / 2, (env_params['north_lat'] + env_params['south_lat']) / 2)
radius = max(abs(env_params['east_lng'] - env_params['west_lng']) / 2,
             abs(env_params['north_lat'] - env_params['south_lat']) / 2)
side = env_params['side']
interval = 2 * radius / side

"""
Here, we build the connection to mongodb, which will be used to speed up access to road network information.
"""
myclient = pymongo.MongoClient("mongodb://localhost:27017/")
mydb = myclient["route_network"]

mycollect = mydb['route_list']

# define the function to get zone_id of segment node
def get_zone(lat, lng):
    """
    :param lat: the latitude of coordinate
    :type : float
    :param lng: the longitude of coordinate
    :type lng: float
    :return: the id of zone that the point belongs to
    :rtype: float
    """
    if lat < center[1]:
        i = math.floor(side / 2) - math.ceil((center[1] - lat) / interval) + side % 2
    else:
        i = math.floor(side / 2) + math.ceil((lat - center[1]) / interval) - 1

    if lng < center[0]:
        j = math.floor(side / 2) - math.ceil((center[0] - lng) / interval) + side % 2
    else:
        j = math.floor(side / 2) + math.ceil((lng - center[0]) / interval) - 1
    return i * side + j

result = pd.DataFrame()
nodelist = []
result['lat'] = lat_list
result['lng'] = lng_list
result['node_id'] = gdf_nodes.index.tolist()
for i in range(len(result)):
    nodelist.append(get_zone(lat_list[i], lng_list[i]))
result['grid_id'] = nodelist

"""Generate the available directions for each grid"""
df_available_directions = pd.DataFrame(columns=['zone_id','direction_0','direction_1','direction_2','direction_3','direction_4'])
df_neighbor_centroid = pd.DataFrame()
direction_1_list = []   # up
direction_2_list = []   # down
direction_3_list = []   # left
direction_4_list = []   # right

direction0_available_list = [i for i in range(side**2)] # stay
direction1_available_list = [] # up
direction2_available_list = [] # down
direction3_available_list = [] # left
direction4_available_list = [] # right
centroid_lng_list = []
centroid_lat_list = []

if env_params['rl_mode'] == "matching":
    for i in range(side**2):

        centroid_lng_list.append(result[result['grid_id']==i]['lng'])
        centroid_lat_list.append(result[result['grid_id']==i]['lat'])
        # up
        if math.floor(i / side) == 0:
            direction_1_list.append(0)
            direction1_available_list.append(np.nan)
        else:
            direction_1_list.append(1)
            direction1_available_list.append(i-side)

        # down
        if math.floor(i / side) == side - 1:
            direction_2_list.append(0)
            direction2_available_list.append(np.nan)
        else:
            direction_2_list.append(1)
            direction2_available_list.append(i + side)

        # left
        if i % side == 0:
            direction_3_list.append(0)
            direction3_available_list.append(np.nan)
        else:
            direction_3_list.append(1)
            direction3_available_list.append(i-1)

        # right
        if i % side == side -1:
            direction_4_list.append(0)
            direction4_available_list.append(np.nan)
        else:
            direction_4_list.append(1)
            direction4_available_list.append(i+1)
elif env_params['rl_mode'] == "reposition":
    for i in range(side**2):
        if len(result[result['grid_id']==i]['lng'].values.tolist()) == 0:
            centroid_lng_list.append(lng_list[0])
            centroid_lat_list.append(lat_list[0])
        else:
            centroid_lng_list.append(result[result['grid_id']==i]['lng'].values.tolist()[0])
            centroid_lat_list.append(result[result['grid_id']==i]['lat'].values.tolist()[0])
        # up
        if math.floor(i / side) == 0 and len(result[result['grid_id']==i-side]['lng'].values.tolist()) == 0:
            direction_1_list.append(0)
            direction1_available_list.append(i)
        else:
            direction_1_list.append(1)
            direction1_available_list.append(i-side)

        # down
        if math.floor(i / side) == side - 1 and len(result[result['grid_id']==i+side]['lng'].values.tolist()) == 0:
            direction_2_list.append(0)
            direction2_available_list.append(i)
        else:
            direction_2_list.append(1)
            direction2_available_list.append(i + side)

        # left
        if i % side == 0 and len(result[result['grid_id']==i-1]['lng'].values.tolist()) == 0:
            direction_3_list.append(0)
            direction3_available_list.append(i)
        else:
            direction_3_list.append(1)
            direction3_available_list.append(i-1)

        # right
        if i % side == side -1 and len(result[result['grid_id']==i+1]['lng'].values.tolist()) == 0:
            direction_4_list.append(0)
            direction4_available_list.append(i)
        else:
            direction_4_list.append(1)
            direction4_available_list.append(i+1)

df_available_directions['zone_id'] = [i for i in range(side**2)]
df_available_directions['direction_0'] = 1
df_available_directions['direction_1'] = direction_1_list
df_available_directions['direction_2'] = direction_2_list
df_available_directions['direction_3'] = direction_3_list
df_available_directions['direction_4'] = direction_4_list

df_neighbor_centroid['zone_id'] = direction0_available_list
df_neighbor_centroid['centroid_lng'] = centroid_lng_list
df_neighbor_centroid['centroid_lat'] = centroid_lat_list
df_neighbor_centroid['stay'] = direction0_available_list
df_neighbor_centroid['up'] = direction1_available_list
df_neighbor_centroid['right'] = direction4_available_list
df_neighbor_centroid['down'] = direction2_available_list
df_neighbor_centroid['left'] = direction3_available_list

# rl for matching
def get_exponential_epsilons(initial_epsilon, final_epsilon, steps, decay=0.99, pre_steps=10):
    """
    obtain exponential decay epsilons
    :param initial_epsilon:
    :param final_epsilon:
    :param steps:
    :param decay: decay rate
    :param pre_steps: first several epsilons does note decay
    :return:
    """
    epsilons = []

    # pre randomness
    for i in range(0, pre_steps):
        epsilons.append(deepcopy(initial_epsilon))

    # decay randomness
    epsilon = initial_epsilon
    for i in range(pre_steps, steps):
        epsilon = max(final_epsilon, epsilon * decay)
        epsilons.append(deepcopy(epsilon))

    return np.array(epsilons)
# rl for matching

# rl for repositioning
def s2e(n, total_len = 14):
    n = n.astype(int)
    k = (((n[:,None] & (1 << np.arange(total_len))[::-1])) > 0).astype(np.float64)
    return k
# rl for repositioning

# rl for repositioning
def get_exponential_epsilons(initial_epsilon, final_epsilon, steps, decay=0.99, pre_steps=10):
    """
    obtain exponential decay epsilons
    :param initial_epsilon:
    :param final_epsilon:
    :param steps:
    :param decay: decay rate
    :param pre_steps: first several epsilons does note decay
    :return:
    """
    epsilons = []

    # pre randomness
    for i in range(0, pre_steps):
        epsilons.append(deepcopy(initial_epsilon))

    # decay randomness
    epsilon = initial_epsilon
    for i in range(pre_steps, steps):
        epsilon = max(final_epsilon, epsilon * decay)
        epsilons.append(deepcopy(epsilon))

    return np.array(epsilons)
# rl for repositioning

def distance(coord_1, coord_2):
    """
    :param coord_1: the coordinate of one point
    :type coord_1: tuple -- (latitude,longitude)
    :param coord_2: the coordinate of another point
    :type coord_2: tuple -- (latitude,longitude)
    :return: the manhattan distance between these two points
    :rtype: float
    """
    manhattan_dis = 0
    try:
        lon1,lat1 = coord_1
        lon2,lat2  = coord_2
        lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
        r = 6371
        lat_dis = r * acos(min(1.0, cos(lat1) ** 2 * cos(lon1 - lon2) + sin(lat1) ** 2))
        lon_dis = r * (lat2 - lat1)
        manhattan_dis = (abs(lat_dis) ** 2 + abs(lon_dis) ** 2) ** 0.5
    except Exception as e:
        print(e)
        print(coord_1)
        print(coord_2)
        print(lon1 - lon2)
        print(cos(lat1) ** 2 * cos(lon1 - lon2) + sin(lat1) ** 2)
        print(acos(cos(lat1) ** 2 * cos(lon1 - lon2) + sin(lat1) ** 2))

    return manhattan_dis

def distance_array(coord_1, coord_2):
    """
    :param coord_1: array of coordinate
    :type coord_1: numpy.array
    :param coord_2: array of coordinate
    :type coord_2: numpy.array
    :return: the array of manhattan distance of these two-point pair
    :rtype: numpy.array
    """
    # manhattan_dis = list()
    # for i in range(len(coord_1)):
    #     lon1,lat1 = coord_1[i]
    #     lon2,lat2 = coord_2[i]
    #     lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
    #     r = 6371
    #     lat_dis = r * acos(min(1.0, cos(lat1) ** 2 * cos(lon1 - lon2) + sin(lat1) ** 2))
    #     lon_dis = r * (lat2 - lat1)
    #     manhattan_dis.append((abs(lat_dis) ** 2 + abs(lon_dis) ** 2) ** 0.5)
    # return np.array(manhattan_dis)
    coord_1 = np.array(coord_1).astype(float)
    coord_2 = np.array(coord_2).astype(float)
    coord_1_array = np.radians(coord_1)
    coord_2_array = np.radians(coord_2)
    dlon = coord_2_array[:, 0] - coord_1_array[:, 0]
    dlat = coord_2_array[:, 1] - coord_1_array[:, 1]
    a = np.sin(dlat / 2) ** 2 + np.cos(coord_1_array[:, 1]) * np.cos(coord_2_array[:, 1]) * np.sin(dlon / 2) ** 2
    c = 2 * np.arcsin(a ** 0.5)
    r = 6371
    distance = c * r
    return distance

def get_distance_array(origin_coord_array, dest_coord_array):
    """
    :param origin_coord_array: list of coordinates
    :type origin_coord_array:  list
    :param dest_coord_array:  list of coordinates
    :type dest_coord_array:  list
    :return: tuple like (
    :rtype: list
    """
    dis_array = []
    for i in range(len(origin_coord_array)):
        dis = distance(origin_coord_array[i], dest_coord_array[i])
        dis_array.append(dis)
    dis_array = np.array(dis_array)
    return dis_array

def route_generation_array(origin_coord_array, dest_coord_array, mode='rg'):
    """

    :param origin_coord_array: the K*2 type list, the first column is lng, the second column
                                is lat.
    :type origin_coord_array: numpy.array
    :param dest_coord_array: the K*2 type list, the first column is lng, the second column
                                is lat.
    :type dest_coord_array: numpy.array
    :param mode: the mode of generation; if the value of mode is complete, return the last node of route;
                 if the value of mode is drop_end, the last node of route will be dropped.
    :type mode: string
    :return: tuple like (itinerary_node_list, itinerary_segment_dis_list, dis_array)
             itinerary_node_list contains the id of nodes, itinerary_segment_dis_list contains
             the distance between two nodes, dis_array contains the distance from origin node to
             destination node
    :rtype: tuple
    """
    # print("route generation start")
    # origin_coord_list为 Kx2 的array，第一列为lng，第二列为lat；dest_coord_array同理
    # itinerary_node_list的每一项为一个list，包含了对应路线中的各个节点编号
    # itinerary_segment_dis_list的每一项为一个array，包含了对应路线中的各节点到相邻下一节点的距离
    # dis_array包含了各行程的总里程
    origin_node_list = get_nodeId_from_coordinate(origin_coord_array[:, 0], origin_coord_array[:, 1])
    dest_node_list = get_nodeId_from_coordinate(dest_coord_array[:, 0], dest_coord_array[:, 1])
    itinerary_node_list = []
    itinerary_segment_dis_list = []
    dis_array = []
    if mode == 'ma':
        for origin, dest in zip(origin_node_list, dest_node_list):
            itinerary_node_list.append([dest])
            dis = distance(node_id_to_lat_lng[origin], node_id_to_lat_lng[dest])
            itinerary_segment_dis_list.append([dis])
            dis_array.append(dis)
        return itinerary_node_list, itinerary_segment_dis_list, np.array(dis_array)

    if mode == 'rg':
        # 返回完整itinerary
        for origin,dest in zip(origin_node_list,dest_node_list):
            data = {
                'node': str(origin) + str(dest)
            }
            re = mycollect.find_one(data)
            if re:
                ite = [int(item) for item in re['itinerary_node_list'].strip('[').strip(']').split(', ')]
            else:
                ite = ox.distance.shortest_path(G, origin, dest, weight='length', cpus=16)
            if ite is not None and len(ite) > 1:
                itinerary_node_list.append(ite)
            else:
                itinerary_node_list.append([origin,dest])
        # itinerary_node_list = ox.distance.shortest_path(G, origin_node_list, dest_node_list, weight='length', cpus=16)
        for itinerary_node in itinerary_node_list:

            if itinerary_node is not None:
                itinerary_segment_dis = []
                for i in range(len(itinerary_node) - 1):
                    # dis = nx.shortest_path_length(G, node_id_to_lat_lng[itinerary_node[i]], node_id_to_lat_lng[itinerary_node[i + 1]], weight='length')

                    dis = distance(node_id_to_lat_lng[itinerary_node[i]], node_id_to_lat_lng[itinerary_node[i + 1]])
                    itinerary_segment_dis.append(dis)
                dis_array.append(sum(itinerary_segment_dis))
                itinerary_segment_dis_list.append(itinerary_segment_dis)
            itinerary_node.pop()

        # a toy example
        # for i in range(origin_coord_array.shape[0]):
        #     origin_lng = origin_coord_array[i, 0]
        #     if origin_lng == 0:
        #         itinerary_node = [0,1,2]
        #         itinerary_segment_dis = [1,1,0]
        #         dis = 2
        #     elif origin_lng == 1:
        #         itinerary_node = [2,3,0]
        #         itinerary_segment_dis = [1, 1, 0]
        #         dis = 2
        # itinerary_node_list.append(itinerary_node)
        # itinerary_segment_dis_list.append(itinerary_segment_dis)
        # dis_array.append(dis)
        # dis_array = np.array(dis_array)
    elif mode == 'drop_end':
        # 对itineray node_list和itineray segment_time_list中的各个item，把末尾节点给drop掉

        # a toy example
        # for i in range(origin_coord_array.shape[0]):
        #     origin_lng = origin_coord_array[i, 0]
        #     if origin_lng == 0:
        #         itinerary_node = [0, 1]
        #         itinerary_segment_dis = [1, 1]
        #         dis = 2
        #     elif origin_lng == 1:
        #         itinerary_node = [2, 3]
        #         itinerary_segment_dis = [1, 1]
        #         dis = 2
        # itinerary_node_list.append(itinerary_node)
        # itinerary_segment_dis_list.append(itinerary_segment_dis)
        # dis_array.append(dis)
        # dis_array = np.array(dis_array)
        for origin,dest in zip(origin_node_list, dest_node_list):
            # data = {
            #     'node': str(origin)+str(dest)
            # }
            # re = mycollect.find_one(data)['itinerary_node_list']
            # if re:
            #     ite = re
            # else:
            ite = ox.distance.shortest_path(G, origin, dest, weight='length', cpus=16)
            if ite is not None and len(ite) > 1:
                itinerary_node_list.append(ite)
            else:
                itinerary_node_list.append([origin,dest])

        for itinerary_node in itinerary_node_list:
            itinerary_segment_dis = []
            for i in range(len(itinerary_node) - 1):
                # dis = nx.shortest_path_length(G, node_id_to_lat_lng[itinerary_node[i]], node_id_to_lat_lng[itinerary_node[i + 1]], weight='length')
                try:
                    dis = distance(node_id_to_lat_lng[itinerary_node[i]], node_id_to_lat_lng[itinerary_node[i + 1]])
                except:
                    print("itinerary exception")

                itinerary_segment_dis.append(dis)
            itinerary_node.pop()
            dis_array.append(sum(itinerary_segment_dis))
            # if len(itinerary_node) != itinerary_segment_dis:
            #     print(len(itinerary_node))
            #     print(itinerary_segment_dis)
            itinerary_segment_dis_list.append(itinerary_segment_dis)

    dis_array = np.array(dis_array)
    return itinerary_node_list, itinerary_segment_dis_list, dis_array

class road_network:

    def __init__(self, **kwargs):
        self.params = kwargs

    def load_data(self):
        """
        :param data_path: the path of road_network file
        :type data_path:  string
        :param file_name: the filename of road_network file
        :type file_name:  string
        :return: None
        :rtype:  None
        """
        # 路网格式：节点数字编号（从0开始），节点经度，节点纬度，所在grid id
        self.df_road_network = result

    def get_information_for_nodes(self, node_id_array):
        """
        :param node_id_array: the array of node id
        :type node_id_array:  numpy.array
        :return:  (lng_array,lat_array,grid_id_array), lng_array is the array of longitude;
                lat_array is the array of latitude; the array of node id.
        :rtype: tuple
        """
        index_list = [self.df_road_network[self.df_road_network['node_id'] == item].index[0] for item in node_id_array]
        lng_array = self.df_road_network.loc[index_list,'lng'].values
        lat_array = self.df_road_network.loc[index_list,'lat'].values
        grid_id_array = self.df_road_network.loc[index_list,'grid_id'].values
        return lng_array, lat_array, grid_id_array

def get_exponential_epsilons(initial_epsilon, final_epsilon, steps, decay=0.99, pre_steps=10):
    """
    :param initial_epsilon: initial epsilon
    :type initial_epsilon: float
    :param final_epsilon: final epsilon
    :type final_epsilon: float
    :param steps: the number of iteration
    :type steps: int
    :param decay: decay rate
    :type decay:  float
    :param pre_steps: the number of iteration of pre randomness
    :type pre_steps: int
    :return: the array of epsilon
    :rtype: numpy.array
    """

    epsilons = []

   # pre randomness
    for i in range(0, pre_steps):
        epsilons.append(deepcopy(initial_epsilon))

    # decay randomness
    epsilon = initial_epsilon
    for i in range(pre_steps, steps):
        epsilon = max(final_epsilon, epsilon * decay)
        epsilons.append(deepcopy(epsilon))

    return np.array(epsilons)

def sample_all_drivers(driver_info, t_initial, t_end, driver_sample_ratio=1, driver_number_dist=''):
    """
    :param driver_info: the information of driver
    :type driver_info:  pandas.DataFrame
    :param t_initial:   time of initial state
    :type t_initial:    int
    :param t_end:       time of terminal state
    :type t_end:        int
    :param driver_sample_ratio:
    :type driver_sample_ratio:
    :param driver_number_dist:
    :type driver_number_dist:
    :return:
    :rtype:
    """
    # 当前并无随机抽样司机；后期若需要，可设置抽样模块生成sampled_driver_info
    new_driver_info = deepcopy(driver_info)
    sampled_driver_info = new_driver_info.sample(frac=driver_sample_ratio)
    sampled_driver_info['status'] = 3
    loc_con = sampled_driver_info['start_time'] <= t_initial
    sampled_driver_info.loc[loc_con, 'status'] = 0
    sampled_driver_info['target_loc_lng'] = sampled_driver_info['lng']
    sampled_driver_info['target_loc_lat'] = sampled_driver_info['lat']
    sampled_driver_info['target_grid_id'] = sampled_driver_info['grid_id']
    sampled_driver_info['remaining_time'] = 0
    sampled_driver_info['matched_order_id'] = 'None'
    sampled_driver_info['total_idle_time'] = 0
    sampled_driver_info['time_to_last_cruising'] = 0
    sampled_driver_info['current_road_node_index'] = 0
    sampled_driver_info['remaining_time_for_current_node'] = 0
    sampled_driver_info['itinerary_node_list'] = [[] for i in range(sampled_driver_info.shape[0])]
    sampled_driver_info['itinerary_segment_time_list'] = [[] for i in range(sampled_driver_info.shape[0])]

    return sampled_driver_info

def sample_request_num(t_mean, std, delta_t):
    """
    sample request num during delta t
    :param t_mean:
    :param std:
    :param delta_t:
    :return:
    """
    random_num = np.random.normal(t_mean, std, 1)[0] * (delta_t / 100)
    random_int = random_num // 1
    random_reminder = random_num % 1

    rn = random.random()
    if rn < random_reminder:
        request_num = random_int + 1
    else:
        request_num = random_int
    return int(request_num)

def reposition(eligible_driver_table, mode):
    """
    :param eligible_driver_table:
    :type eligible_driver_table:
    :param mode:
    :type mode:
    :return:
    :rtype:
    """
    random_number = np.random.randint(0, side * side - 1)
    dest_array = []
    for _ in range(len(eligible_driver_table)):
        record = result[result['grid_id'] == random_number]
        if len(record) > 0:
            dest_array.append([record.iloc[0]['lng'], record.iloc[0]['lat']])
        else:
            dest_array.append([result.iloc[0]['lng'], result.iloc[0]['lat']])
    coord_array = eligible_driver_table.loc[:, ['lng', 'lat']].values
    itinerary_node_list, itinerary_segment_dis_list, dis_array = route_generation_array(coord_array, np.array(dest_array))
    return itinerary_node_list, itinerary_segment_dis_list, dis_array

def cruising(eligible_driver_table, mode,grid_value ={}):
    """
    :param eligible_driver_table: information of eligible driver.
    :type eligible_driver_table: pandas.DataFrame
    :param mode: the type of both-rg-cruising, if type is random; it can cruise to every node with equal
                probability; if the type is nearby, it will cruise to the node in adjacent grid or
                just stay at the original region.
    :type mode: string
    :return: itinerary_node_list, itinerary_segment_dis_list, dis_array
    :rtype: tuple
    """
    dest_array = []
    grid_id_list = eligible_driver_table.loc[:, 'grid_id'].values
    for grid_id in (grid_id_list):
        if mode == "global-random":
            random_number = random.randint(0,side*side-1)
        elif mode == 'random':
            target = [grid_id]
            if int((grid_id - 1) / side) == int(grid_id / side) and grid_id - 1 > 0:
                target.append(grid_id - 1)
            if int((grid_id + 1) / side) == int(grid_id / side) and grid_id + 1 < side * side:
                target.append(grid_id + 1)
            if grid_id + side < side * side:
                target.append(grid_id + side)
            if grid_id - side > 0:
                target.append(grid_id - side)
            random_number = choice(target)
        elif mode == 'nearby':
            target = []
            if int((grid_id - 1) / side) == int(grid_id / side) and grid_id - 1 > 0:
                target.append(grid_id - 1)
            if int((grid_id + 1) / side) == int(grid_id / side) and grid_id + 1 < side * side:
                target.append(grid_id + 1)
            if grid_id + side < side * side:
                target.append(grid_id + side)
            if grid_id - side > 0:
                target.append(grid_id - side)
            random_number = choice(target)
        record = result[result['grid_id'] == random_number]
        if len(record) > 0:
            dest_array.append([record.iloc[0]['lng'], record.iloc[0]['lat']])
        else:
            dest_array.append([result.iloc[0]['lng'], result.iloc[0]['lat']])
    coord_array = eligible_driver_table.loc[:, ['lng', 'lat']].values
    itinerary_node_list, itinerary_segment_dis_list, dis_array = route_generation_array(coord_array,
                                                                                np.array(dest_array))
    return itinerary_node_list, itinerary_segment_dis_list, dis_array

def skewed_normal_distribution(u,thegma,k,omega,a,input_size):

    return skewnorm.rvs(a,loc=u,scale=thegma,size=input_size)

def order_dispatch(wait_requests, driver_table, maximal_pickup_distance=950, dispatch_method='LD',method='pickup_distance'):
    """
    :param wait_requests: the requests of orders
    :type wait_requests: pandas.DataFrame
    :param driver_table: the information of online drivers
    :type driver_table:  pandas.DataFrame
    :param maximal_pickup_distance: maximum of pickup distance
    :type maximal_pickup_distance: int
    :param dispatch_method: the method of order dispatch
    :type dispatch_method: string
    :return: matched_pair_actual_indexs: order and driver pair, matched_itinerary: the itinerary of matched driver
    :rtype: tuple
    """
    con_ready_to_dispatch = (driver_table['status'] == 0) | (driver_table['status'] == 4)
    idle_driver_table = driver_table[con_ready_to_dispatch]
    num_wait_request = wait_requests.shape[0]
    num_idle_driver = idle_driver_table.shape[0]
    matched_pair_actual_indexs = []
    matched_itinerary = []

    if num_wait_request > 0 and num_idle_driver > 0:
        if dispatch_method == 'LD':
            # generate order driver pairs and corresponding itinerary
            request_array_temp = wait_requests.loc[:, ['origin_lng', 'origin_lat', 'order_id', 'weight']]
            request_array = np.repeat(request_array_temp.values, num_idle_driver, axis=0)
            driver_loc_array_temp = idle_driver_table.loc[:, ['lng', 'lat', 'driver_id']]
            driver_loc_array = np.tile(driver_loc_array_temp.values, (num_wait_request, 1))
            dis_array = distance_array(request_array[:, :2], driver_loc_array[:, :2])
            if method == "pickup_distance":
                # weight转换为最大pickup distance - 当前pickup distance
                request_array[:,-1] = maximal_pickup_distance - dis_array + 1
            flag = np.where(dis_array <= maximal_pickup_distance)[0]
            if len(flag) > 0:
                order_driver_pair = np.vstack(
                    [request_array[flag, 2], driver_loc_array[flag, 2], request_array[flag, 3], dis_array[flag]]).T
                matched_pair_actual_indexs = LD(order_driver_pair.tolist())
                request_indexs = np.array(matched_pair_actual_indexs)[:, 0]
                driver_indexs = np.array(matched_pair_actual_indexs)[:, 1]
                request_indexs_new = []
                driver_indexs_new = []
                for index in request_indexs:
                    request_indexs_new.append(request_array_temp[request_array_temp['order_id'] == int(index)].index.tolist()[0])
                for index in driver_indexs:
                    driver_indexs_new.append(driver_loc_array_temp[driver_loc_array_temp['driver_id'] == index].index.tolist()[0])
                request_array_new = np.array(request_array_temp.loc[request_indexs_new])[:,:2]
                driver_loc_array_new = np.array(driver_loc_array_temp.loc[driver_indexs_new])[:,:2]
                itinerary_node_list, itinerary_segment_dis_list, dis_array = route_generation_array(
                    driver_loc_array_new, request_array_new, mode=env_params['pickup_mode'])
                # itinerary_node_list_new = []
                # itinerary_segment_dis_list_new = []
                # dis_array_new = []
                # for item in matched_pair_actual_indexs:
                #     index = int(item[3])
                #     itinerary_node_list_new.append(itinerary_node_list[index])
                #     itinerary_segment_dis_list_new.append(itinerary_segment_dis_list[index])
                #     dis_array_new.append(dis_array[index])

                matched_itinerary = [itinerary_node_list, itinerary_segment_dis_list, dis_array]
    return matched_pair_actual_indexs, np.array(matched_itinerary)

def driver_online_offline_decision(driver_table, current_time):

    # 注意pickup和delivery driver不应当下线
    # 车辆状态：0 cruise (park 或正在cruise)， 1 表示delivery，2 pickup, 3 表示下线, 4 reposition
    # This function is aimed to switch the driver states between 0 and 3, based on the 'start_time' and 'end_time' of drivers
    # Notice that we should not change the state of delievery and pickup drivers, since they are occopied.
    online_driver_table = driver_table.loc[(driver_table['start_time'] <= current_time) & (driver_table['end_time'] > current_time)]
    offline_driver_table = driver_table.loc[(driver_table['start_time'] > current_time) | (driver_table['end_time'] <= current_time)]

    online_driver_table = online_driver_table.loc[(online_driver_table['status'] != 1) & (online_driver_table['status'] != 2)]
    offline_driver_table = offline_driver_table.loc[(offline_driver_table['status'] != 1) & (offline_driver_table['status'] != 2)]
    # print(f'online count: {len(online_driver_table)}, offline count: {len(offline_driver_table)}, total count: {len(driver_table)}')
    new_driver_table = driver_table
    new_driver_table.loc[new_driver_table.isin(online_driver_table.to_dict('list')).all(axis=1), 'status'] = 0
    new_driver_table.loc[new_driver_table.isin(offline_driver_table.to_dict('list')).all(axis=1), 'status'] = 3
    # return new_driver_table
    return new_driver_table

# define the function to get zone_id of segment node

def get_nodeId_from_coordinate(lng, lat):
    """

    :param lat: latitude
    :type lat:  float
    :param lng: longitute
    :type lng:  float
    :return:  id of node
    :rtype: string
    """
    node_list = []
    for i in range(len(lat)):
        x = node_coord_to_id[(lng[i],lat[i])]
        node_list.append(x)
    return node_list

def KM_simulation(wait_requests, driver_table, method = 'nothing'):
    # currently, we use the dispatch alg of peibo
    idle_driver_table = driver_table[driver_table['status'] == 0]
    num_wait_request = wait_requests.shape[0]
    num_idle_driver = idle_driver_table.shape[0]

    if num_wait_request > 0 and num_idle_driver > 0:
        starttime_1 = time.time()

        request_array = wait_requests.loc[:, ['origin_lat', 'origin_lng', 'order_id', 'weight']].values
        request_array = np.repeat(request_array, num_idle_driver, axis=0)
        driver_loc_array = idle_driver_table.loc[:, ['lat', 'lng', 'driver_id']].values
        driver_loc_array = np.tile(driver_loc_array, (num_wait_request, 1))
        assert driver_loc_array.shape[0] == request_array.shape[0]
        dis_array = distance_array(request_array[:, :2], driver_loc_array[:, :2])
        # print('negative: ', np.where(dis_array)<0)
        flag = np.where(dis_array <= 950)[0]
        if method == 'pickup_distance':
            order_driver_pair = np.vstack([request_array[flag, 2], driver_loc_array[flag, 2], 951 - dis_array[flag], dis_array[flag]]).T
        elif method in ['total_travel_time_no_subway', 'total_travel_time_with_subway']:
            order_driver_pair = np.vstack(
                [request_array[flag, 2], driver_loc_array[flag, 2], request_array[flag, 3] + 135 - dis_array[flag]/6.33, dis_array[flag]]).T
        elif method in ['sarsa_total_travel_time', 'sarsa_total_travel_time_no_subway']:
            order_driver_pair = np.vstack(
                [request_array[flag, 2], driver_loc_array[flag, 2], request_array[flag, 3] + 135 - dis_array[flag] / 6.33,
                 dis_array[flag]]).T
        else:
            order_driver_pair = np.vstack([request_array[flag, 2], driver_loc_array[flag, 2], request_array[flag, 3], dis_array[flag]]).T  # rl for matching
        order_driver_pair = order_driver_pair.tolist()

        endtime_1 = time.time()
        dtime_1 = endtime_1 - starttime_1
        #print('# of pairs: ', len(order_driver_pair))
        #print("pair forming time：%.8s s" % dtime_1)

        if len(order_driver_pair) > 0:
            #matched_pair_actual_indexs = km.run_kuhn_munkres(order_driver_pair)
            matched_pair_actual_indexs = dispatch_alg_array(order_driver_pair)

            endtime_2 = time.time()
            dtime_2 = endtime_2 - endtime_1
            #print('# of matched pairs: ', len(matched_pair_actual_indexs))
            #print("dispatch alg 1 running time：%.8s s" % dtime_2)
        else:
            matched_pair_actual_indexs = []
    else:
        matched_pair_actual_indexs = []

    return matched_pair_actual_indexs

def KM_for_agent():
    # KM used in agent.py for KDD competition
    pass

def random_actions(possible_directions):
    # make random move and generate a one hot vector
    action = random.sample(possible_directions, 1)[0]
    return action

# rl for matching
# state for sarsa
class State:
    def __init__(self, time_slice: int, grid_id: int):
        self.time_slice = time_slice  # time slice
        self.grid_id = grid_id  # the grid where a taxi stays in

    def __hash__(self):
        return hash(str(self.grid_id) + str(self.time_slice))

    def __eq__(self, other):
        if self.grid_id == other.grid_id and self.time_slice == other.time_slice:
            return True
        return False
# rl for matching

#############################################################################


#!/usr/bin/env python3
# coding=utf-8
import asyncio

import aiohttp
import pytest

from podcastdownloader.episode import Episode
from podcastdownloader.exceptions import EpisodeException

@pytest.fixture(scope='session')
def client_session() -> aiohttp.ClientSession:
    out = aiohttp.ClientSession()
    return out

@pytest.mark.parametrize(('test_link_dict', 'expected'), (
    ([{
        'rel': 'alternate',
        'type': 'text/html',
        'href': 'http://evenmorenewspodcast.com/usa-still-leaving-afghanistan-still-shooting'
        '-unarmed-people-w-christopher-rivas-ep-142',
    },
        {
        'length': '54468321',
        'type': 'audio/mpeg',
        'href': 'https://dts.podtrac.com/redirect.mp3/chtbl.com/track/242FB3/'
        'traffic.libsyn.com/secure/evenmorenews/EMN_Ep142.mp3?dest-id=695480',
        'rel': 'enclosure',
    }],
        'https://dts.podtrac.com/redirect.mp3/chtbl.com/track/242FB3/'
        'traffic.libsyn.com/secure/evenmorenews/EMN_Ep142.mp3?dest-id=695480'),
))
def test_episode_find_url(test_link_dict: list[dict], expected: str):
    test_dict = {'links': test_link_dict, }
    result = Episode._find_url(test_dict)
    assert result == expected

@pytest.mark.parametrize('test_link_dict', (
    [{
        'rel': 'alternate',
        'type': 'text/html',
        'href': 'http://evenmorenewspodcast.com/usa-still-leaving-afghanistan-still-shooting'
        '-unarmed-people-w-christopher-rivas-ep-142',
    }],
))
def test_episode_find_url_bad(test_link_dict: list[dict]):
    test_dict = {'links': test_link_dict, }
    with pytest.raises(EpisodeException):
        Episode._find_url(test_dict)

@pytest.mark.parametrize(('test_url', 'expected'), (
    ('https://www.example.com/test.png', '.png'),
    ('https://www.example.com/test.mp3', '.mp3'),
    ('https://www.example.com/random/test.flac', '.flac'),
    ('https://www.example.com/test.mp3?test=value', '.mp3'),
    ('https://www.example.com/test.mp3?test=value#test', '.mp3'),
    ('https://www.example.com/test.aac', '.aac'),
))
def test_determine_file_extension_from_url(test_url: str, expected: str, client_session):
    result = asyncio.run(Episode._get_file_extension(test_url, client_session))
    assert result == expected

@pytest.mark.parametrize(('test_name', 'expected'), (
    ('test', 'test'),
    ('te/st', 'test'),
    ('test/test', 'testtest'),
    ('test\0', 'test'),
))
def test_clean_name(test_name: str, expected: str):
    result = Episode._clean_name(test_name)
    assert result == expected


import csv
import logging

import psycopg2.extras

from . import DBManager
from . import dimRole
from . import dimPerson

LOGGING = logging.getLogger(__name__)

def stage_csv(conn, file_path):
    LOGGING.debug("StagingFile '{file}'".format(file=file_path))
    with open(file_path, 'r') as csv_file:
        reader = csv.DictReader(csv_file)
        # ToDo: Validation of column names and types
        with conn.cursor() as cur:
            psycopg2.extras.execute_values(
                cur,
                """
                INSERT INTO
                  stg.dimPersonRole(
                    source_file_name,
                    source_file_creation,
                    externalReference_Person,
                    externalReference_Role,
                    effective_from
                  )
                VALUES
                %s
                """,
                reader,
                template="""
                  (
                    %(source_file_name)s,
                    %(create_date)s,
                    %(person_id)s,
                    %(role)s,
                    %(profile_modify_date)s
                  )
                """,
                page_size=1000
            )
            # ToDo: Logging of rows upload, time taken, etc
            conn.commit()

def cascadeActivations(conn, source):
    # to all children first
    pass
    # any necessary actions here
    dimRole.registerInitialisations(
        conn,
        """
          (
            SELECT DISTINCT externalReference_Role FROM stg.dimPersonRole WHERE externalReference_Role IS NOT NULL
          )
            {alias}
        """,
        {'externalReference_Role': 'externalReference_Role'}
    )
    dimPerson.registerInitialisations(
        conn,
        """
          (
            SELECT DISTINCT externalReference_Person FROM stg.dimPersonRole
          )
            {alias}
        """,
        {'externalReference_Person': 'externalReference_Person'}
    )

    # to all foreign key dependancies
    dimRole.cascadeActivations(conn, 'dimPersonRole')
    if (source != 'dimPerson'):
        dimPerson.cascadeActivations(conn, 'dimPersonRole')

def cascadeRetirements(conn, source):
    # to all foreign key dependancies first
    dimRole.cascadeRetirements(conn, 'dimPersonRole')
    if (source != 'dimPerson'):
        dimPerson.cascadeRetirements(conn, 'dimPersonRole')

    # any necessary actions here
    applyOrderOfPrecedence(conn)
    stageDeactivations(conn)
    resolveStagingFKs(conn)
    stageInitsTruncsAndUpdates(conn)

    # to all children
    pass

def applyOrderOfPrecedence(conn):
    LOGGING.debug("applyOrderOfPrecedence()")
    with conn.cursor() as cur:
        cur.execute(
            """
            WITH
              collapsed
            AS
            (
              SELECT DISTINCT
                externalreference_person,
                source_file_creation,
                source_file_name,
                effective_from
              FROM
                stg.dimpersonrole
            ),
              running_lowest
            AS
            (
              SELECT
                *,
                MIN(effective_from)
                  OVER (PARTITION BY externalreference_person
                            ORDER BY source_file_creation DESC,    -- Newer files have precedence (as if applied over the top of older files)
                                    source_file_name DESC,        -- Tie breaker : Same Person, Multiple Files, Same Creation Date - Behave as if applied in name order
                                    effective_from DESC           -- Where one file contains a sequence of changes, apply the changes in chronological order
                      )
                        AS lowest_effective_from
              FROM
                collapsed
            ),
              lagged
            AS
            (
              SELECT
                *,
                LAG(effective_from, 1, 2147483647)
                  OVER (PARTITION BY externalreference_person
                            ORDER BY source_file_creation DESC,    -- Newer files have precedence (as if applied over the top of older files)
                                    source_file_name DESC,        -- Tie breaker : Same Person, Multiple Files, Same Creation Date - Behave as if applied in name order
                                    effective_from DESC           -- Where one file contains a sequence of changes, apply the changes in chronological order
                      )
                        AS next_effective_from
              FROM
                running_lowest
              WHERE
                effective_from = lowest_effective_from             -- If the effective_from is higher than the lowest encountered so far, it's from an older file so can be ignored
            )
            UPDATE
              stg.dimpersonrole
            SET
              effective_stop = lagged.next_effective_from
            FROM
              lagged
            WHERE
                  lagged.effective_from           < lagged.next_effective_from                     -- Prevent zero duration periods
              AND lagged.externalreference_person = stg.dimpersonrole.externalreference_person
              AND lagged.source_file_name         = stg.dimpersonrole.source_file_name
              AND lagged.source_file_creation     = stg.dimpersonrole.source_file_creation
              AND lagged.effective_from           = stg.dimpersonrole.effective_from
            ;
            """
        )
    conn.commit()

def stageDeactivations(conn):
    LOGGING.debug("stageDeactivations()")
    with conn.cursor() as cur:
        cur.execute(
            """
            INSERT INTO
              stg.dimPersonRole (
                source_file_name,
                source_file_creation,
                externalreference_person,
                externalreference_role,
                effective_from,
                effective_stop,
                is_active,
                _staging_mode
              )
            SELECT
              '<De-Activate>',
              -1,
              stg.externalreference_person,
              dr.externalreference,
              stg.effective_from,
              stg.effective_stop,
              FALSE,
              'U'
            FROM
            (
              SELECT
                externalreference_person,
                effective_from,
                effective_stop
              FROM
                stg.dimPersonRole
              WHERE
                effective_stop IS NOT NULL  -- staging row not superceded by another staging row
              GROUP BY
                externalreference_person,
                effective_from,
                effective_stop
            )
              stg
            INNER JOIN
              dim.dimPerson       AS dp
                ON dp.externalReference = stg.externalreference_person
            INNER JOIN
            (
              SELECT
                personID,
                roleID
              FROM
                dim.dimPersonRole
              GROUP BY
                personID,
                roleID
            )
              dpr
                ON dpr.personID = dp.id
            INNER JOIN
              dim.dimRole         AS dr
                ON dr.id = dpr.roleID
            LEFT JOIN
              stg.dimPersonRole   AS chk
                ON  chk.externalreference_person = dp.externalreference
                AND chk.externalreference_role   = dr.externalreference
                AND chk.effective_from           = stg.effective_from
                AND chk.effective_stop          IS NOT NULL
            WHERE
              chk.externalreference_person IS NULL
            ;
            """
        )
    conn.commit()

def resolveStagingFKs(conn):
    LOGGING.debug("resolveStagingFKs()")
    with conn.cursor() as cur:
        cur.execute(
            """
            UPDATE
              stg.dimPersonRole   AS stg
            SET
              personID               = dpr.personID,
              roleID                 = dpr.RoleID,
              current_effective_from = dpr.effective_from,
              current_effective_stop = dpr.effective_stop
            FROM
              dim.dimPersonRole   AS dpr
            INNER JOIN
              dim.dimPerson       AS dp
                ON dp.id = dpr.personID
            INNER JOIN
              dim.dimRole         AS dr
                ON dr.id = dpr.roleID
            WHERE
                  stg.externalReference_Person  = dp.externalReference
              AND stg.externalReference_Role    = dr.externalReference
              AND stg.effective_from           >= dpr.effective_from
              AND stg.effective_from           <  dpr.effective_stop
            ;
            """
        )
    conn.commit()

def stageInitsTruncsAndUpdates(conn):
    LOGGING.debug("stageInitsTruncsAndUpdates()")
    with conn.cursor() as cur:
        cur.execute(
            """
            INSERT INTO
              stg.dimPersonRole (
                source_file_name,
                source_file_creation,
                externalreference_person,
                externalreference_role,
                effective_from,
                effective_stop,
                is_active,
                _staging_mode
              )
            (
              --------------------------------------------------------------------------------
              --------------------------------------------------------------------------------
              -- Entities that need initialising
              --------------------------------------------------------------------------------
              --------------------------------------------------------------------------------
              SELECT
                '<Initialise>',
                -2,
                externalreference_person,
                externalreference_role,
                0,
                MIN(effective_from),
                FALSE,
                'I'
              FROM
                stg.dimPersonRole
              WHERE
                    personID       IS     NULL  -- New Entity in need of initialisation
                AND effective_stop IS NOT NULL  -- Row not superceded by another staging row
                AND externalreference_role IS NOT NULL -- Is not a dummy record [see dimPerson.pushDeActivations()]
              GROUP BY
                externalreference_person,
                externalreference_role
              HAVING
                MIN(effective_from) >  0  -- Prevent zero length periods
              --------------------------------------------------------------------------------
            )
            ---------
            UNION ALL
            ---------
            (
              --------------------------------------------------------------------------------
              --------------------------------------------------------------------------------
              -- Associations then need updating (new association overlaps existing start)
              --------------------------------------------------------------------------------
              --------------------------------------------------------------------------------
              SELECT
                DISTINCT ON (
                  stg.externalreference_person,
                  stg.externalreference_role,
                  dim.effective_from
                )
                '<'
              || CASE WHEN dim.effective_from < stg.effective_from THEN 'Truncate'
                      WHEN dim.effective_stop > stg.effective_stop THEN 'Truncate'
                                                                  ELSE '' END
              || CASE WHEN dim.effective_from < stg.effective_from THEN ''
                                                                  ELSE 'Update' END
              || '>',
                -3,
                stg.externalreference_person,
                stg.externalreference_role,
                dim.effective_from,
                CASE WHEN dim.effective_from < stg.effective_from THEN stg.effective_from
                    WHEN dim.effective_stop > stg.effective_stop THEN stg.effective_stop
                                                                  ELSE dim.effective_stop END,
                CASE WHEN dim.effective_from < stg.effective_from THEN dim.is_active
                                                                  ELSE stg.is_active END,
                'U'
              FROM
                stg.dimPersonRole   AS stg
              INNER JOIN
                dim.dimPersonRole   AS dim
                  ON  dim.personID        = stg.personID
                  AND dim.roleID          = stg.roleID
                  AND dim.effective_from <  stg.effective_stop
                  AND dim.effective_stop  > stg.effective_from
                  AND dim.effective_from <> stg.effective_from  -- Don't create a duplicate record to update
              ORDER BY
                stg.externalreference_person,
                stg.externalreference_role,
                dim.effective_from,
                stg.effective_from
              --------------------------------------------------------------------------------
            );
            """
        )
    conn.commit()

def applyChanges(conn, source):
    if (source is None):
        cascadeActivations(conn, 'dimPersonRole')
        cascadeRetirements(conn, 'dimPersonRole')

    if (source != 'dimRole'):
        dimRole.applyChanges(conn, 'dimPersonRole')
    if (source != 'dimPerson'):
        dimPerson.applyChanges(conn, 'dimePersonRole')

    LOGGING.debug("applyChanges()")
    _applyChanges(conn)

def _applyChanges(conn):
    with conn.cursor() as cur:
        cur.execute(
            """
            DELETE FROM
              dim.dimPersonRole   d
            USING
              stg.dimPersonRole   s
            WHERE
                  s.PersonID      = d.PersonID
              AND s.RoleID        = d.RoleID
              AND s._staging_mode = 'D'
            ;

            INSERT INTO
              dim.dimPersonRole (
                PersonID,
                RoleID,
                effective_from,
                effective_stop,
                is_active
              )
            SELECT
              dp.id,
              dr.id,
              stg.effective_from,
              CASE WHEN stg.current_effective_stop < stg.effective_stop THEN stg.current_effective_stop ELSE stg.effective_stop END,
              stg.is_active
            FROM
              stg.dimPersonRole   stg
            INNER JOIN
              dim.DimPerson       dp
                ON dp.externalReference = stg.externalReference_Person
            INNER JOIN
              dim.DimRole         dr
                ON dr.externalReference = stg.externalReference_Role
            WHERE
              stg.effective_stop IS NOT NULL
            ON CONFLICT
              (
                personID,
                roleID,
                effective_from
              )
                DO UPDATE
                  SET effective_stop = EXCLUDED.effective_stop,
                      is_active      = EXCLUDED.is_active
            ;

            DELETE FROM
              stg.dimPersonRole
            ;
            """
        )
    conn.commit()


from django.contrib.auth import logout
from django.urls import path
from .views import *

urlpatterns = [
    path('', HomepageView.as_view(), name="home"),
    path('signup/', signup_view, name="signup"),
    path('login/', login_view, name="login"),
    path('logout/', logout_view, name="logout"),
    path('send_friend_request/<int:userID>/',
        send_friend_request, name="send_friend_request"),
    path('accept_friend_request/<int:requestID>/',
        accept_friend_request, name="accept_friend_request"),
    path('friends/', friend_list, name="friend_list"),
    path('remove_friend/<int:userID>/', remove_friend,
        name="remove_friend"),
]


import eg

eg.RegisterPlugin(
    name = "TechnoTrend USB IR Receiver",
    author = "Bitmonster",
    version = "1.1",
    kind = "remote",
    guid = "{66211720-B0DE-46E2-AD57-2D70F477DE02}",
    description = __doc__,
)

import os
from threading import Lock, Timer, Thread
from time import clock, sleep
from functools import partial

from eg.WinApi.Dynamic import (
    cdll, DWORD, POINTER, ULONG, HANDLE, BYTE, c_void_p, c_int, CFUNCTYPE, CDLL
)

USBIR_MODE_DIV = 2

# typedef void (*PIRCBFCN) (PVOID Context,
#                           PVOID Buf,
#                           ULONG len, // buffer length in bytes
#                           USBIR_MODES IRMode,
#                           HANDLE hOpen,
#                           BYTE DevIdx);
IRCALLBACKFUNC = CFUNCTYPE(
    c_void_p, # return type
    c_void_p, # Context
    POINTER(DWORD), # Buf
    ULONG, # len (buffer length in bytes)
    c_int, # IRMode (of enum USBIR_MODES)
    HANDLE, # hOpen
    BYTE # DevIdx
)

class TTIR(eg.IrDecoderPlugin):

    def __init__(self):
        eg.IrDecoderPlugin.__init__(self, 1)

    def __close__(self):
        self.irDecoder.Close()

    def __start__(self):
        self.dll = None
        self.hOpen = None
        pluginDir = os.path.abspath(os.path.dirname(__file__))
        dll = CDLL(os.path.join(pluginDir, "TTUSBIR.dll"))
        self.cCallback = IRCALLBACKFUNC(self.IrCallback)
        self.hOpen = dll.irOpen(0, USBIR_MODE_DIV, self.cCallback, 0)
        if self.hOpen == -1:
            raise self.Exceptions.DeviceNotFound
#        self.irGetUniqueCode = dll.ir_GetUniqueCode
#        self.irGetUniqueCode.restype  = DWORD
        self.dll = dll
        self.data = []
        self.timer = eg.ResettableTimer(self.OnTimeout)
        self.dataLock = Lock()
        self.lastTime = clock()
        self.startByte = 1
        self.dll.irSetPowerLED(self.hOpen, 0)
        self.ledTimer = eg.ResettableTimer(
            partial(self.dll.irSetPowerLED, self.hOpen, 0)
        )

    def OnComputerSuspend(self, dummySuspendType):
        self.dll.irClose(self.hOpen)

    def OnComputerResume(self, dummySuspendType):
        self.hOpen = self.dll.irOpen(
            0, USBIR_MODE_DIV, self.cCallback, 0
        )
        if self.hOpen == -1:
            raise self.Exceptions.DeviceNotFound

    def __stop__(self):
        if self.dll is not None:
            self.dll.irClose(self.hOpen)
            self.dll = None
            self.hOpen = None
            self.cCallback = None
        self.timer.Stop()
        self.ledTimer.Stop()

    def IrCallback(self, context, buf, length, irMode, hOpen, devIdx):
        if irMode == USBIR_MODE_DIV:
            self.dll.irSetPowerLED(self.hOpen, 1)
            self.ledTimer.Reset(1)
            self.timer.Reset(80)
            #self.lastTime = clock()
            self.dataLock.acquire()
            #print "---", length / 4, clock() - self.lastTime
            append = self.data.append
            for i in xrange(self.startByte, min(length/4, 500)):
                value = buf[i] & 0x00ffffff
                append(value)
                if value > 12000:
                    self.irDecoder.Decode(self.data, len(self.data))
                    self.data = []
                    append = self.data.append
            self.startByte = 0
            self.dataLock.release()

    def OnTimeout(self):
        if self.dataLock.acquire(0):
            data = self.data
            self.data = []
            self.startByte = 1
            self.dataLock.release()
            data.append(10000)
            self.irDecoder.Decode(data, len(data))


###############################################################################
# Auxiliary
#   Non-specific functions needed by routines
###############################################################################
import os
import warnings
import numpy as np
import matplotlib.colors as mcolors
warnings.filterwarnings("ignore")

def isnotebook():
    try:
        shell = get_ipython().__class__.__name__
        if shell == 'ZMQInteractiveShell':
            return True
        elif shell == 'TerminalInteractiveShell':
            return False
        else:
            return False
    except NameError:
        return False

def padList(lst, n):
    lst.extend([None] * n)
    lst = lst[:n]
    return lst

def removeBanned(lastfmData, bans, label='Artist'):
    return lastfmData[~lastfmData[label].isin(bans)]

def replace(dataframe, replacementDict, columnNames):
    (df, repDict, col) = (dataframe, replacementDict, columnNames)
    cats = sorted(list(repDict.keys()))
    for cat in cats:
        repSet = repDict[cat]
        df.loc[df[col[0]].isin(repSet), col[1]] = cat
    return df

def makeFolder(path):
    if not os.path.exists(path):
        try:
            os.mkdir(path)
        except OSError:
            raise OSError(
                "Can't create destination directory (%s)!" % (path)
            )

def colorPaletteFromHexList(clist):
    c = mcolors.ColorConverter().to_rgba
    clrs = [c(i) for i in clist]
    rvb = mcolors.LinearSegmentedColormap.from_list("", clrs)
    return rvb

def rollingAverage(x, w):
    return np.convolve(x, np.ones(w), 'valid') / w


from  rest_framework import serializers,status
from core.utils.exception import CustomValidation
from core.utils.helper_function import get_amount_by_percent
from ..models import monthly_salary_structure as models
from django.db import transaction
from career_path import models as career_path_models

class ListOfEmployeeReceivablesSerializer(serializers.Serializer):
    fixed_receivables_element= serializers.CharField()
    fixed_receivables_element_gross_percent= serializers.IntegerField()

class ListOfEmployeeOtherReceivablesSerializer(serializers.Serializer):
    other_receivables_element = serializers.CharField()
    other_receivables_element_gross_percent = serializers.IntegerField()
class ListOfEmployeeRegulatoryRecievablesSerializer(serializers.Serializer):
    regulatory_receivables= serializers.CharField()
    regulatory_receivables_gross_percent= serializers.IntegerField()
    regulatory_rates = serializers.IntegerField()

class ListOfEmployeeRegulatoryDeductablesSerializer(serializers.Serializer):
    regulatory_deductables= serializers.CharField()
    regulatory_deductables_gross_percent =serializers.IntegerField()
    regulatory_rates = serializers.IntegerField()

class ListOfEmployeeOtherDeductablesSerializer(serializers.Serializer):
    other_deductables= serializers.CharField()
    other_deductables_gross_percent =serializers.IntegerField()

class MonthSalaryStructureCreationSerializer(serializers.Serializer):
    "struture Style"
    structure_type = serializers.ChoiceField(choices=['monthly','daily','hourly'])
    rate =serializers.DecimalField(required=False,max_digits=20, decimal_places=2)
    number_of_work = serializers.IntegerField(required=False)

    grade_level = serializers.CharField()
    gross_money = serializers.DecimalField(max_digits=20, decimal_places=2)
    "Receivables"
    employee_receivables = ListOfEmployeeReceivablesSerializer(many=True)
    employee_regulatory_recievables =ListOfEmployeeRegulatoryRecievablesSerializer(many=True)
    employee_other_receivables  = ListOfEmployeeOtherReceivablesSerializer(many=True)

    "Deductables"
    employee_regulatory_deductables = ListOfEmployeeRegulatoryDeductablesSerializer(many=True)
    employee_other_deductables = ListOfEmployeeOtherDeductablesSerializer(many=True)

    def validate(self, attrs):
        structure_type = attrs.get('structure_type',None)
        rate=attrs.get('rate',None)
        number_of_work=attrs.get('number_of_work',None)

        if structure_type =='daily' or structure_type =='hourly':
            if rate is None:raise CustomValidation(
            detail=f'Rate  is required for {structure_type}',field='error',status_code=status.HTTP_400_BAD_REQUEST
            )
            if number_of_work is None:raise CustomValidation(
            detail=f'Number of work required for {structure_type}',field='error',status_code=status.HTTP_400_BAD_REQUEST
            )

        if not  self._validate_gross_percent(attrs): raise CustomValidation(
            detail='Total gross is ment to be 100%',field='error',status_code=status.HTTP_400_BAD_REQUEST
        )
        if not  career_path_models.CareerPath.objects.filter(career_path_id=attrs.get('grade_level')).exists():
            raise CustomValidation(detail='this level does not exist',field='grade_level',status_code=status.HTTP_400_BAD_REQUEST)
        else:
            'check if this career path exist in monthly payroll'
            career_path  = career_path_models.CareerPath.objects.get(career_path_id=attrs.get('grade_level'))
            if models.MonthlySalaryStructure.objects.filter(grade_level=career_path,structure_type=structure_type).exists():
                raise CustomValidation(detail='This level already has a Monthly Salary Payroll Strcuture',field='grade_level',status_code=status.HTTP_400_BAD_REQUEST)

        return super().validate(attrs)

    def _validate_gross_percent(self,attrs):

        def get_other_receivable_gross_percent(each_item):
            return each_item.get('other_receivables_element_gross_percent',0)
        def getfixed_receivables_element_gross_percent(each_item):
            return each_item.get('fixed_receivables_element_gross_percent',0)
        def getregulatory_receivables_gross_percent(each_item):
            return each_item.get('regulatory_receivables_gross_percent',0)
        def getregulatory_deductables_gross_percent(each_item):
            return each_item.get('regulatory_deductables_gross_percent',0)
        def getother_deductables_gross_percent(each_item):
            return each_item.get('other_deductables_gross_percent',0)

        "this validate if all the gross Receivables percent sum up to 100"

        list_of_gross = [
            sum(map(getfixed_receivables_element_gross_percent,attrs.get('employee_receivables'))),
            sum(map(getregulatory_receivables_gross_percent,attrs.get('employee_regulatory_recievables'))),
            sum(map(get_other_receivable_gross_percent,attrs.get('employee_other_receivables')))
            # sum(map(getregulatory_deductables_gross_percent,attrs.get('employee_regulatory_deductables'))),
            # sum(map(getother_deductables_gross_percent,attrs.get('employee_other_deductables'))),
        ]
        return sum(list_of_gross) ==100

    def create(self, validated_data):
        structure_type = validated_data.get('structure_type',None)
        rate=validated_data.get('rate',None)
        number_of_work=validated_data.get('number_of_work',None)
        grade_level = validated_data.get('grade_level')
        gross_money = validated_data.get('gross_money')
        employee_receivables = validated_data.get('employee_receivables',[])
        employee_regulatory_recievables = validated_data.get('employee_regulatory_recievables',[])
        employee_regulatory_deductables = validated_data.get('employee_regulatory_deductables',[])
        employee_other_deductables = validated_data.get('employee_other_deductables',[])
        employee_other_receivables= validated_data.get('employee_other_receivables',[])
        carer_path = career_path_models.CareerPath.objects.get(career_path_id=grade_level)
        "first we need to create MonthlySalaryStructure"
        monthlysalarystructureinstance = models.MonthlySalaryStructure.objects.create(
            grade_level=carer_path,
            gross_money=gross_money,
        )
        if structure_type =='daily' or structure_type =='hourly':
            monthlysalarystructureinstance.structure_type=structure_type
            monthlysalarystructureinstance.rate=rate
            monthlysalarystructureinstance.number_of_work=number_of_work
            monthlysalarystructureinstance.gross_money = monthlysalarystructureinstance.cal_gross_money()
            monthlysalarystructureinstance.save()
        "bulk create receivables "
        self.bulkCreateEmployeeReceivables(monthlysalarystructureinstance,employee_receivables)
        self.bulkCreateEmployeeRegulatoryRecievables(monthlysalarystructureinstance,employee_regulatory_recievables)
        self.bulkCreateEmployeeOtherReceivable(monthlysalarystructureinstance,employee_other_receivables)
        "bulk create deductables"
        self.bulkCreateEmployeeRegulatoryDeductable(monthlysalarystructureinstance,employee_regulatory_deductables)
        self.bulkCreateEmployeeOtherDeductables(monthlysalarystructureinstance,employee_other_deductables)
        return monthlysalarystructureinstance

    def bulkCreateEmployeeOtherReceivable(self,monthlysalarystructureinstance,employee_other_receivables:list):
        with transaction.atomic():
            for data in employee_other_receivables:
                instance= models.EmployeeOtherReceivables(
                    monthly_salary_structure=monthlysalarystructureinstance,
                    other_receivables_element=data.get('other_receivables_element','null'),
                    other_receivables_element_gross_percent=data.get('other_receivables_element_gross_percent',0),
                    value=get_amount_by_percent(
                        data.get('other_receivables_element_gross_percent',0),monthlysalarystructureinstance.gross_money
                    )
                )
                instance.save()
    def bulkCreateEmployeeReceivables(self,monthlysalarystructureinstance,employee_receivables:list):
        with transaction.atomic():
            for data in employee_receivables:
                instance = models.EmployeeReceivables(
                    monthly_salary_structure=monthlysalarystructureinstance,
                    fixed_receivables_element=data.get('fixed_receivables_element','null'),
                    fixed_receivables_element_gross_percent=data.get('fixed_receivables_element_gross_percent',0),
                    value = get_amount_by_percent(
                        data.get('fixed_receivables_element_gross_percent',0),monthlysalarystructureinstance.gross_money)
                )
                instance.save()

    def bulkCreateEmployeeRegulatoryRecievables(self,monthlysalarystructureinstance,employee_regulatory_recievables:list):

        with transaction.atomic():
            for data in employee_regulatory_recievables:
                instance = models.EmployeeRegulatoryRecievables(
                    monthly_salary_structure=monthlysalarystructureinstance,
                    Employee_regulatory_recievables=data.get('regulatory_receivables',"null"),
                    Employee_regulatory_recievables_gross_percent=data.get('regulatory_receivables_gross_percent',0.00),
                    regulatory_rates=data.get('regulatory_rates',0.00),
                    value = get_amount_by_percent(
                        data.get('regulatory_receivables_gross_percent',0),monthlysalarystructureinstance.gross_money)
                )
                instance.save()

    def bulkCreateEmployeeRegulatoryDeductable(self,monthlysalarystructureinstance,employee_regulatory_deductables:list):
            with transaction.atomic():
                for data in employee_regulatory_deductables:
                    instance = models.EmployeeRegulatoryDeductables(
                        monthly_salary_structure=monthlysalarystructureinstance,
                        Employee_regulatory_deductables=data.get('regulatory_deductables','null'),
                        Employee_regulatory_deductables_gross_percent=data.get('regulatory_deductables_gross_percent',0.00),
                        regulatory_rates=data.get('regulatory_rates',0.00),
                        value = get_amount_by_percent(
                        data.get('regulatory_deductables_gross_percent',0),monthlysalarystructureinstance.gross_money)
                    )
                    instance.save()

    def bulkCreateEmployeeOtherDeductables(self,monthlysalarystructureinstance,employee_other_deductables:list):
        with transaction.atomic():
            for data in employee_other_deductables:
                instance = models.EmployeeOtherDeductables(
                        monthly_salary_structure=monthlysalarystructureinstance,
                        Employee_other_deductables= data.get('other_deductables',"null"),
                        Employee_other_deductables_gross_percent=data.get('other_deductables_gross_percent',0.00),
                        value = get_amount_by_percent(
                        data.get('other_deductables_gross_percent',0),monthlysalarystructureinstance.gross_money)
                )
                instance.save()

class  MonthSalaryStructureCleanerSerializer(serializers.ModelSerializer):

    employee_receivables = serializers.SerializerMethodField()
    employee_regulatory_recievables = serializers.SerializerMethodField()
    employee_regulatory_deductables = serializers.SerializerMethodField()
    employee_other_deductables = serializers.SerializerMethodField()
    employee_other_receivables = serializers.SerializerMethodField()

    def get_employee_other_receivables(self,MonthlySalaryInstance):
        return models.EmployeeOtherReceivables.objects.filter(monthly_salary_structure=MonthlySalaryInstance).values(
            'other_receivables_element',
            'other_receivables_element_gross_percent','value')
    def get_employee_receivables(self,MonthlySalaryInstance):
        return models.EmployeeReceivables.objects.filter(monthly_salary_structure=MonthlySalaryInstance).values(
            'fixed_receivables_element','fixed_receivables_element_gross_percent','value'
        )

    def get_employee_regulatory_recievables(self,MonthlySalaryInstance):
        return models.EmployeeRegulatoryRecievables.objects.filter(monthly_salary_structure=MonthlySalaryInstance).values(
            'Employee_regulatory_recievables','Employee_regulatory_recievables_gross_percent','regulatory_rates',
            'value'
        )

    def get_employee_regulatory_deductables(self,MonthlySalaryInstance):
        return models.EmployeeRegulatoryDeductables.objects.filter(monthly_salary_structure=MonthlySalaryInstance).values(
            'Employee_regulatory_deductables','Employee_regulatory_deductables_gross_percent','regulatory_rates',
            'value'
        )

    def get_employee_other_deductables(self,MonthlySalaryInstance):
        return models.EmployeeOtherDeductables.objects.filter(monthly_salary_structure=MonthlySalaryInstance).values(
            'Employee_other_deductables','Employee_other_deductables_gross_percent','value',
        )
    class Meta:
        fields = "__all__"
        model = models.MonthlySalaryStructure


# importing all required modules
import tkinter as tk
from tkinter import END
from tkinter.filedialog import askopenfilename
from tkcalendar import Calendar
import CSVparsing
import ftp_connect
import displayCSV
import os
import shutil

class App:
    """
    CREATING UI, largely created by Adam D
    """
    def __init__(self):
        """
        CONFIGURING WINDOW
        """

        # defining widgets
        self.calendar = None
        self.btn_upload = None
        self.btn_choose_file = None
        self.scrollbar = None
        self.dropDown = None
        self.entries_to_use = None
        self.frm_scroll_box = None
        self.btn_view = None
        self.btn_today = None
        self.btn_filter = None
        self.ent_filter = None
        self.lbl_filter = None
        self.frm_filter = None

        # creates window
        self.window = tk.Tk()
        self.window.title("Medical Data")

        # configures grid layout
        self.window.rowconfigure(0, minsize=250, weight=1)
        self.window.rowconfigure(1, minsize=100, weight=1)
        self.window.columnconfigure(0, minsize=230, weight=1)
        self.window.columnconfigure(1, minsize=100, weight=1)
        self.window.columnconfigure(2, minsize=100, weight=1)
        self.init_ui()

    def init_ui(self):
        """
        CREATING WIDGETS
        """
        # configuring filter widgets
        self.frm_filter = tk.Frame(master=self.window)
        self.lbl_filter = tk.Label(master=self.frm_filter,
                                   text="Filter by Date")
        """calendar code created by team"""
        self.btn_filter = \
            tk.Button(
                master=self.frm_filter,
                text="Get Date",
                command=self.get_date
            )
        # creating calendar widget
        self.calendar = Calendar(master=self.frm_filter,
                                 selectmode="day")
        """end of calendar code"""

        # other button widgets
        self.btn_view = tk.Button(
            master=self.window,
            text="View Selected File",
            command=self.selectedItemOutput
        )

        # configuring scrollable list
        self.frm_scroll_box = tk.Frame(master=self.window)
        self.dropDown = tk.Listbox(self.frm_scroll_box)
        self.scrollbar = tk.Scrollbar(self.frm_scroll_box)
        self.dropDown.config(yscrollcommand=self.scrollbar.set)

        # configuring file upload widgets
        self.btn_choose_file = tk.Button(
            master=self.window,
            text="Choose File",
            command=self.choose_file
        )
        self.btn_upload = tk.Button(
            master=self.window,
            text="Upload"
            # command=
        )

        """
        CREATING WIDGET LAYOUT
        """
        # laying out widgets on the main window
        self.frm_scroll_box.grid(row=0, column=0)
        self.frm_filter.grid(row=0, column=1, columnspan=2, padx=5, pady=5)
        self.btn_view.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
        self.btn_choose_file.grid(row=1, column=1, sticky="nsew", padx=5, pady=10)
        self.btn_upload.grid(row=1, column=2, sticky="nsew", padx=10, pady=10)

        # laying out filtering widgets within frm_filter
        self.lbl_filter.grid(row=0)
        self.calendar.grid(row=1)
        self.btn_filter.grid(row=2, padx=5, pady=5, sticky="nsew")

        # laying out scrollable list widgets within frm_scroll_box
        self.scrollbar.pack(side=tk.RIGHT, fill="y")
        self.dropDown.pack(side=tk.LEFT, fill="y")

    """
    FUNCTIONS, largely created by Harry A and Sunil S
    """

    """
    when choose file button is clicked, a dialogue box opens
    which allows the user to select a file, the filepath is returned
    """
    def choose_file(self):
        # user selects filepath from dialogue window
        filepath = askopenfilename(filetypes=(("csv files", "*.csv"),))
        # if no file path is selected, nothing happens
        if not filepath:
            return
        # changes text of button to display the filepath
        self.btn_choose_file["text"] = filepath
        # returns the filepath
        return filepath

    """
    Once the get_Date button is pressed the validated files
    are grabbed from the server and added to the dropdown list
    """
    def get_date(self):

        self.outListItems = []
        date_string = self.calendar.selection_get()
        date_string = str(date_string).replace("-", "")
        try:
            itemList = ftp_connect.ftp_fetch()  # validation to check if there is a connection to FTP
        except:
            print("Couldnt connect to FTP Server, is config up to date? or is server running?")
            exit(0)

        for items in itemList:
            if CSVparsing.validateFilename(items):
                if str(date_string) in str(items):
                    os.makedirs("tempFTPDownload/", exist_ok=True)
                    ftp_connect.ftp_pull(items, "tempFTPDownload/" + str(items))
                    if CSVparsing.masterValidate("tempFTPDownload/",
                                                 items):  # Validates all files before adding them to Show List
                        os.makedirs("FTPDownload/" + str(date_string[:4]) + "/" + str(date_string[4:6]) + "/" + str(date_string[6:8]), exist_ok=True)
                        self.outListItems.append(items)

        if len(self.outListItems) != 0:
            for files in self.outListItems:
                os.rename("tempFTPDownload/" + files,
                          "FTPDownload/" + files[9:13] + "/" + files[13:15] + "/" + files[15:17] + "/" + files)
            shutil.rmtree("tempFTPDownload")
        self.putInDropDown(self.outListItems)

    """
    Adds all the valid files to the drop down list in the UI
    """
    def putInDropDown(self, validFilesList):
        self.dropDown.delete(0, tk.END)
        for val in validFilesList:
            self.dropDown.insert(END, val)

    """
    Method outputs the given selected file into a Tkinter GUI for easy user reading
    """
    def selectedItemOutput(self):
        self.fileToOutput = ""
        for item in self.dropDown.curselection():
            self.fileToOutput = self.dropDown.get(item)
        ftp_connect.ftp_pull(self.fileToOutput, "FTPDownload/" + self.fileToOutput[9:13] + "/"
                             + self.fileToOutput[13:15] + "/" + self.fileToOutput[15:17] + "/" + self.fileToOutput)  # Creates a temp file to store Pulled FTP CSV data
        outputObj = displayCSV.DisplayCSV("FTPDownload/" + self.fileToOutput[9:13] + "/" +
                                          self.fileToOutput[13:15] + "/" + self.fileToOutput[15:17] + "/" + self.fileToOutput)

"""
LAUNCHING UI
"""
def launch_gui():
    app = App()  # Launches the Tkinter UI
    app.window.mainloop()

if __name__ == "__main__":
    launch_gui()