#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, platform
import tkinter as tk
import tkinter.font as tkFont
import threading
import socket
import random
import keyboard
import json

from player import OwnPlayer, OnlinePlayer, Target
from env import Env
from config import Config
from interface import Interface, ChatInfo
from client import Client
from render import Canvas
from map.map import Map

GAME_NAME = '2PQSTD'
config_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ressources/config/config.json')
ROLES = [('Assault', 'A'), ('Shotgun', 'SG'), ('Sniper', 'S'), ('SMG', 'SMG'), ('Rayon', 'R')]

FULLSCREEN = False
MAP = 'full_map_3.compile.map'

class App:
    def __init__(self, player_name, role):
        self.name = player_name
        self.role = role
        self.fen = tk.Tk()
        self.config = Config(config_path)
        self.map = Map(MAP, 'map')
        self.canvas = Canvas(self.fen, self.map.width, self.map.height)
        self.env = Env(self.fen, self.map, self.canvas, max_framerate=self.config.get('max_framerate'))
        self.player = OwnPlayer(0, 50, 50, self.env, self.name, self.role)
        self.player.bind_keys(self.config.get('key_binding'))
        self.interface = Interface(self.player, self.env)
        self.chat = ChatInfo(self.env)

    def start(self):
        self.fen.state("zoomed")
        if FULLSCREEN:
            self.fen.wm_attributes('-fullscreen', 'true')
        self.env.update()
        self.fen.mainloop()

class LocalGame(App):
    def __init__(self, player_name, difficulty, role):
        App.__init__(self, player_name, role)
        self.difficulty = difficulty
        self.entry = None
        self.fen.title(GAME_NAME + ' - Local')
        self.fen.bind('<Key-g>', self.restart)

    def restart(self, *event): ## Doesn't work
        if self.env.command_entry_focus: return
        self.env.exit()
        self.start()

    def generate_target(self):
        if self.difficulty == 1:
            Target(1, 400, 250, self.env, level=1)
        else:
            for i in range(self.difficulty):
                Target(i, random.randint(150, self.map.width - 150), random.randint(150, self.map.height - 150), self.env, level=self.difficulty)

class OnlineGame(App):
    def __init__(self, player_name, role):
        App.__init__(self, player_name, role)
        self.connection = None
        self.client = None
        self.fen.title(GAME_NAME + ' - Multi')

    def connect(self, ip, port):
        self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client = Client(self.connection, self.player, ip, port)
        self.client.send_connection_info()
        self.client.start()

class SplashScreen:
    def __init__(self, online_callback, offline_callback, settings_callback):
        self.fen = tk.Tk()
        self.config = Config(config_path)
        self.online_callback = online_callback
        self.offline_callback = offline_callback
        self.settings_callback = settings_callback
        self.path = os.path.dirname(os.path.realpath(__file__))

    def create_window(self):
        self.fen.title('Bienvenue dans ' + GAME_NAME)
        self.fen.attributes('-topmost', True)
        self.width, self.height = self.fen.winfo_screenwidth(), self.fen.winfo_screenheight()
        L, H = self.width / 3, self.height / 2
        X, Y = (self.width - L) / 2, (self.height - H) / 2
        self.fen.geometry('%dx%d%+d%+d' % (L,H,X,Y))
        self.fen.resizable(width=False, height=False)

        ## Style
        title_font = tkFont.Font(family='Avenir Next', size=35, weight='bold')
        subtitle_font = tkFont.Font(family='Avenir Next', size=22, weight='normal')
        regular_font = tkFont.Font(family='Avenir Next', size=15, weight='normal')

        title = tk.Label(self.fen, text='Bienvenue dans ' + GAME_NAME, font=title_font)
        subtitle = tk.Label(self.fen, text='Sélectionnez le mode de jeu : ', font=subtitle_font)

        name_var = tk.StringVar(self.fen, value=self.config.get('default_name'))
        difficulty_var = tk.IntVar(self.fen, value=self.config.get('default_difficulty'))

        name_label = tk.Label(self.fen, text='Nom : ', font=regular_font)
        name_entry = tk.Entry(self.fen, textvariable=name_var, width=20)

        role_label = tk.Label(self.fen, text='Role : ', font=regular_font)
        role_list = []
        selected_role = tk.StringVar()
        selected_role.set(self.config.get('default_role'))
        for (role, value) in ROLES:
            check_box = tk.Radiobutton(self.fen, text=role, value=value, variable=selected_role,
                                        indicatoron=0, width=10, pady=4, selectcolor='blue', relief=tk.SUNKEN)
            role_list.append(check_box)

        difficulty_label = tk.Label(self.fen, text='Difficultée : ', font=regular_font)
        difficulty_scale = tk.Scale(self.fen, variable=difficulty_var, orient='horizontal', from_=0, to=10, resolution=1, length=200, relief=tk.FLAT)

        PvE_button = tk.Button(self.fen, text='Local', command=lambda: handle_click('PvE'), padx=30, pady=5, relief=tk.FLAT)
        PvP_button = tk.Button(self.fen, text='Multi', command=lambda: handle_click('PvP'), padx=30, pady=5, relief=tk.FLAT)

        settings_icon = tk.PhotoImage(file='{}/ressources/open_file.gif'.format(self.path))
        settings = tk.Button(self.fen, text='Settings', relief=tk.FLAT, padx=15, pady=5, command=lambda: self.settings_callback(self))

        ## LAYOUT ##
        title.place(relx=0.5, rely=0.1, anchor=tk.CENTER)
        subtitle.place(relx=0.5, rely=0.22, anchor=tk.CENTER)

        name_label.place(relx=0.1, rely=0.42, anchor=tk.W)
        name_entry.place(relx=0.8, rely=0.42, anchor=tk.E)

        role_label.place(relx=0.1, rely=0.52, anchor=tk.W)
        role_width = 0.9/len(ROLES)
        for (index, role) in enumerate(role_list):
            role.place(relx=0.05 + index*role_width, rely=0.60, anchor=tk.W)

        difficulty_label.place(relx=0.1, rely=0.74, anchor=tk.W)
        difficulty_scale.place(relx=0.8, rely=0.71, anchor=tk.E)

        PvE_button.place(relx=0.3, rely=0.9, anchor=tk.W)
        PvP_button.place(relx=0.7, rely=0.9, anchor=tk.E)

        settings.place(relx= 0.9, rely=0.9, anchor=tk.CENTER)

        def handle_click(mode):
            self.fen.destroy()
            if mode == 'PvE':
                self.offline_callback(name_var.get(), difficulty_var.get(), selected_role.get())
            elif mode == 'PvP':
                self.online_callback(name_var.get(), self.config.get('server_ip'), int(self.config.get('server_port')), selected_role.get())

    def start(self):
        self.fen.mainloop()

class Settings:
    def __init__(self, parent):
        self.parent = parent
        self.config = Config(config_path)
        self.new_config = {}
        self.platform = platform.system()
        self.path = os.path.dirname(os.path.realpath(__file__))
        self.create_window()

    def create_window(self):
        self.fen = tk.Toplevel()
        width, height = self.fen.winfo_screenwidth(), self.fen.winfo_screenheight()
        L, H = width / 2.5, height / 2
        X, Y = (width - L) / 2, (height - H) / 2
        self.fen.geometry('%dx%d%+d%+d' % (L,H,X,Y))

        ## Style
        title_font = tkFont.Font(family='Avenir Next', size=30, weight='bold')
        subtitle_font = tkFont.Font(family='Avenir Next', size=20, weight='normal')
        regular_font = tkFont.Font(family='Avenir Next', size=15, weight='normal')

        max_framerate = tk.IntVar(self.fen, value=self.config.get('max_framerate'))
        default_difficulty = tk.IntVar(self.fen, value=self.config.get('default_difficulty'))
        default_role = tk.StringVar(self.fen, value=self.config.get('default_role'))
        default_ip = tk.StringVar(self.fen, value=self.config.get('server_ip'))
        default_port = tk.IntVar(self.fen, value=self.config.get('server_port'))
        default_name = tk.StringVar(self.fen, value=self.config.get('default_name'))

        title = tk.Label(self.fen, text='Paramètres', font=title_font)
        max_framerate_label = tk.Label(self.fen, text='Framerate Maximum (fps)')
        default_difficulty_label = tk.Label(self.fen, text='Difficulté par défaut (1-10)')
        default_role_label = tk.Label(self.fen, text='Role par défaut')
        default_name_label = tk.Label(self.fen, text='Nom')
        default_ip_label = tk.Label(self.fen, text='Adresse IP par défaut')
        default_port_label = tk.Label(self.fen, text='Port par défaut')

        def validate():
            self.config.set('max_framerate', max_framerate.get())
            self.config.set('default_difficulty', default_difficulty.get())
            self.config.set('default_role', default_role.get())
            self.config.set('server_ip', default_ip.get())
            self.config.set('server_port', default_port.get())
            self.config.set('default_name', default_name.get())
            self.config.save()
            self.parent.create_window()
            self.fen.destroy()

        max_framerate_entry = tk.Entry(self.fen, textvariable=max_framerate)
        default_difficulty_entry = tk.Entry(self.fen, textvariable=default_difficulty)
        default_name_entry = tk.Entry(self.fen, textvariable=default_name)
        default_ip_entry = tk.Entry(self.fen, textvariable=default_ip)
        default_port_entry = tk.Entry(self.fen, textvariable=default_port)
        keybinding = tk.Button(self.fen, text='Key Bind', command=self.setup_keybind, padx=20, pady=5, relief=tk.FLAT)
        valider = tk.Button(self.fen, text='Valider', command=validate, padx=20, pady=5, relief=tk.FLAT)

        role_list = []
        for (role, value) in ROLES:
            check_box = tk.Radiobutton(self.fen, text=role, value=value, variable=default_role,
                                        indicatoron=0, width=7, pady=2, selectcolor='blue', relief=tk.SUNKEN)
            role_list.append(check_box)

        ## LAYOUT ##
        title.place(relx=0.5, rely=0.1, anchor=tk.CENTER)
        default_name_label.place(relx=0.1, rely=0.3, anchor=tk.W)
        default_difficulty_label.place(relx=0.1, rely=0.4, anchor=tk.W)
        default_role_label.place(relx=0.1, rely=0.5, anchor=tk.W)
        default_ip_label.place(relx=0.1, rely=0.6, anchor=tk.W)
        default_port_label.place(relx=0.1, rely=0.7, anchor=tk.W)
        max_framerate_label.place(relx=0.1, rely=0.8, anchor=tk.W)

        default_name_entry.place(relx=0.9, rely=0.3, anchor=tk.E)
        default_difficulty_entry.place(relx=0.9, rely=0.4, anchor=tk.E)
        default_ip_entry.place(relx=0.9, rely=0.6, anchor=tk.E)
        default_port_entry.place(relx=0.9, rely=0.7, anchor=tk.E)
        max_framerate_entry.place(relx=0.9, rely=0.8, anchor=tk.E)
        keybinding.place(relx=0.6, rely=0.9, anchor=tk.CENTER)
        valider.place(relx=0.4, rely=0.9, anchor=tk.CENTER)

        role_width = 0.6/len(ROLES)
        for (index, role) in enumerate(role_list):
            role.place(relx=0.35 + index*role_width, rely=0.5, anchor=tk.W)

        self.fen.mainloop()

    def setup_keybind(self):
        self.key_fen = tk.Toplevel(self.fen)
        width, height = self.fen.winfo_screenwidth(), self.fen.winfo_screenheight()
        L, H = width / 2, height / 1.8
        X, Y = (width - L) / 2, (height - H) / 2
        self.key_fen.geometry('%dx%d%+d%+d' % (L, H, X, Y))
        self.update_key_bind()

    def update_key_bind(self):
        for widget in self.key_fen.winfo_children():
            widget.place_forget()
        labels = {
            'up': 'Avancer',
    		'down': 'Reculer',
    		'left': 'Gauche',
    		'right': 'Droite',
    		'dash': 'Dash',
    		'melee': 'Coup de mêlée',
    		'reload': 'Recharger',
    		'panic': 'Panique',
            'dash_preview': 'Dash Preview',
    		'help': 'Aide'
        }
        for id, key in enumerate(self.config.get('key_binding', True).keys()):
            if key in labels.keys():
                self.create_key_bind(key, labels[key], id)

        tk.Button(self.key_fen, text='Valider', command=self.validate, padx=15, pady=2, relief=tk.FLAT).place(relx=0.4, rely=0.9, anchor=tk.CENTER)
        tk.Button(self.key_fen, text='Défaut', command=self.default, padx=15, pady=2, relief=tk.FLAT).place(relx=0.6, rely=0.9, anchor=tk.CENTER)

    def create_key_bind(self, key, label, id):
        offset_height = 0.65
        key_text = 'Shift' if self.config.get('key_binding', True)[key] == 56 else str(self.config.get('key_binding', True)[key]).capitalize()
        tk.Label(self.key_fen, text=label).place(relx=0.1, rely=(id + offset_height)/10, anchor=tk.W)
        tk.Button(self.key_fen, text=key_text, command=lambda: self.detect_keypress(key), width=10).place(relx=0.9, rely=(id + offset_height)/10, anchor=tk.E)

    def detect_keypress(self, key):
        new_key = keyboard.read_key()
        if self.platform == 'Darwin' and new_key == 'shift':
            new_key = 56
        self.config.set(f'key_binding.{key}', new_key)
        self.update_key_bind()

    def default(self):
        with open(os.path.join(self.path, 'ressources/config/config_default.json'), 'r') as default:
            self.new_config['key_binding'] = json.load(default)['key_binding']
        self.update_key_bind()

    def validate(self):
        self.config.save()
        self.fen.destroy()


import random

class SkipListNode(object):
    def __init__(self, val, high=1):
        # 节点存储的值
        self.data = val
        # 节点对应索引层的深度
        self.deeps = [None] * high

class SkipList(object):
    """
        An implementation of skip list.
        The list stores positive integers without duplicates.
        跳表的一种实现方法。
        跳表中储存的是正整数，并且储存的是不重复的。
        Author: Ben
    """

    def __init__(self):
        # 索引层的最大深度
        self.__MAX_LEVEL = 16
        # 跳表的高度
        self._high = 1
        # 每一索引层的首节点, 默认值为None
        self._head = SkipListNode(None, self.__MAX_LEVEL)

    def find(self, val):
        cur = self._head
        # 从索引的顶层, 逐层定位要查找的值
        # 索引层上下是对应的, 下层的起点是上一个索引层中小于插入值的最大值对应的节点
        for i in range(self._high - 1, -1, -1):
            # 同一索引层内, 查找小于插入值的最大值对应的节点
            while cur.deeps[i] and cur.deeps[i].data < val:
                cur = cur.deeps[i]

        if cur.deeps[0] and cur.deeps[0].data == val:
            return cur.deeps[0]
        return None

    def insert(self, val):
        '''
        新增时, 通过随机函数获取要更新的索引层数,
        要对低于给定高度的索引层添加新结点的指针
        '''
        high = self.randomLevel()
        if self._high < high:
            self._high = high
        # 申请新结点
        newNode = SkipListNode(val, high)
        # cache用来缓存对应索引层中小于插入值的最大节点
        cache = [self._head] * high
        cur = self._head

        # 在低于随机高度的每一个索引层寻找小于插入值的节点
        for i in range(high - 1, -1, -1):
            # 每个索引层内寻找小于带插入值的节点
            # ! 索引层上下是对应的, 下层的起点是上一个索引层中小于插入值的最大值对应的节点
            while cur.deeps[i] and cur.deeps[i].data < val:
                cur = cur.deeps[i]
            cache[i] = cur

        # 在小于高度的每个索引层中插入新结点
        for i in range(high):
            # new.next = prev.next \ prev.next = new.next
            newNode.deeps[i] = cache[i].deeps[i]
            cache[i].deeps[i] = newNode

    def delete(self, val):
        '''
        删除时, 要将每个索引层中对应的节点都删掉
        '''
        # cache用来缓存对应索引层中小于插入值的最大节点
        cache = [None] * self._high
        cur = self._head
        # 缓存每一个索引层定位小于插入值的节点
        for i in range(self._high - 1, -1, -1):
            while cur.deeps[i] and cur.deeps[i].data < val:
                cur = cur.deeps[i]
            cache[i] = cur
        # 如果给定的值存在, 更新索引层中对应的节点
        if cur.deeps[0] and cur.deeps[0].data == val:
            for i in range(self._high):
                if cache[i].deeps[i] and cache[i].deeps[i].data == val:
                    cache[i].deeps[i] = cache[i].deeps[i].deeps[i]

    def randomLevel(self, p=0.25):
        '''
        #define ZSKIPLIST_P 0.25      /* Skiplist P = 1/4 */
        https://github.com/antirez/redis/blob/unstable/src/t_zset.c
        '''
        high = 1
        for _ in range(self.__MAX_LEVEL - 1):
            if random.random() < p:
                high += 1
        return high

    def __repr__(self):
        vals = []
        p = self._head
        while p.deeps[0]:
            vals.append(str(p.deeps[0].data))
            p = p.deeps[0]
        return '->'.join(vals)

if __name__ == '__main__':
    sl = SkipList()
    for i in range(100):
        sl.insert(i)
    print(sl)
    p = sl.find(7)
    print(p.data)
    sl.delete(37)
    print(sl)
    sl.delete(37.5)
    print(sl)


from pyspark import SparkConf, SparkContext

# Declaring the spark variables
conf = SparkConf().setMaster("local").setAppName("Customer-Spark")
sc = SparkContext(conf=conf)

def parseLine(line):
    fields = line.split(',')
    customerID = int(fields[0])
    dollarAmount = float(fields[2])
    return customerID, dollarAmount

lines = sc.textFile("customer-orders.csv")
parsedLine = lines.map(parseLine)
# customerInfo = parsedLine.mapValues(lambda x: (x, 1)).reduceByKey(lambda x, y: (x[0] + y[0], x[1] + y[1]))
cinfo = lines.map(parseLine)
# dollarPerCustomer = customerInfo.mapValues(lambda x: x[0] + x[1])
dpc = cinfo.reduceByKey(lambda x, y: x + y)
# results = dollarPerCustomer.collect()

resultsFlipped = dpc.map(lambda x: (x[1], x[0]))
total = resultsFlipped.sortByKey()

results = total.collect()
for result in results:
    print(result)


from flask import Flask
from flask_socketio import SocketIO, emit, join_room, leave_room
from flask import Blueprint, jsonify, request, session
import time

app = Flask(__name__, static_url_path='/static',)
socketio = SocketIO(app, message_queue='redis://redis:6379')

CHANNELS = [f"channel{i}" for i in range(1000)]

USERS = [f"user{i}" for i in range(1000)]

MEMBERS = [f"member{i}" for i in range(1000)]

def timed(func):
    def wrapper(*args, **kwargs):
        start = time.time_ns()
        func(*args, **kwargs)
        end = time.time_ns()
        print(f"event {func.__name__} processes in ms", (end - start) // 1_000_000)
    return wrapper

@socketio.on('connect')
@timed
def on_connect():
    userId = request.headers.get("Authorization", None)
    for channel in CHANNELS:
        join_room(channel)

    for user in USERS:
        join_room(user)

    for member in MEMBERS:
        join_room(member)

    emit('onUserUpdated', {"userId": userId, "online": True}, room=userId)

@socketio.on('disconnect')
@timed
def on_disconnect():
    userId = request.headers.get("Authorization", None)
    emit('onUserUpdated', {"userId": userId, "online": False}, room=userId)

@socketio.on('sendMessage')
@timed
def send_message(data):
    emit('onMessageReceived', data, room=data["channel"])

@socketio.on('subscribeChannels')
@timed
def subscribe_channels(channels):
    start = time.time_ns()

    for channel in CHANNELS:
        if channel in channels["channels"]:
            print("joining room", channel)
            join_room(channel)
        else:
            leave_room(channel)

    end = time.time_ns()
    print("subscribed to channels", channels["channels"], (end - start) // 1_000_000)

@app.route('/')
def index():
    return 'Index Page'


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 11 12:24:04 2020

@author: vall
"""

import numpy as np
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
import matplotlib.pylab as plab
import os
import v_save as vs
import v_utilities as vu

english = False
trs = vu.BilingualManager(english=english)

#%% PARAMETERS

# Saving directories
folder = ["Scattering/AuSphere/AllVacTest/7)Diameters/WLen4560",
          "Scattering/AuSphere/AllVacTest/7)Diameters/WLen4560"]
home = vs.get_home()

# Sorting and labelling data series
sorting_function = [vu.sort_by_number, vu.sort_by_number]
series_label = [lambda s : f"Meep {vu.find_numbers(s)[0]} nm",
                lambda s : f"Mie {vu.find_numbers(s)[0]} nm"]
series_label = [lambda s : trs.choose("MEEP Data", "Datos MEEP") + f" {vu.find_numbers(s)[0]} nm",
                lambda s : trs.choose("Mie Theory", "Teoría Mie") + f" {vu.find_numbers(s)[0]} nm",]
series_must = ["SC", "SC"] # leave "" per default
series_column = [1, 2]

# Scattering plot options
plot_title = trs.choose("Scattering for Au spheres of different diameters in vacuum",
                        "Dispersión de esferas de Au de diferentes diámetros en vacío")
series_colors = [plab.cm.Reds, plab.cm.Reds]
series_linestyles = ["solid", "dashed"]
plot_make_big = True
plot_file = lambda n : os.path.join(home, "DataAnalysis", n)

#%% LOAD DATA

path = []
file = []
series = []
data = []
params = []
header = []

for f, sf, sm in zip(folder, sorting_function, series_must):

    path.append( os.path.join(home, f) )
    file.append( lambda f, s : os.path.join(path[-1], f, s) )

    series.append( os.listdir(path[-1]) )
    series[-1] = vu.filter_to_only_directories(series[-1])
    series[-1] = vu.filter_by_string_must(series[-1], sm)
    series[-1] = sf(series[-1])

    data.append( [] )
    params.append( [] )
    for s in series[-1]:
        data[-1].append(np.loadtxt(file[-1](s, "Results.txt")))
        params[-1].append(vs.retrieve_footer(file[-1](s, "Results.txt")))
    header.append( vs.retrieve_header(file[-1](s, "Results.txt")) )

    for i in range(len(params[-1])):
        if not isinstance(params[-1][i], dict):
            params[-1][i] = vu.fix_params_dict(params[-1][i])

    # r = [p["r"] for p in params]
    # from_um_factor = [p["from_um_factor"] for p in params]

#%% GET MAX WAVELENGTH

max_wlen = []
for d, sc in zip(data, series_column):
    max_wlen.append( [d[i][np.argmax(d[i][:,sc]), 0] for i in range(len(d))] )
dif_max_wlen = [max_wlen[0][i] - max_wlen[1][i] for i in range(len(data[0]))]

e_wlen = []
for d in data:
    e_wlen.append( np.mean([ d[i][j, 0] - d[i][j+1, 0]
                    for j in range(len(d[i])-1)
                    for i in range(len(d))]) )

max_wlen = []
e_max_wlen = []
part_max_wlen = []
for d, sc in zip(data, series_column):
    max_wlen.append( [d[i][np.argmax(d[i][:,sc]), 0] for i in range(len(d))] )
    part_max_wlen.append( [
        [d[i][np.argmax(d[i][:,sc])-1, 0], d[i][np.argmax(d[i][:,sc])+1, 0] ]
        for i in range(len(d)) ] )
    e_max_wlen.append( [ np.mean([
        abs(d[i][np.argmax(d[i][:,sc])-1, 0] - d[i][np.argmax(d[i][:,sc]), 0]),
        abs(d[i][np.argmax(d[i][:,sc])+1, 0] - d[i][np.argmax(d[i][:,sc]), 0])
        ]) for i in range(len(d)) ] )
dif_max_wlen = [max_wlen[0][i] - max_wlen[1][i] for i in range(len(data[0]))]
e_dif_max_wlen = [np.mean([e_max_wlen[0][i], e_max_wlen[1][i]]) for i in range(len(data[0]))]

#%% NORMALIZED PLOT

colors = [sc(np.linspace(0,1,len(s)+3))[3:]
          for sc, s in zip(series_colors, series)]

plt.figure()
plt.title(plot_title)
for s, d, p, sc, psl, pc, pls in zip(series, data, params, series_column,
                                     series_label, colors, series_linestyles):

    for ss, sd, sp, spc in zip(s, d, p, pc):
        plt.plot(sd[:,0], sd[:,sc] / max(sd[:,sc]),
                 linestyle=pls, color=spc, label=psl(ss))

plt.xlabel(trs.choose(r"Wavelength $\lambda$ [nm]", r"Longitud de onda $\lambda$ [nm]"))
plt.ylabel(trs.choose("Normalized Scattering Cross Section",
                      "Sección eficaz de dispersión normalizada"))
plt.legend()
if plot_make_big:
    mng = plt.get_current_fig_manager()
    mng.window.showMaximized()
del mng
vs.saveplot(plot_file("AllScatt.png"), overwrite=True)

#%% NON NORMALIZED PLOT

colors = [sc(np.linspace(0,1,len(s)+3))[3:]
          for sc, s in zip(series_colors, series)]

plt.figure()
plt.title(plot_title)
for s, d, p, sc, psl, pc, pls in zip(series, data, params, series_column,
                                     series_label, colors, series_linestyles):

    for ss, sd, sp, spc in zip(s, d, p, pc):
        plt.plot(sd[:,0], sd[:,sc],
                 linestyle=pls, color=spc, label=psl(ss))

plt.xlabel(trs.choose(r"Wavelength $\lambda$ [nm]", r"Longitud de onda $\lambda$ [nm]"))
plt.ylabel(trs.choose("Scattering Efficiency", "Eficacia de Dispersión"))
plt.legend()
if plot_make_big:
    mng = plt.get_current_fig_manager()
    mng.window.showMaximized()
del mng
vs.saveplot(plot_file("AllScattEf.png"), overwrite=True)

#%% IN UNITS PLOT

colors = [sc(np.linspace(0,1,len(s)+3))[3:]
          for sc, s in zip(series_colors, series)]

plt.figure()
plt.title(plot_title)
for s, d, p, sc, psl, pc, pls in zip(series, data, params, series_column,
                                     series_label, colors, series_linestyles):

    for ss, sd, sp, spc in zip(s, d, p, pc):
        plt.plot(sd[:,0], sd[:,sc] * np.pi * (sp['r'] * sp['from_um_factor'] * 1e3)**2,
                 linestyle=pls, color=spc, label=psl(ss))

plt.xlabel(trs.choose(r"Wavelength $\lambda$ [nm]", r"Longitud de onda $\lambda$ [nm]"))
plt.ylabel(trs.choose("Scattering Cross Section [nm$^2$]",
                      "Sección eficaz de dispersión [nm$^2$]"))
plt.legend()
if plot_make_big:
    mng = plt.get_current_fig_manager()
    mng.window.showMaximized()
del mng
vs.saveplot(plot_file("AllScattSec.png"), overwrite=True)

#%% ONE HUGE PLOT

colors = [sc(np.linspace(0,1,len(s)+3))[3:]
          for sc, s in zip(series_colors, series)]

fig = plt.figure()
plot_grid = gridspec.GridSpec(ncols=4, nrows=2, hspace=0.5, wspace=0.5, figure=fig)

main_ax = fig.add_subplot(plot_grid[:,0:2])
main_ax.set_title(trs.choose("All Diameters", "Todos los diámetros"))
main_ax.xaxis.set_label_text(trs.choose(r"Wavelength $\lambda$ [nm]", r"Longitud de onda $\lambda$ [nm]"))
main_ax.yaxis.set_label_text(trs.choose("Normalized Scattering Cross Section",
                                        "Sección eficaz de dispersión normalizada"))

for s, d, p, sc, psl, pc, pls in zip(series, data, params, series_column,
                                     series_label, colors, series_linestyles):

    for ss, sd, sp, spc in zip(s, d, p, pc):
        main_ax.plot(sd[:,0], sd[:,sc] / max(sd[:,sc]),
                     linestyle=pls, color=spc, label=psl(ss))
main_ax.legend()

plot_list = [plot_grid[0,2], plot_grid[0,3], plot_grid[1,2], plot_grid[1,3]]
axes_list = []
for pl in plot_list:
    axes_list.append(fig.add_subplot(pl))

for s, d, p, sc, psl, pc, pls in zip(series, data, params, series_column,
                                         series_label, colors, series_linestyles):
    for ax, ss, sd, sp, spc in zip(axes_list, s, d, p, pc):
        ax.set_title(trs.choose("Diameter", "Diámetro") +
                     f" {2*sp['r']*sp['from_um_factor']*1e3: 1.0f} nm")
        ax.plot(sd[:,0], sd[:,sc] * np.pi * (sp['r'] * sp['from_um_factor'] * 1e3)**2,
                linestyle=pls, color=spc, label=psl(ss))
        ax.xaxis.set_label_text(trs.choose(r"Wavelength $\lambda$ [nm]", r"Longitud de onda $\lambda$ [nm]"))
        ax.yaxis.set_label_text(trs.choose("Scattering Cross Section [nm$^2$]",
                                           "Sección eficaz de dispersión [nm$^2$]"))

fig.set_size_inches([13.09,  5.52])

vs.saveplot(plot_file("AllScattBig.png"), overwrite=True)


from http.server import BaseHTTPRequestHandler, HTTPServer
from Data_rx import DataRx
from SevenSegment import SevenSegment
from Led import Led
from multiprocessing import Manager
import threading
import RPi.GPIO as GPIO

class MyHTTPRequestHandler(BaseHTTPRequestHandler):
    manager = Manager()
    List_Data = manager.list() # initialize List_Data as a class attribute
    Stage_Data = manager.list()
    SevenSegment = SevenSegment()
    LedArray = [Led(13),Led(19)]
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.IN)

    Stage_Data.append("Runing")
    def do_GET(self):
        if self.path == '/start_transmition':
            self.DataGenerator = DataRx()
            t1 = threading.Thread(target=self.DataGenerator.PutData, args=(MyHTTPRequestHandler.List_Data, MyHTTPRequestHandler.Stage_Data,))
            t1.start()
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            self.wfile.write("ReadyToTransmit".encode()) # Ready to transmit

        elif self.path == '/ask_input':
            while not(GPIO.input(17)):
                pass
            MyHTTPRequestHandler.Stage_Data[0] = "Stop"
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            inputdata = "1"
            self.wfile.write(inputdata.encode())
        else:
            self.send_error(404)

    def do_POST(self):
        if self.path == '/get_line':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            if MyHTTPRequestHandler.List_Data:
                self.wfile.write(MyHTTPRequestHandler.List_Data.pop(0).encode())  # remove and sent the first element of the list
            else:
                self.wfile.write("No element".encode())
            MyHTTPRequestHandler.LedArray[0].High()
            MyHTTPRequestHandler.LedArray[1].Low()

        elif self.path == '/send_data':
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.end_headers()
            content_length = int(self.headers.get('Content-Length', 0))
            data = self.rfile.read(content_length).decode('utf-8').split()
            MyHTTPRequestHandler.SevenSegment.PinAssing(data)
            MyHTTPRequestHandler.LedArray[1].High()
            MyHTTPRequestHandler.LedArray[0].Low()

        else:
            self.send_error(404)

def run():
    server_address = ('', 8000)
    httpd = HTTPServer(server_address, MyHTTPRequestHandler)
    httpd.serve_forever()

if __name__ == '__main__':
    t2 = threading.Thread(target=run)
    t2.start()


import praw
import threading
import time
import datetime
import numpy as np
import pandas as pd

reddit = praw.Reddit()

# posts = []
threads = []
done = []
pkl_idx = 0
start_time = time.time()

class post:
	checkpoint_times = [x for x in range(2, 62, 2)]
	# checkpoint_times = [1/15]

	def __init__(self, _id, created_utc):
		self.id = _id
		self.time = created_utc
		self.cur_time_idx = 0
		self.scores = []
		self.comments = []

	def utc_to_time(utc):
		return utc

def save_done(done):
	global pkl_idx
	df = pd.DataFrame(data=[[x for x in p.scores] + [x for x in p.comments] + [p.time] for p in done],
		columns=['scores ' + str(x) for x in post.checkpoint_times] + ['comments ' + str(x) for x in post.checkpoint_times] + ['time'],
		index=[p.id for p in done])

	df.to_pickle('data-{:02d}.pkl'.format(pkl_idx))
	print('saved data ' + str(pkl_idx))
	pkl_idx += 1
	done = []

def manage_post(p, done):
	while p.cur_time_idx < len(post.checkpoint_times):
		now = time.time()
		seconds_to_checkpoint = (p.time + post.checkpoint_times[p.cur_time_idx] * 60) - now
		# print("seconds ", seconds_to_checkpoint)
		if seconds_to_checkpoint > 0:
			time.sleep(seconds_to_checkpoint)
		lock = threading.Lock()
		with lock:
			score = reddit.submission(p.id).score
			num_comments = reddit.submission(p.id).num_comments
		p.scores.append(score)
		p.comments.append(num_comments)
		# print(p.id, p.scores, p.comments)
		p.cur_time_idx += 1
		# print(p.id, " on checkpoint ", p.cur_time_idx)
	lock = threading.Lock()
	with lock:
		done.append(p)
		if len(done) >= 32:
			save_done(done)

for submission in reddit.subreddit("askreddit").stream.submissions():
	now = time.time()
	# print(submission.title, now, submission.created_utc)
	if now - submission.created_utc > 15:
		continue
	cur_post = post(submission.id, now)
	thread = threading.Thread(target=manage_post, args=(cur_post, done))
	threads.append(thread)
	# posts.append(cur_post)
	thread.start()
	if now - start_time > 3*60*60:
		break
for thread in threads:
	thread.join()

# row0 = ['names'] + ['scores ' + str(x) for x in post.checkpoint_times] + ['comments ' + str(x) for x in post.checkpoint_times]
# output = np.array([row0] + [[p.id] + [x for x in p.scores] + [x for x in p.comments] for p in posts])

if done:
	save_done(done)

# pd.set_option('display.max_rows', None)
# pd.set_option('display.max_columns', None)

# for p in posts:
# 	print('{:7s}'.format(p.id), end='')
# 	for score in p.scores:
# 		print('{:4d}'.format(score), end='')
# 	print()
# 	print(' ' * 7, end='')
# 	for num_comments in p.comments:
# 		print('{:4d}'.format(num_comments), end='')
# 	print()


import random

def create_pieces(pieces):
    for i in range(7):
        for j in range(i, 7):
            pieces.append([i, j])
    random.shuffle(pieces)

def find_first_piece(computer, player):
    for i in reversed(range(7)):
        if [i, i] in computer:
            return computer.pop(computer.index([i, i]))
        if [i, i] in player:
            return player.pop(player.index([i, i]))
    return None

def distribute_pieces(deck, player, start_pieces):
    player.extend(deck[:start_pieces])
    for item in player:
        deck.remove(item)

def initialize_game(deck, computer, player, snake):
    while True:
        create_pieces(deck)
        distribute_pieces(deck, computer, start_pieces=7)
        distribute_pieces(deck, player, start_pieces=7)
        first_piece = find_first_piece(computer, player)
        if len(computer) == len(player):
            deck.clear()
            player.clear()
            computer.clear()
            snake.clear()
            continue
        snake.append(first_piece)
        break

def print_hand(hand):
    for i, piece in enumerate(hand):
        print(f'{i + 1}: {piece}')

def print_snake(domino_snake):
    if len(domino_snake) > 6:
        right_part = str(domino_snake[0:3])[1:- 1]
        left_part = str(domino_snake[-3:])[1: - 1]
        snake = f'{right_part}...{left_part}'
    else:
        snake = str(domino_snake)[1: - 1]
    print(snake)

def print_status(player_pieces, computer_pieces, turn_indicator, players, is_over):
    if is_over:
        if len(player_pieces) == 0 or len(player_pieces) < len(computer_pieces):
            status = 'The game is over. You won!'
        elif len(computer_pieces) == 0 or len(computer_pieces) < len(player_pieces):
            status = 'The game is over. The computer won!'
        else:
            status = "The game is over. It's a draw!"
    elif players[turn_indicator] == 'computer':
        status = 'Computer is about to make a move. Press Enter to continue...'
    else:
        status = "It's your turn to make a move. Enter your command."
    print(f'Status: {status}')

def print_interface(deck, computer, player, snake, turn, players, is_over):
    print('=' * 70)
    print(f'Stock size: {len(deck)}')
    print(f'Computer pieces: {len(computer)}')
    print()
    print_snake(snake)
    print()
    print('Your pieces:')
    print_hand(player)
    print_status(player, computer, turn, players, is_over)

def check_input(pieces):
    input_string = input()
    if not input_string.lstrip("-").isdigit():
        print('Invalid input. Please try again.')
        return check_input(pieces)
    move = int(input_string)
    if abs(move) > pieces:
        print('Invalid input. Please try again.')
        return check_input(pieces)
    return move

def check_snake(snake):
    for i in range(7):
        if str(snake).count(str(i)) == 9:
            return True
    return False

def check_deck(snake, computer, player, deck):
    is_possible_move = True
    if not deck:
        for piece in computer:
            if check_left_side(snake, piece) or check_right_side(snake, piece):
                is_possible_move = False
        for piece in player:
            if check_left_side(snake, piece) or check_right_side(snake, piece):
                is_possible_move = False
    else:
        is_possible_move = False
    return is_possible_move

def check_left_side(domino_snake, players_piece):
    end = domino_snake[0][0]
    return end in players_piece

def check_right_side(domino_snake, players_piece):
    end = domino_snake[-1][1]
    return end in players_piece

def turn_piece(domino_snake, piece, side):
    if side > 0:
        if domino_snake[-1][1] != piece[0]:
            piece.reverse()
    else:
        if domino_snake[0][0] != piece[1]:
            piece.reverse()

def player_move(player_pieces, stock_pieces, domino_snake):
    while True:
        move = check_input(len(player_pieces))
        player_piece = player_pieces[abs(move) - 1]
        if move == 0:
            if len(stock_pieces) != 0:
                player_pieces.append(stock_pieces.pop(random.randint(0, len(stock_pieces) - 1)))
            break
        elif move < 0 and check_left_side(domino_snake, player_piece):
            player_pieces.remove(player_piece)
            turn_piece(domino_snake, player_piece, move)
            domino_snake.insert(0, player_piece)
            break
        elif check_right_side(domino_snake, player_piece):
            player_pieces.remove(player_piece)
            turn_piece(domino_snake, player_piece, move)
            domino_snake.append(player_piece)
            break
        else:
            print('Illegal move. Please try again.')
            continue

def computer_move(player_pieces, stock_pieces, domino_snake):
    input()
    movies = []
    movies.extend(range(-len(player_pieces), 0))
    movies.extend(range(1, len(player_pieces) + 1))
    movies.append(0)
    for move in movies:
        player_piece = player_pieces[abs(move) - 1]
        if move == 0:
            if len(stock_pieces) != 0:
                player_pieces.append(stock_pieces.pop(random.randint(0, len(stock_pieces) - 1)))
            break
        elif move < 0 and check_left_side(domino_snake, player_piece):
            player_pieces.remove(player_piece)
            turn_piece(domino_snake, player_piece, move)
            domino_snake.insert(0, player_piece)
            break
        elif check_right_side(domino_snake, player_piece):
            player_pieces.remove(player_piece)
            turn_piece(domino_snake, player_piece, move)
            domino_snake.append(player_piece)
            break

def calculate_numbers(computer_pieces, domino_snake):
    _weight_numbers = dict()
    visible_piece = []
    visible_piece.extend(computer_pieces)
    visible_piece.extend(domino_snake)
    for i in range(7):
        count = 0
        for item in visible_piece:
            if item == [i, i]:
                count += 2
            elif i in item:
                count += 1
        _weight_numbers[i] = count
    return _weight_numbers

def weight_hand(weight_numbers, computer_pieces):
    weight_pieces = dict()
    for index, item in enumerate(computer_pieces):
        weight_piece = weight_numbers[item[0]] + weight_numbers[item[1]]
        weight_pieces[index] = weight_piece

    sorted_keys = sorted(weight_pieces, key=weight_pieces.get)  # [1, 3, 2]
    computer_sort = list(computer_pieces)
    for i, val in enumerate(sorted_keys):
        computer_pieces[i] = computer_sort[val]
    computer_pieces.reverse()

def computer_ai_move(computer_pieces, stock_pieces, domino_snake):
    input()
    weight_numbers = calculate_numbers(computer_pieces, domino_snake)
    weight_hand(weight_numbers, computer_pieces)
    for piece in computer_pieces:
        if check_left_side(domino_snake, piece):
            computer_pieces.remove(piece)
            turn_piece(domino_snake, piece, side=-1)
            domino_snake.insert(0, piece)
            break
        if check_right_side(domino_snake, piece):
            computer_pieces.remove(piece)
            turn_piece(domino_snake, piece, side=1)
            domino_snake.append(piece)
            break
    else:
        if len(stock_pieces) != 0:
            computer_pieces.append(stock_pieces.pop(random.randint(0, len(stock_pieces) - 1)))

def game():
    stock_pieces, computer_pieces, player_pieces, domino_snake = [], [], [], []
    players = ('player', 'computer')

    initialize_game(deck=stock_pieces, computer=computer_pieces, player=player_pieces, snake=domino_snake)
    turn_indicator = 1 if len(player_pieces) < len(computer_pieces) else 0

    while True:
        is_over = check_snake(domino_snake) \
                  or check_deck(domino_snake, computer_pieces, player_pieces, stock_pieces) \
                  or len(computer_pieces) == 0 or len(player_pieces) == 0
        print_interface(deck=stock_pieces,
                        computer=computer_pieces,
                        player=player_pieces,
                        snake=domino_snake,
                        turn=turn_indicator,
                        players=players,
                        is_over=is_over)
        if is_over:
            break
        if players[turn_indicator] == 'player':
            player_move(player_pieces=player_pieces, stock_pieces=stock_pieces, domino_snake=domino_snake)
        else:
            computer_ai_move(computer_pieces=computer_pieces, stock_pieces=stock_pieces, domino_snake=domino_snake)
        turn_indicator = (turn_indicator + 1) % len(players)

game()


import sys, os
sys.path.append("../")

import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['pdf.fonttype'] = 42
import matplotlib.gridspec as gridspec
plt.rcParams["font.family"] = "Optima"
plt.rcParams["font.weight"] = "light"

import matplotlib.pyplot as plt
import seaborn as sns

import numpy as np
import arviz as az

import yaml
import json

from epimodel.plotting.intervention_plots import combine_npi_samples

from tqdm import tqdm
import pandas as pd
import argparse

argparser = argparse.ArgumentParser()
argparser.add_argument('--wearing_results_path', dest='wearing_results_path', type=str, required=True)
argparser.add_argument('--mandate_results_path', dest='mandate_results_path', type=str, required=True)

args, _ = argparser.parse_known_args()

base_dir_wearing = args.wearing_results_path
base_dir_mandates = args.mandate_results_path

exp_main_tags = {
    "Unrecorded factors": ['npi_leaveout', 'mobility_leaveout', 'mob_and_wearing_only', 'fake_wearing_npi'],
    "Data": ["boostrap", 'mask_leave_on', 'mask_thresholds', 'window_of_analysis'],
    "Delay distributions": ["gen_int_mean", "cases_delay_mean", "cases_delay_disp_mean"],
    "Prior distributions": ["basic_R_prior_mean", "basic_R_prior_scale", 'basic_R_hyperprior_mean_mean',
                            'basic_R_hyperprior_mean_scale', "r_walk_noise_scale_prior",
                            "intervention_prior", 'mobility_sigma', 'mobility_mean', 'mask_sigma',
                            'wearing_prior_scale'],
    "Model structure": ["r_walk_period", 'wearing_parameterisation']
}

def get_all_exp_info(base_dir, all_info_dicts=None):

    if all_info_dicts is None:
        all_info_dicts = []
    for subdir, dirs, files in os.walk(base_dir):
        for f in files:
            if f.endswith('.json'):
                with open(os.path.join(subdir, f), 'r') as f:
                    try:
                        info_dict = json.load(f)

                        if 'MandateReduction' in info_dict.keys():
                            npi_name = 'Mask Mandates'
                            reduction = np.array(info_dict['MandateReduction'])
                        else:
                            npi_name = 'Mask Wearing'
                            reduction = np.array(info_dict['WearingReduction'])

                        med = np.median(100*(1-reduction), axis=0)

                        main_tag = None
                        for name, v in exp_main_tags.items():
                            if info_dict["exp_tag"] in v:
                                main_tag = name

                                reduced_info_dict = {
                                    'npi': npi_name,
                                    "med": med,
                                    'tag': main_tag
                                }
                                all_info_dicts.append(reduced_info_dict)
                                # print(len(all_info_dicts))
                            # else:
                            #     print(f'{info_dict["exp_tag"]} not in dict')

                    except Exception as e:
                        print(e)

    return all_info_dicts

all_wearing_dicts = get_all_exp_info(base_dir_wearing)

meds = pd.DataFrame(all_wearing_dicts)['med']
print(f'Mean: {np.mean(meds)}, sd: {np.sqrt(np.var(meds))}')

all_dicts = get_all_exp_info(base_dir_mandates, all_wearing_dicts)

sns.color_palette('colorblind')
cols = sns.color_palette('colorblind')

main_dict = {
    'Mask Wearing' : {
        'npis': ['Mask Wearing'],
        'type': 'include',
        'color': 'black',
        'main': True,
    },
        'Mask Mandates': {
        'npis': ['Mask Mandates'],
        'type': 'include',
        'color': 'black',
        'main': True,
    }
}

npi_medians_df = pd.DataFrame(all_dicts)

fig = plt.figure(constrained_layout=True, figsize=(5.75, 3.75), dpi=400)
gs = gridspec.GridSpec(ncols=8, nrows=11, figure=fig)

main_ax = fig.add_subplot(gs[:8, :])

exp_tags = np.unique(npi_medians_df["tag"])
cols = [*sns.color_palette('colorblind'), *sns.color_palette('bright')]
plt.plot([0, 0], [-1, 40], linestyle='-', alpha=1, zorder=-5, linewidth=1, color="tab:gray")

npi_names = list(main_dict.keys())
npi_cols = [d['color'] for k, d in main_dict.items()] #maybe this should be something else

for i, col in enumerate(npi_cols):
    if i % 2 == 0:
        plt.fill_between(
            [-100, 100],
            [i-0.5, i-0.5],
            [i+0.5, i+0.5],
            color=col,
            alpha=0.05,
            linewidth=0,
            zorder=-5
        )
    else:
         plt.fill_between(
            [-100, 100],
            [i-0.5, i-0.5],
            [i+0.5, i+0.5],
            color=col,
            alpha=0.1,
            linewidth=0,
            zorder=-5
        )

sns.stripplot(x="med", y="npi", data=npi_medians_df, size=5, zorder=1,
          jitter=0.1, order=npi_names, alpha=0.3, hue="tag", dodge=True,
          palette="colorblind", linewidth=0.05)

for i, tick in enumerate(plt.gca().get_yticklabels()):
    tick.set_color(npi_cols[i])

plt.yticks(fontsize=7, linespacing=0.8)
plt.xlabel("Median Reduction in R (%)")
plt.ylabel("")
plt.xlim([-30, 50])
plt.grid(axis='x', linewidth=0.5, zorder=-10, color="tab:gray", alpha=0.25)
plt.xticks([-20, 0, 20, 40])
plt.yticks()
plt.legend(bbox_to_anchor=(0.5, -0.3), loc='upper center', fontsize=8, ncol=3, fancybox=True, shadow=True, handletextpad=0.05)
plt.savefig('validation_all.pdf', bbox_inches='tight')


from django.conf.urls import url, include

from .views import KeywordList, KeywordAdd, KeywordEdit, KeywordDetail
from .views import CategoryList, CategoryAdd, CategoryEdit, CategoryDetail

app_name = 'spkeyword'

keyword_patterns = [
    url(r'^$', KeywordList.as_view(), name='list'),
    url(r'^new$', KeywordAdd.as_view(), name='add'),
    url(r'^(?P<pk>.+)/$', KeywordDetail.as_view(), name='display'),
#    url(r'^(?P<pk>.+)/edit$', add_change_spkeyword, name='change_keyword'),
    url(r'^(?P<pk>.+)/edit$', KeywordEdit.as_view(), name='edit'),
]

category_patterns = [
    url(r'^$', CategoryList.as_view(), name='list_categories'),
    url(r'^new$', CategoryAdd.as_view(), name='add_category'),
    url(r'^(?P<pk>.+)/$', CategoryDetail.as_view(), name='display_category'),
#    url(r'^(?P<pk>.+)/edit$', add_change_spkeyword, name='change_category'),
    url(r'^(?P<pk>.+)/edit$', CategoryEdit.as_view(), name='edit_category'),
]

urlpatterns = [
    url(r'^keywords/', include(keyword_patterns)),
    url(r'^categories/', include(category_patterns)),
]


# coding: utf-8

import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import LogisticRegression
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso

data=pd.read_csv('data.csv')
del data['mid_weighted_average_price']

def LinearModel(model,data,interval):#using LinearRegression and LogisticRegression
    clf=model
    train=data.iloc[0:int(data.shape[0]*0.7)]#split data to 70% train and 30% test
    test=data.iloc[int((data.shape[0])*0.7+1):-1]
    test.index=range(int(data.shape[0]*0.3-1))
    y_train=train['best_mid_price'].iloc[interval:-1]#set 'best_mid_price' after a certain interval as the target values
    y_test=test['best_mid_price'].iloc[interval:-1]
    clf.fit(train.iloc[0:-interval-1,2:10],y_train)
    predict1=clf.predict(train.iloc[0:-interval-1,2:10])#for calculating the bias
    predict2=clf.predict(test.iloc[0:-interval-1,2:10])#predict the target values in test data

    xx=np.zeros(y_train.shape[0])#collecting the bias for each record
    for i in range(y_train.shape[0]):
        xx[i]=predict1[i]-y_train.iloc[i]

    xx2=np.zeros(y_test.shape[0])
    yy=np.zeros(y_test.shape[0])
    for i in range(y_test.shape[0]):#determine the prediction
        xx2[i]=predict2[i]-y_test.iloc[i]
        if xx2[i]<-0.01:
            yy[i]=-1
        elif xx2[i]>0.01:
            yy[i]=1
        else:
            yy[i]=0
    s=0
    index=int(data.shape[0]*0.7+1)
    for i in range(len(yy)):
        if int(yy[i])==data['output_30'].iloc[index+i]:
            s+=1

    return yy,s/len(yy)

def LinearClassifier(data,interval,column):# using SGDClassifier
    clf=SGDClassifier()
    train=data.iloc[0:int(data.shape[0]*0.7)]
    test=data.iloc[int((data.shape[0])*0.7+1):-1]
    test.index=range(int(data.shape[0]*0.3-1))
    y_train=train.iloc[interval:-1,10+column]
    y_test=test.iloc[interval:-1,10+column]
    clf.fit(train.iloc[0:-interval-1,2:10],y_train)
    predict=clf.predict(test.iloc[0:-interval-1,2:10])
    score=clf.score(test.iloc[0:-interval-1,2:10],y_test)
    return predict,score

def ret_cal(seq,data,interval):
    ret=0
    for i in range(seq.shape[0]):
        if seq[i]==-1:
            ret+=(data.iloc[i]-data.iloc[i+interval])/data.iloc[i]
        elif seq[i]==1:
            ret+=(data.iloc[i+interval]-data.iloc[i])/data.iloc[i]
    return ret

output=pd.DataFrame([])
score=np.zeros(18)
s=0
for i in ['1','5','10','50','100','300']:
    yy,score[s]=LinearModel(LinearRegression(),data,int(i))#yy is an array of output, score is the accuracy of prediction
    yy=yy[0:17505]
    output[str(s)]=yy
    yy,score[s+1]=LinearModel(LogisticRegression(max_iter=10),data,int(i))#max_iter cannot be large or it will cost minutes to fit
    yy=yy[0:17505]
    output[str(s+1)]=yy
    yy,score[s+2]=LinearClassifier(data,int(i),int(s/3+1))
    yy=yy[0:17505]
    output[str(s+2)]=yy
    s=s+3
print(score)
output.columns=['lin_0.1','log_0.1','sgd_0.1','lin_0.5','log_0.5','sgd_0.5',
               'lin_1','log_1','sgd_1','lin_5','log_5','sgd_5',
                'lin_10','log_10','sgd_10','lin_30','log_30','sgd_30'
               ]

ret_cal(output.iloc[:,0],data["best_mid_price"].iloc[41559:-1],300)

t=0
for i in ['1','5','10','50','100','300','1','5','10','50','100','300','1','5','10','50','100','300']:
    ret[t]=ret_cal(output.iloc[:,t],data["best_mid_price"].iloc[41559:-1],int(i))
    t+=1

output.loc['return']=ret
output.loc['score']=score

output.to_csv('C:/Users/Hao Li/Desktop/2018 spring/9733/project/lin_log_sgd.csv')


# class parent():
#     c=0
#     def __init__(self):
#         self.context="mahmoud"
#     def get_obj_var(self):
#         parent.c=self.context

#     def a(self,b):
#         b=self.context
#         return b
#     b=a(self,b)
# b=0
# children= parent()
# c=children.get_obj_var()
# print(c)
# print(children.c)

class Date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day

    @classmethod
    def set_date(cls,date):
        year,month,day=map(int,date.split('-'))
        return cls(year,month,day)
    @property
    def name(self):
        #making that name not accessed by the user even if it set it
        self.var="default"
        return self.var

obj1=Date(1999,5,22)

obj1.var="ali"
obj1.mm="mmnn"
print(obj1.mm)
print (obj1.name)
print (obj1.var)
print(obj1.__dict__)
#obj2=Date.set_date("1999-5-22")

#print(obj1.year,obj2.year)


import requests
from bs4 import BeautifulSoup
from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')

def home():
    return render_template('index.html')

@app.route('/populer')
def populer():
    url = requests.get('https://id.carousell.com/categories/books-and-stationery-5')

    soup = BeautifulSoup(url.text, 'html.parser')

    books = soup.find('div', attrs={'class': 'D_s'})
    populer = books.find_all('div', attrs={'class': 'D_aK'})

    return render_template('populer.html', populer=populer)

if __name__ == '__main__':
    app.run(debug=True)


from django.conf.urls import url

from . import views

app_name = 'post'
urlpatterns = [
    url(r'^$',
        views.post_list,
        name='list'),
    url(r'^add/$',
        views.post_add,
        name='add'),
    url(r'^(?P<post_id>[0-9]+)/delete/$',
        views.post_delete,
        name='delete'),
    url(r'^(?P<post_id>[0-9]+)/$',
        views.post_detail,
        name='detail'),
    url(r'^(?P<post_id>[0-9]+)/comment/add/$',
        views.comment_add,
        name='comment_add'),
    url(r'^(?P<post_id>[0-9]+)/like/toggle/$',
        views.post_like_toggle,
        name='like_toggle'),
    url(r'^(?P<post_id>[0-9]+)/comment/(?P<comment_id>[0-9]+)/delete/$',
        views.comment_delete,
        name='comment_delete'),
]


import matplotlib.pyplot as plt
import yaml
from pandas import DataFrame

"""Limpa o ruído nas magnitudes, a partir de intervalos encontrados no notebook exploration.ipynb"""
def clean_df(df: DataFrame):
    index_0 = df['mag'].between(0, 500, "neither")
    df.loc[index_0, 'mag'] = 0

    index_1000 = df['mag'].between(800, 1300, "neither")
    df.loc[index_1000, 'mag'] = 1000

    index_2000 = df['mag'].between(1720, 2152, "neither")
    df.loc[index_2000, 'mag'] = 2000

    index_3000 = df['mag'].between(2580, 3020, "neither")
    df.loc[index_3000, 'mag'] = 3000

    return df

"""Plota os vetores num scatter 3D"""
def show_plot(df: DataFrame, show_id: int,
              show_0: bool, show_1000: bool,
              show_2000: bool, show_3000: bool):

    # Mostra somente o ID escolhido
    df_id = df.loc[df['id'] == show_id]

    # Caso o ID não exista nos dados retorna erro
    if df_id.shape[0] == 0:
        raise Exception("ID não existe nos dados!")

    # Caso nenhuma magnitude seja mostrada retorna erro
    if not (show_0 or show_1000 or show_2000 or show_3000):
        raise Exception("Nenhuma magnitude escolhida! Escolha ao menos uma.")

    ax = plt.axes(projection ="3d")

    # frames de cada magnitude
    df_0 = df_id.loc[df_id['mag'] == 0]
    df_1000 = df_id.loc[df_id['mag'] == 1000]
    df_2000 = df_id.loc[df_id['mag'] == 2000]
    df_3000 = df_id.loc[df_id['mag'] == 3000]

    # Cria um eixo para a magnitude caso tenha sido habilitado
    if show_0:
        ax.scatter3D(df_0['x'], df_0['y'], df_0['z'], label="0") # type: ignore

    if show_1000:
        ax.scatter3D(df_1000['x'], df_1000['y'], df_1000['z'], label="1000") # type: ignore

    if show_2000:
        ax.scatter3D(df_2000['x'], df_2000['y'], df_2000['z'], label="2000") # type: ignore

    if show_3000:
        ax.scatter3D(df_3000['x'], df_3000['y'], df_3000['z'], label="3000") # type: ignore

    ax.legend(loc=1)

    plt.show()

def get_config():
    plot_config = dict()
    with open("config.yaml", "r") as stream:
        try:
            plot_config = yaml.safe_load(stream)
        except yaml.YAMLError as exc:
            raise exc

    return plot_config


import requests

from django.conf import settings
from django.urls import reverse_lazy
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import FormView, TemplateView

from .models import Todo
from .forms import TodoForm

HEADERS = {
    'Authorization': f'Bearer {settings.ACCESS_TOKEN}'
}

class Home(LoginRequiredMixin, FormView):
    template_name = 'todo/home.html'
    form_class = TodoForm
    success_url = reverse_lazy('home')

    def form_valid(self, form):
        # Get the current user
        profile = self.request.user.profile

        # Prepare the data to be sent to the API
        data = {
            'title': form.cleaned_data['title'],
            'description': form.cleaned_data['description'],
            'profile': profile.id  # Include the current user ID
        }

        # Send a POST request to the API to create a new to-do item
        response = requests.post(
            'http://localhost:8000/api/', data=data, headers=HEADERS)

        return super().form_valid(form)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # Fetch the list of to-do items from the API
        response = requests.get('http://localhost:8000/api/', headers=HEADERS)
        context['todos'] = response.json()
        return context

@login_required
def todo_complete(request, pk):
    response = requests.get(
        f'http://localhost:8000/api/{pk}/', headers=HEADERS)
    completed = response.json()['completed']
    title = response.json()['title']
    description = response.json()['description']
    if completed:
        data = {
            'title': title,
            'description': description,
            'completed': False}
    else:
        data = {
            'title': title,
            'description': description,
            'completed': True}
    requests.put(
        f'http://localhost:8000/api/{pk}/', headers=HEADERS, data=data)
    return redirect('home')


# dependencies
import pandas as pd
from azely.time import get_time

# constants
expected = pd.date_range(
    "2020-01-01",
    "2020-01-07",
    None,
    freq="10T",
    tz="Asia/Tokyo",
)

# test functions
def test_time_by_tzinfo():
    result = get_time("2020-01-01 to 2020-01-07", "Asia/Tokyo", "10T")
    assert (result == expected).all()

def test_time_by_location():
    result = get_time("2020-01-01 to 2020-01-07", "Tokyo", "10T")
    assert (result == expected).all()


# 349. Intersection of Two Arrays - two pointers O(m + n)
#                                 - binary search O(m * logn)
def intersection(nums1, nums2):
    nums1.sort()
    nums2.sort()
    res = []

    i, j = 0, 0
    while i < len(nums1) and j < len(nums2):
        if nums1[i] < nums2[j]:
            i += 1
        elif nums1[i] > nums2[j]:
            j += 1
        else:
            res.append(nums1[i])
            i += 1
            j += 1

    return res

# binary search O(n.logm)
def intersection(arr1, arr2):
    result = []

    for num in arr1:
        if binarySearchFound(arr2, num):
            result.append(num)
    return result

def binarySearchFound(nums, target):
    l, r = 0, len(nums) - 1
    while l + 1 < r:
        mid = (l + r) // 2
        if nums[mid] == target:
            return True
        elif target < nums[mid]:
            r = mid
        else:
            l = mid

    if nums[l] == target:
        return True
    if nums[r] == target:
        return True
    return False

01-Array/01-search/349. Intersection of Two Arrays.py


"""An image processing pipeline stage which detects doors in the scene."""

import cv

__author__ = "Nick Pascucci (npascut1@gmail.com)"

class DoorDetectError(Exception):
    pass

class ScanningDoorDetectPipe:
    """An implementation of a simple barscan door detector.

    This detector expects to be called on an edge-detected image."""

    def __init__(self, next_pipe):
        self.next_pipe = next_pipe

    def process(self, image, bar_size=1):
        # First thing's first: we need to get sums for each row and column in
        # the image.
        # TODO Implement parameterization of the bar width
        row_sums = []
        col_sums = []

        # Vertical scan: look at each row and sum it.
        # OpenCV matrices are a pain because they're not iterable; I wrote a
        # method to sum them up to make life a little easier.
        for row in range(image.height):
            neighbors = [self.sum_cvmat(image[row + i])
                         for i in range(-bar_size, bar_size)
                         if row + i >= 0 and row + i < image.height]
            row_sums.append(sum(neighbors))

        # Horizontal scan. As the image is stored in rows, we need to take the
        # nth element from each row in order to form a column. Just a little
        # more work than the vertical scan.
        for col in range(image.width):
            neighbors = [self.sum_cvmat(image[:, col + i])
                         for i in range(-bar_size, bar_size)
                         if col + i >= 0 and col + i < image.width]
            col_sums.append(sum(neighbors))

        # We want the index of the largest 2 elements of our sum list.
        # I don't feel like writing a max function, so...
        max_col_1 = max(enumerate(col_sums), key=lambda elem: elem[1])[0]

        # Ok, now remove the maximum and go get the second-largest.
        col_sums[max_col_1] = 0
        max_col_2 = max(enumerate(col_sums), key=lambda elem: elem[1])[0]

        # Rinse, repeat for rows.
        max_row_1 = max(enumerate(row_sums), key=lambda elem: elem[1])[0]
        row_sums[max_row_1] = 0
        max_row_2 = max(enumerate(row_sums), key=lambda elem: elem[1])[0]

        # We'll build a couple of tuples specifying the corners for our
        # convenience here. Keep in mind these are the row/column numbers.
        top_left = (min(max_col_1, max_col_2), max(max_row_1, max_row_2))
        bottom_right = (max(max_col_1, max_col_2), min(max_row_1, max_row_2))

        image = self.grayscale_to_color(image)

        # Now that we know where the door is in the image, we'll highlight it.
        # This is supposed to be red; I guess OpenCV uses BGR instead of RGB.
        cv.Rectangle(image, top_left, bottom_right, cv.Scalar(0, 0, 255))

        if self.next_pipe:
            processed_image = self.next_pipe.process(image)
            return processed_image
        else:
            return image

    def sum_cvmat(self, cvmat, channel=0):
        """Sum a one-dimensional cvmat instance.

        Sums the values for the given channel of a cvmat for which either the
        number of rows or the number of columns is 1."""
        if cvmat.rows > 1 and cvmat.cols > 1:
            raise DoorDetectError("Array is not one dimensional.")

        if type(cvmat[0,0]) is tuple:
            if cvmat.rows > 1:
                # We want to get the specified channel for each row in the cvmat.
                return sum([cvmat[i, 0][channel] for i in range(cvmat.rows)])
            elif cvmat.cols > 1:
                return sum([cvmat[0, i][channel] for i in range(cvmat.cols)])

        elif type(cvmat[0,0]) is float:
            if cvmat.rows > 1:
                # We want to get the specified channel for each row in the cvmat.
                return sum([cvmat[i, 0] for i in range(cvmat.rows)])
            elif cvmat.cols > 1:
                return sum([cvmat[0, i] for i in range(cvmat.cols)])

    def grayscale_to_color(self, image):
        color = cv.CreateMat(image.height, image.width, cv.CV_8UC3)
        cv.CvtColor(image, color, cv.CV_GRAY2RGB)
        return color

class HaarDoorDetectPipe:
    """An implementation of a door detector which uses a CV cascade classifier.

    This detector should be called on the same type of image used in training
    the classifier."""

    def __init__(self, next_pipe, path="haarcascade-door.xml"):
        self.next_pipe = next_pipe
        self.hc = cv.Load(path)

    def process(self, image):
        doors = cv.HaarDetectObjects(image, self.hc, cv.CreateMemStorage())

        for (x, y, w, h), n in doors:
            cv.Rectangle(image, (x, y), (x+w, y+h), 255)

        if self.next_pipe:
            processed_image = self.next_pipe.process(image)
            return processed_image
        else:
            return image


'''
@Author: Michael 2022-09-29 18:37:17

'''
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
from Dijkstra import Dijkstra

def load_data(path):
    df_edge = pd.read_excel(path, sheet_name = 'Edge')
    df_OD = pd.read_excel(path, sheet_name = 'OD')
    Edge = np.array(df_edge)
    OD = np.array(df_OD)

    T_a0 = Edge[:,3]
    C_a = Edge[:,2]
    num_node = int(np.max(np.max(Edge,axis = 0)[:2]))

    return num_node, Edge, OD, T_a0, C_a

def Mgraph(Edge, X_a, OD, alpha, beta, num_node, T_a0, C_a):
    inf = 10 * len(OD) * np.max(T_a0) * (1 + alpha * (np.sum(OD[:,-1])/np.min(C_a)) ** beta)
    mgraph = np.ones((num_node, num_node)) * inf
    T_a = T_a0 * (1 + alpha * (X_a / C_a) ** beta)
    for i in range(len(Edge)):
        row = int(Edge[i,0] - 1)
        column = int(Edge[i,1] - 1)
        mgraph[row, column] = T_a[i]

    return mgraph, inf

def Get_Y_a(mgraph, Edge, OD, inf, num_node):
    Y_a = np.zeros(len(Edge))
    for i in range(len(OD)):
        Q = np.zeros((num_node,num_node))
        start = int(OD[i,0])
        end = int(OD[i,1])
        q = OD[i,2]
        path, _ = Dijkstra(mgraph, start, end, inf)
        for j in range(len(path)-1):
            row = path[j] - 1
            column = path[j+1] - 1
            Q[row,column] = q
        for k in range(len(Edge)):
            row = int(Edge[k,0] - 1)
            column = int(Edge[k,1] - 1)
            Y_a[k] = Y_a[k] + Q[row,column]

    return Y_a

def Lamda(T_a0, X_a, C_a,Y_a, lamda, alpha, beta):
    f = lambda T_a0, X_a, C_a, Y_a, lamda, alpha, beta: np.sum((Y_a - X_a) * T_a0 * (1 + alpha * ((X_a + lamda * (Y_a - X_a)) / C_a) ** beta))
    a,b = 0,1
    while 1:
        lamda = 0.5 * (a + b)
        if abs(f(T_a0, X_a, C_a,Y_a, lamda, alpha, beta)) < 1e-6:
            break
        elif f(T_a0, X_a, C_a,Y_a, a, alpha, beta) * f(T_a0, X_a, C_a,Y_a, lamda, alpha, beta) < 0:
            b = lamda
        else:
            a = lamda
        if b - a <= 1e-3:
            break
    return lamda

def Frank_Wolfe(path, alpha, beta):
    start_time = time.time()
    num_node, Edge, OD, T_a0, C_a = load_data(path)
    X_a = np.zeros(len(Edge))
    n = 1
    Cost = []
    ls_lamda = []
    ls_gap = []

    while 1:
        mgraph, inf = Mgraph(Edge, X_a, OD, alpha, beta, num_node, T_a0, C_a)
        Y_a = Get_Y_a(mgraph, Edge, OD, inf, num_node)
        UEIT = np.sum(Y_a * T_a0 * (1 + alpha * (X_a / C_a) ** beta)) #UE ideal time

        if n == 1:
            lamda = 1
        else:
            lamda = Lamda(T_a0, X_a, C_a,Y_a, lamda, alpha, beta)

        # crit = np.power(np.sum((lamda * (Y_a - X_a)) ** 2) , 0.5) / (np.sum(X_a) + 1e-6)

        X_a = lamda * Y_a + (1 - lamda) * X_a
        n = n + 1
        TSTT = np.sum(X_a * T_a0 * (1 + alpha * (X_a / C_a) ** beta)) # total system travel time
        gap = abs(TSTT / UEIT - 1)

        Cost.append(TSTT)
        ls_lamda.append(lamda)
        ls_gap.append(gap)
        display(Cost, ls_lamda, ls_gap)

        print(f'iter:{n - 1}, cost:{TSTT}, lamda:{lamda}, gap:{gap}')

        if gap <= 1e-4:
            break

    T_a = T_a0 * (1 + alpha * (X_a / C_a) ** beta)

    end_time = time.time()
    run_time = end_time - start_time - 1e-3 * n

    return Edge, X_a, T_a, n, run_time, Cost, ls_gap, ls_lamda

def Output(Edge, X_a, T_a, n, run_time, Cost, ls_gap, ls_lamda):

    head_UE = ['init_node', 'term_node', 'capacity', 'X_a', 'T_a']
    UE = np.concatenate((Edge[:,0:3], X_a.reshape(-1,1), T_a.reshape(-1,1)), axis = 1)
    data_UE = pd.DataFrame(UE)
    # data_UE.to_excel(r'F:\Code\交通网络均衡\Traffic_Flow_Equilibrium\Frank-Wolfe\result.xlsx', header = head_UE, sheet_name = 'UE_result')

    head_Aux = ['Cost', 'gap', 'lamda']
    Aux = np.concatenate((np.array(Cost).reshape(-1,1), np.array(ls_gap).reshape(-1,1), np.array(ls_lamda).reshape(-1,1)), axis = 1)
    data_Aux = pd.DataFrame(Aux)
    # data_Aux.to_excel(r'F:\Code\交通网络均衡\Traffic_Flow_Equilibrium\Frank-Wolfe\result.xlsx', header = head_Aux, sheet_name = 'Aux_data')

    with pd.ExcelWriter(r'F:\Code\交通网络均衡\Traffic_Flow_Equilibrium\Frank-Wolfe\result.xlsx') as writer:
        data_UE.to_excel(writer, header = head_UE, sheet_name = 'UE_result')
        data_Aux.to_excel(writer, header = head_Aux, sheet_name = 'Aux_data')

    print(f"迭代次数,{n - 1},运行时间,{run_time}s,系统总消耗时间,{Cost[-1]}")

def display(Cost, ls_lamda, ls_gap):
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus']=False

    plt.subplot(1,3,1)
    plt.plot(Cost[:])
    plt.xlabel('迭代次数')
    plt.ylabel('TSTT')

    plt.subplot(1,3,2)
    plt.plot(ls_lamda[:])
    plt.xlabel('迭代次数')
    plt.ylabel('步长')

    plt.subplot(1,3,3)
    plt.plot(ls_gap[:])
    plt.xlabel('迭代次数')
    plt.ylabel('gap')

    plt.pause(1e-3)

def main(path, alpha, beta):
    Edge, X_a, T_a, n, run_time, Cost, ls_gape, ls_lamda = Frank_Wolfe(path, alpha, beta)
    Output(Edge, X_a, T_a, n, run_time, Cost, ls_gape, ls_lamda)
    plt.show()

# main(r'F:\Code\交通网络均衡\Traffic_Flow_Equilibrium\Frank-Wolfe\N_Q.xlsx', 0.15, 4)

main(r'F:\Code\交通网络均衡\Traffic_Flow_Equilibrium\Frank-Wolfe\Anaheim_net.xlsx', 0.15, 4)


#!/usr/bin/env python
# coding: utf-8

# (sec:hmm-ex)=
# # Hidden Markov Models
#
# In this section, we introduce Hidden Markov Models (HMMs).

# ## Boilerplate

# In[1]:

# Install necessary libraries

try:
    import jax
except:
    # For cuda version, see https://github.com/google/jax#installation
    get_ipython().run_line_magic('pip', 'install --upgrade "jax[cpu]"')
    import jax

try:
    import jsl
except:
    get_ipython().run_line_magic('pip', 'install git+https://github.com/probml/jsl')
    import jsl

try:
    import rich
except:
    get_ipython().run_line_magic('pip', 'install rich')
    import rich

# In[2]:

# Import standard libraries

import abc
from dataclasses import dataclass
import functools
import itertools

from typing import Any, Callable, NamedTuple, Optional, Union, Tuple

import matplotlib.pyplot as plt
import numpy as np

import jax
import jax.numpy as jnp
from jax import lax, vmap, jit, grad
from jax.scipy.special import logit
from jax.nn import softmax
from functools import partial
from jax.random import PRNGKey, split

import inspect
import inspect as py_inspect
from rich import inspect as r_inspect
from rich import print as r_print

def print_source(fname):
    r_print(py_inspect.getsource(fname))

# ## Utility code

# In[3]:

def normalize(u, axis=0, eps=1e-15):
    '''
    Normalizes the values within the axis in a way that they sum up to 1.
    Parameters
    ----------
    u : array
    axis : int
    eps : float
        Threshold for the alpha values
    Returns
    -------
    * array
        Normalized version of the given matrix
    * array(seq_len, n_hidden) :
        The values of the normalizer
    '''
    u = jnp.where(u == 0, 0, jnp.where(u < eps, eps, u))
    c = u.sum(axis=axis)
    c = jnp.where(c == 0, 1, c)
    return u / c, c

# (sec:casino-ex)=
# ## Example: Casino HMM
#
# We first create the "Ocassionally dishonest casino" model from {cite}`Durbin98`.
#
# ```{figure} /figures/casino.png
# :scale: 50%
# :name: casino-fig
#
# Illustration of the casino HMM.
# ```
#
# There are 2 hidden states, each of which emit 6 possible observations.

# In[4]:

# state transition matrix
A = np.array([
    [0.95, 0.05],
    [0.10, 0.90]
])

# observation matrix
B = np.array([
    [1/6, 1/6, 1/6, 1/6, 1/6, 1/6], # fair die
    [1/10, 1/10, 1/10, 1/10, 1/10, 5/10] # loaded die
])

pi, _ = normalize(np.array([1, 1]))
pi = np.array(pi)

(nstates, nobs) = np.shape(B)

# Let's make a little data structure to store all the parameters.
# We use NamedTuple rather than dataclass, since we assume these are immutable.
# (Also, standard python dataclass does not work well with JAX, which requires parameters to be
# pytrees, as discussed in https://github.com/google/jax/issues/2371).

# In[5]:

class HMM(NamedTuple):
    trans_mat: jnp.array  # A : (n_states, n_states)
    obs_mat: jnp.array  # B : (n_states, n_obs)
    init_dist: jnp.array  # pi : (n_states)

params = HMM(A, B, pi)
print(params)
print(type(params.trans_mat))

# ## Sampling from the joint
#
# Let's write code to sample from this model. First we code it in numpy using a for loop. Then we rewrite it to use jax.lax.scan, which is faster.

# In[6]:

def hmm_sample_numpy(params, seq_len, random_state=0):

    def sample_one_step_(hist, a, p):
        x_t = np.random.choice(a=a, p=p)
        return np.append(hist, [x_t]), x_t

    np.random.seed(random_state)

    trans_mat, obs_mat, init_dist = params.trans_mat, params.obs_mat, params.init_dist
    n_states, n_obs = obs_mat.shape

    state_seq = np.array([], dtype=int)
    obs_seq = np.array([], dtype=int)

    latent_states = np.arange(n_states)
    obs_states = np.arange(n_obs)

    state_seq, zt = sample_one_step_(state_seq, latent_states, init_dist)
    obs_seq, xt = sample_one_step_(obs_seq, obs_states, obs_mat[zt])

    for _ in range(1, seq_len):
        state_seq, zt = sample_one_step_(state_seq, latent_states, trans_mat[zt])
        obs_seq, xt = sample_one_step_(obs_seq, obs_states, obs_mat[zt])

    return state_seq, obs_seq

# In[7]:

seq_len = 20
state_seq, obs_seq = hmm_sample_numpy(params, seq_len, random_state=0)
print(state_seq)
print(obs_seq)

# Now let's write a JAX version.

# In[8]:

#@partial(jit, static_argnums=(1,))
def hmm_sample(params, seq_len, rng_key):

    trans_mat, obs_mat, init_dist = params.trans_mat, params.obs_mat, params.init_dist
    n_states, n_obs = obs_mat.shape

    initial_state = jax.random.categorical(rng_key, logits=logit(init_dist), shape=(1,))
    obs_states = jnp.arange(n_obs)

    def draw_state(prev_state, key):
        logits = logit(trans_mat[:, prev_state])
        state = jax.random.categorical(key, logits=logits.flatten(), shape=(1,))
        return state, state

    rng_key, rng_state, rng_obs = jax.random.split(rng_key, 3)
    keys = jax.random.split(rng_state, seq_len - 1)

    final_state, states = jax.lax.scan(draw_state, initial_state, keys)
    state_seq = jnp.append(jnp.array([initial_state]), states)

    def draw_obs(z, key):
        obs = jax.random.choice(key, a=obs_states, p=obs_mat[z])
        return obs

    keys = jax.random.split(rng_obs, seq_len)
    obs_seq = jax.vmap(draw_obs, in_axes=(0, 0))(state_seq, keys)

    return state_seq, obs_seq

# In[9]:

seq_len = 20
state_seq, obs_seq = hmm_sample(params, seq_len, PRNGKey(1))
print(state_seq)
print(obs_seq)


from google.cloud import storage
import os
from ses_email import send_email_default
from gcp_projects import get_projects
from gcp_authentication import get_key

"""Removes Global Permissions from Google Cloud Platform Buckets and sends Email with Bucket and Project Names"""

os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = get_key()
sendemail = False
bucket_dict = {}
bckts = []

for project_name in get_projects():
    storage_client = storage.Client(project=project_name)
    buckets = storage_client.list_buckets()

    for bucket in buckets:
        policy = bucket.get_iam_policy()
        for role in policy:
            members = policy[role]

            for member in members:
                if member == 'allUsers' or member == 'allAuthenticatedUsers':
                    sendemail = True
                    bucket_dict[bucket.name] = project_name
                    policy = bucket.get_iam_policy()
                    policy[role].discard(member)
                    bucket.set_iam_policy(policy)
                    print(bucket.name)
                    print(policy)
                    print(member)

subject = 'Globally Accessible Buckets Found and Fixed!'
body_text = '\n'.join({'Bucket:\t{0}\nProject:\t{1}\n'.format(key, value) for (key, value) in bucket_dict.items()})

if sendemail:
    send_email_default(subject, body_text)


#importing all the external modulues
import numpy as np

#Defined the given function
def f(x):
    return (x*np.log(x))-x

#This is the code for Trapezoidal ALgorithm
def Trapezoidal(a,b,f):    #a=inital value, b= Final Value, f=Function
    n=1000
    h=(b-a)/n
    g=(f(a)+f(b))/2
    for i in range (1,n):
        g=g+f(a+i*h)
    area=h*g
    return area

#This is the code for simpson algorithm
def Simpson(a,b,f):
    n=1000  #Here 'a' is Initial value,'b' is Final Value, 'f' is function
    h=(b-a)/n
    g=f(a)+f(b)
    for i in range (1,n,2):
        x_i=a+(i*h)
        g=g+4*f(x_i)
    for j in range (2,n,2):
        x_j=a+(j*h)
        g=g+2*f(x_j)
    A=(h/3)*g
    return A

print("The value of Integration using Trapezoidal method is:",Trapezoidal(1,3,f))
print("The value of Integration using Simpson method is:",Simpson(1,3,f))