import torch
import numpy as np
import time
import math

class BaseModule(torch.nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        return x

class Agent0(torch.nn.Module):
    def __init__(self,res=100):
        super().__init__()
        self.res = res
        self.grid = torch.nn.Parameter(torch.zeros((res,res)))

    def forward(self, x):

        pos_x = (x[:,0]*(self.res-1)).floor().long()
        pos_y = (x[:,1]*(self.res-1)).floor().long()
        value = self.grid[pos_x,pos_y]
        action = torch.rand((len(x),4), device=x.device)*2-1

        #print(torch.stack([pos_x, pos_y,value],1))
        return action, value[...,None]

class Agent1(torch.nn.Module):
    def __init__(self,in_features, hidden_dim):
        super().__init__()
        self.l1 = torch.nn.Linear(in_features, hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 1)

    def forward(self, x):
        x = torch.relu(self.l1(x))
        x = torch.relu(self.l2(x))
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent2(torch.nn.Module):
    def __init__(self,in_features, hidden_dim):
        super().__init__()
        self.l1 = torch.nn.Linear(in_features, hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.l3 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.l4 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 1)

    def forward(self, x):
        x = torch.relu(self.l1(x))
        x = torch.relu(self.l2(x))
        xr = x
        x = torch.relu(self.l3(x))
        x = torch.relu(self.l4(x)) + xr
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent3(torch.nn.Module):
    def __init__(self,in_features, hidden_dim):
        super().__init__()
        self.n = 3
        self.l1 = torch.nn.Linear(in_features*(self.n*2+1), hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 1)
        self.K = torch.pow(1.5, torch.arange(6))

    def forward(self, x):
        e=torch.empty(x.shape+(self.n*2,), device=x.device)
        for i in range(self.n):
            e[:,:,2*i+0]=torch.sin(x*self.K[i]+i)
            e[:,:,2*i+1]=torch.cos(x*self.K[i]+i)
        x = torch.concat([x,e.reshape(x.shape[0],-1)],-1)
        x = torch.relu(self.l1(x))
        x = torch.relu(self.l2(x))
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent4(torch.nn.Module):
    def __init__(self,in_features, hidden_dim, levels=16, table_size=2048, channels=2, growith_factor = 1.3):
        super().__init__()
        self.l1 = torch.nn.Linear(in_features+levels*channels, hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 1)

        self.levels = levels
        self.table_size = table_size
        self.channels = channels
        self.T = torch.nn.Parameter(torch.randn(levels, table_size, channels))
        self.K = torch.nn.Parameter(torch.pow(growith_factor, torch.arange(levels)[:,None]), requires_grad=False)

        self.PRIMES = [2654436881, 5915587277, 1500450271, 3267000013, 5754853343,
         4093082899, 9576890767, 3628273133, 2860486313, 5463458053,
         3367900313, 5654500741, 5654500763, 5654500771, 5654500783,
         5654500801, 5654500811, 5654500861, 5654500879, 5654500889,
         5654500897, 5654500927, 5654500961, 5654500981, 5654500993,
         9999999967, 7654487179, 7654489553, 7654495087, 7654486423,
         7654488209, 8654487029, 8654489771, 8654494517, 8654495341]

    def forward(self, x):

        self.K = self.K.to(x.device)
        p = (x.cumsum(-1)[:,None]*self.K)
        c = p.frac().sort(-1)[0]
        R = (p.frac()[...,None]>=c[...,None,:]).float()
        R = torch.concat([R,torch.zeros(*R.shape[:-1],1, device=x.device)],-1)
        c = torch.concat([c,torch.ones(*c.shape[:-1],1, device=x.device)],-1)
        A = R + p.floor()[...,None]
        A -= torch.concat([torch.zeros_like(A[...,-1:,:]),A[...,:-1,:]],-2)
        c -= torch.concat([torch.zeros_like(c[...,-1:]),c[...,:-1]],-1)

        cidx = A[:,:,0].long() * self.PRIMES[0]
        for i in range(1, A.shape[2]):
            cidx = cidx ^ (A[:,:,i].int() * self.PRIMES[i])

        feats=[]
        for i in range(self.levels):
            t=self.T[i]
            feats.append(t[cidx[:,i] % self.table_size])
        f = torch.stack(feats,1)
        f = (f*c[...,None]/self.K[...,None]).sum(2)

        x = torch.concat([x, f.reshape(x.shape[0],-1)],-1)

        x = torch.relu(self.l1(x))
        x = torch.relu(self.l2(x))
        action = self.action(x)
        value = self.value(x)
        return action, value

config={
	"optimizer": {
		"otype": "Adam",
		"learning_rate": 1e-2,
		"beta1": 0.9,
		"beta2": 0.99,
		"epsilon": 1e-15,
		"l2_reg": 1e-6
	},
	"encoding": {
		"otype": "HashGrid",
		"n_levels": 16,
		"n_features_per_level": 2,
		"log2_hashmap_size": 15,
		"base_resolution": 4,
		"per_level_scale": 1.3
	},
	"network": {
		"otype": "FullyFusedMLP",
		"activation": "ReLU",
		"output_activation": "None",
		"n_neurons": 64,
		"n_hidden_layers": 2
	}
}

import tinycudann as tcnn

class Agent5(torch.nn.Module):
    def __init__(self, in_coordinates, hidden_dim=64, levels=16, table_bit_size=15, channels=2, growith_factor = 1.25, base_res=1):
        super().__init__()

        self.in_coordinates=in_coordinates

        config__encoding = {
            "otype": "HashGrid",
            "n_levels": levels,
            "n_features_per_level": channels,
            "log2_hashmap_size": table_bit_size,
            "base_resolution": base_res,
            "per_level_scale": growith_factor
        }
        config_nn = {
            "otype": "FullyFusedMLP",
            "activation": "ReLU",
            "output_activation": "None",
            "n_neurons": hidden_dim,
            "n_hidden_layers": 2
	    }

        self.encodings = torch.nn.ParameterList()
        for _ in range(in_coordinates):
            self.encodings.append(tcnn.Encoding(2, config__encoding))

        self.nn = tcnn.Network(in_coordinates * levels * channels, 5, config_nn)

    def forward(self, x):

        x = x.reshape(x.shape[0], self.in_coordinates, 2)

        enc = []
        for i in range(self.in_coordinates):
            enc.append( self.encodings[i](x[:,i]) )
        x = torch.concat(enc,-1)
        x = self.nn(x)

        return x[:,:-1], x[:,-1:]

class Agent6(torch.nn.Module):
    def __init__(self,in_features, hidden_dim, heads=64, heads_dim=2, levels=5):
        super().__init__()

        self.heads = heads
        self.in_features = in_features
        self.hidden_dim = hidden_dim
        self.heads_dim = heads_dim
        self.levels= levels
        self.groups = 1

        self.l1 = torch.nn.Linear(in_features, hidden_dim)

        self.L_residual = torch.nn.ParameterList()
        for i in range(levels):
            lr1 = torch.nn.Linear(hidden_dim, hidden_dim)
            pr1 = torch.nn.Linear(hidden_dim, heads*heads_dim)
            lr2 = torch.nn.Linear((hidden_dim + heads)//self.groups, hidden_dim//self.groups)
            self.L_residual.append(torch.nn.ParameterList([lr1,pr1,lr2]))

        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 255)

    def forward(self, x):

        x = self.l1(x)

        for i in range(self.levels):
            lr1,pr1,lr2 = self.L_residual[i]
            xr = 2

            p1 = pr1(x).reshape(-1,self.heads, self.heads_dim)
            d1 = torch.norm(p1, dim=-1)
            x = torch.relu(lr1(x))
            x = torch.concat([x, d1],-1)

            x = x.reshape(-1,(self.hidden_dim + self.heads)//self.groups)
            x = torch.relu(lr2(x)).reshape(-1,self.hidden_dim)
            x = x + xr

        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent7(torch.nn.Module):
    def __init__(self,in_features, hidden_dim):
        super().__init__()

        self.in_features = in_features
        self.hidden_dim = hidden_dim

        self.l1 = torch.nn.Linear(in_features, hidden_dim)

        self.l2 = torch.nn.Linear(hidden_dim*2, hidden_dim)

        self.l3 = torch.nn.Linear(hidden_dim*2, hidden_dim)

        self.action = torch.nn.Linear(hidden_dim*2, 2*2)
        self.value = torch.nn.Linear(hidden_dim*2, 1)

    def forward(self, x):
        x = self.l1(x)
        x = torch.concat([x.relu(), x.square()],-1)

        x = self.l2(x)
        x = torch.concat([x.relu(), x.square()],-1)

        x = self.l3(x)
        x = torch.concat([x.relu(), x.square()],-1)

        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent8(torch.nn.Module):
    def __init__(self,in_features, hidden_dim):
        super().__init__()
        self.l1 = torch.nn.Linear(in_features, hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 1)

    def forward(self, x):
        x = self.l1(x).relu().square()
        x = self.l2(x).relu().square()
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent9(torch.nn.Module):
    def __init__(self,in_features, hidden_dim):
        super().__init__()
        self.l1 = torch.nn.Linear(in_features, hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 1)

    def forward(self, x):
        x = torch.exp(-self.l1(x).square())
        x = torch.exp(-self.l2(x).square())
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent10(torch.nn.Module):
    def __init__(self, in_points, hidden_dim):
        super().__init__()
        self.in_points = in_points
        self.n = 0
        self.l1 = torch.nn.Linear((in_points*2+in_points*(in_points-1))*(self.n*2+1), hidden_dim)
        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.action = torch.nn.Linear(hidden_dim, 2*2)
        self.value = torch.nn.Linear(hidden_dim, 255)
        self.K = torch.pow(1.5, torch.arange(6))

    def forward(self, x):

        S = x.shape

        xs = x.reshape(S[0], self.in_points, 2)
        c = torch.cdist(xs,xs)
        c = c.reshape(S[0], -1)[:,1:].reshape(S[0], self.in_points-1, self.in_points+1)[:,:,:-1].reshape(S[0], -1)

        x = torch.concat([x,c],-1)

        e=torch.empty(x.shape+(self.n*2,), device=x.device)
        for i in range(self.n):
            e[:,:,2*i+0]=torch.sin(x*self.K[i]+i)
            e[:,:,2*i+1]=torch.cos(x*self.K[i]+i)
        x = torch.concat([x,e.reshape(x.shape[0],-1)],-1)
        x = torch.relu(self.l1(x))
        x = torch.relu(self.l2(x))
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent11(torch.nn.Module):
    def __init__(self, in_points, hidden_dim):
        super().__init__()
        self.n = 2
        self.in_points = in_points
        self.t_L = torch.nn.TransformerEncoderLayer(d_model=2*(1+self.n*2), nhead=1+self.n*2, dim_feedforward=hidden_dim)
        self.T = torch.nn.TransformerEncoder(self.t_L, 2)
        self.action = torch.nn.Linear(in_points*2*(1+self.n*2), 4)
        self.value = torch.nn.Linear(in_points*2*(1+self.n*2), 1)
        self.K = torch.pow(1.5, torch.arange(6))

    def forward(self, x):
        e=torch.empty(x.shape+(self.n*2,), device=x.device)
        for i in range(self.n):
            e[:,:,2*i+0]=torch.sin(x*self.K[i]+i)
            e[:,:,2*i+1]=torch.cos(x*self.K[i]+i)
        x = torch.concat([x.reshape(x.shape[0], self.in_points, 2),e.reshape(x.shape[0], self.in_points, -1)], -1)
        x = self.T(x)
        x = x.reshape(x.shape[0], -1)
        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent12(torch.nn.Module):
    def __init__(self, in_features, heads=64, heads_dim=2):
        super().__init__()

        self.heads = heads
        self.in_features = in_features
        self.heads_dim = heads_dim

        self.p1 = torch.nn.Linear(in_features, heads*heads_dim)
        self.p2 = torch.nn.Linear(heads*(heads_dim+1), heads*heads_dim)
        self.p3 = torch.nn.Linear(heads*(heads_dim+1), heads*heads_dim)

        self.action = torch.nn.Linear(heads*(heads_dim+1), 2*2)
        self.value = torch.nn.Linear(heads*(heads_dim+1), 255)

    def forward(self, x):
        p1 = self.p1(x)
        d1 = torch.norm(p1.reshape(-1,self.heads, self.heads_dim), dim=-1)
        x = torch.relu(p1)
        x = torch.concat([x, d1],-1)

        p2 = self.p2(x)
        d2 = torch.norm(p2.reshape(-1,self.heads, self.heads_dim), dim=-1)
        x = torch.relu(p2)
        x = torch.concat([x, d2],-1)

        p3 = self.p3(x)
        d3 = torch.norm(p3.reshape(-1,self.heads, self.heads_dim), dim=-1)
        x = torch.relu(p3)
        x = torch.concat([x, d3],-1)

        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent13(torch.nn.Module):
    def __init__(self, in_points, hidden_dim, levels=3):
        super().__init__()
        self.in_points = in_points

        self.l1 = torch.nn.Linear((in_points*2), hidden_dim)
        self.p1 = torch.nn.Parameter(torch.randn((hidden_dim, in_points*2)))
        self.l2 = torch.nn.Linear(hidden_dim*2, hidden_dim)
        self.p2 = torch.nn.Parameter(torch.randn((hidden_dim, hidden_dim*2)))
        self.action = torch.nn.Linear(hidden_dim*2, 2*2)
        self.value = torch.nn.Linear(hidden_dim*2, 255)
        self.eps = 1e-10

    def forward(self, x):

        l = self.l1(x).relu()
        p = (self.p1.exp()/x.shape[-1] @ x.square()[...,None] + self.eps).sqrt()[...,0]
        x = torch.concat([l,p],-1)

        l = self.l2(x).relu()
        p = (self.p2.exp()/x.shape[-1] @ x.square()[...,None] + self.eps).sqrt()[...,0]
        x = torch.concat([l,p],-1)

        action = self.action(x)
        value = self.value(x)
        return action, value

class Agent14(torch.nn.Module):
    def __init__(self, in_points, hidden_dim):
        super().__init__()
        self.in_points = in_points
        in_features = in_points*2
        self.l1 = torch.nn.Linear(in_features + in_features**2 + in_points*(in_points-1), hidden_dim)
        #self.l1 = torch.nn.Linear(in_features, hidden_dim)

        self.l2 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.l3 = torch.nn.Linear(hidden_dim, hidden_dim)

        self.l4 = torch.nn.Linear(hidden_dim, hidden_dim)
        self.l5 = torch.nn.Linear(hidden_dim, hidden_dim)

        self.action = torch.nn.Linear(hidden_dim, 25)
        self.value = torch.nn.Linear(hidden_dim, 255)
        with torch.no_grad():
            #self.action.weight[:] *= 0.1
            #self.action.bias[:] = 1/hidden_dim
            self.value.weight[:] = 1
            self.value.bias[:]= 0
            pass

    def forward(self, x):

        S = x.shape

        x2 = x[:,None]*x[:,:,None]/2

        xs = x.reshape(S[0], self.in_points, 2)
        c = torch.cdist(xs,xs)
        c = c.reshape(S[0], -1)[:,1:].reshape(S[0], self.in_points-1, self.in_points+1)[:,:,:-1].reshape(S[0], -1)

        x = torch.concat([x,x2.flatten(1),c],1)#,x3.flatten(1)
        x = torch.relu(self.l1(x))

        xr = x
        x = torch.relu(self.l2(x))
        x = torch.relu(self.l3(x)) + xr

        xr = x
        x = torch.relu(self.l4(x))
        x = torch.relu(self.l5(x)) + xr

        action = self.action(x)
        value = self.value(x)
        return action, value


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

import pygame
import os
from pygame.locals import *
from utemper_public import *
import utemper_screen_image

class cScreen_2:
    pantalla=0
    carpeta_img = "img/dia/"
    letra_color = (0,0,0)
    cUtemperSceenImagen=None
    screen = None

    def __init__(self, screen):
        self.screen = screen
        try:
            self.cUtemperSceenImagen = utemper_screen_image.cScreenImeges()
            self.Letra = pygame.font.Font("font/stag-sans-light-webfont.ttf", 20)
            self.pantalla=1
        except:
            log(4,"Imposible iniciar la pantalla 2 ")
            self.pantalla=0

    def refrescar_screen(self):
        if (self.pantalla==0):
            log(3," Pantalla inactiva: Imposible refrescar la pantalla 2 ")
            return
        if (gv.noche==1):
            self.carpeta_img="img/noche/"
            self.letra_color=(255,255,255)
        else:
            self.carpeta_img="img/dia/"
            self.letra_color=(0,0,0)

        # cargamos el fondo
        fichero_fondo = self.carpeta_img+"fondo/config_fondo.jpg"
        fondo = self.cUtemperSceenImagen.getImagen(fichero_fondo)
        self.screen.blit(fondo, (0, 0))

        #text
        mytext = self.Letra.render("Seleciona el modo.", False, self.letra_color).convert_alpha()
        posX = (gv.screen_widht/2) - (mytext.get_size()[0]/2)
        self.screen.blit(mytext, (posX ,15))

        #botones.
        icon = self.cUtemperSceenImagen.getImagen(self.carpeta_img+"iconos/boton_0.png")
        posX = (gv.screen_widht/2) - (icon.get_size()[0]/2)
        self.screen.blit(icon, (posX,55))

        icon = self.cUtemperSceenImagen.getImagen(self.carpeta_img+"iconos/boton_1.png")
        posX = (gv.screen_widht/2) - (icon.get_size()[0]/2)
        self.screen.blit(icon, (posX,100))

        icon = self.cUtemperSceenImagen.getImagen(self.carpeta_img+"iconos/boton_2.png")
        posX = (gv.screen_widht/2) - (icon.get_size()[0]/2)
        self.screen.blit(icon, (posX,155))

        # se muestran lo cambios en pantalla
        pygame.display.flip()
        log(1,"Refrescar screen 2 OK")

    def boton_screen (self, pos):
        # Entrar menu
        self.screen_number = 1


import os
import subprocess
from libqtile import layout, bar, hook
from libqtile.config import Click, Drag, DropDown, Group, Key, Match, ScratchPad, Screen, Rule
from libqtile.command import lazy
from bar import widget_defaults, init_widgets_list
# from thin_bar import widget_defaults, init_widgets_list

mod = "mod4"
term = "kitty"
browser = "brave"
editor = "code"
file_manager = "thunar"

keys = [
    # Qtile window manager
    Key([mod, "control"], "r", lazy.restart(), desc='Restart Qtile'),
    Key([mod, "control"], "p", lazy.shutdown(), desc='Shutdown Qtile'),
    Key([mod, "control"], "s", lazy.spawn(
        f'{term} --hold -e python3 .config/qtile/scripts/qtile-keys'), desc='Show qtile keys'),

    # Common
    Key([mod], "q", lazy.window.kill(), desc='Kill window'),
    Key([mod], "x", lazy.spawn("archlinux-logout"), desc='Logout menu'),
    Key([mod, "control"], "y", lazy.spawn(
        "betterlockscreen -l dim -- --time-str='%H:%M'"), desc='Lock screen'),
    Key([mod], "p", lazy.spawncmd(), desc='Spawn prompt in the bar'),

    # Launch
    Key([mod], "Return", lazy.spawn(term), desc='Launch terminal'),
    Key([mod, 'shift'], "Return", lazy.spawn(
        f'{term} -e tmux a'), desc='Launch tmux terminal attached to last session'),
    Key([mod, 'shift'], "f", lazy.spawn(
        file_manager), desc='Launch file manager'),
    Key([mod], "b", lazy.spawn(browser), desc='Launch browser'),
    Key([mod], "c", lazy.spawn("code"), desc='Launch vscode'),
    Key([mod], 'd', lazy.spawn("discord")),
    Key([mod], "r", lazy.spawn("rofi -show drun"), desc='Spawn app launcher'),
    Key([mod], "F11", lazy.spawn("rofi-theme-selector"), desc='Change rofi theme'),

    # Toggle between layouts
    Key([mod], "space", lazy.next_layout(), desc='Toggle between layouts'),

    # Monitor focus
    Key([mod], "w", lazy.to_screen(0), desc='Focus monitor 1'),
    Key([mod], "e", lazy.to_screen(1), desc='Focus monitor 2'),
    Key([mod], "t", lazy.to_screen(2), desc='Focus monitor 3'),

    # Window focus
    Key([mod], "h", lazy.layout.left(), desc='Focus window left'),
    Key([mod], "l", lazy.layout.right(), desc='Focus window right'),
    Key([mod], "j", lazy.layout.down(), desc='Focus window down'),
    Key([mod], "k", lazy.layout.up(), desc='Focus window up'),
    Key([mod], "s", lazy.spawn("rofi -show"), desc='Show open windows'),

    # Window move
    Key([mod, "shift"], "h", lazy.layout.shuffle_left(), desc="Move window left"),
    Key([mod, "shift"], "l", lazy.layout.shuffle_right(), desc="Move window right"),
    Key([mod, "shift"], "j", lazy.layout.shuffle_down(), desc="Move window down"),
    Key([mod, "shift"], "k", lazy.layout.shuffle_up(), desc="Move window up"),

    # Window resize
    Key([mod], "f", lazy.window.toggle_fullscreen(),
        desc='Toggle window fullscreen'),
    Key([mod], "m", lazy.window.toggle_maximize(),
        desc='Toggle window maximize'),
    Key([mod], "n", lazy.window.toggle_minimize(),
        desc='Toggle window minimize'),
    Key([mod, "shift"], "space", lazy.window.toggle_floating(),
        desc='Toggle window floating'),

    Key([mod, "control"], "h", lazy.layout.grow_left(), desc="Grow window left"),
    Key([mod, "control"], "l", lazy.layout.grow_right(), desc="Grow window right"),
    Key([mod, "control"], "j", lazy.layout.grow_down(), desc="Grow window down"),
    Key([mod, "control"], "k", lazy.layout.grow_up(), desc="Grow window up"),

    # Media
    Key([], "XF86AudioLowerVolume", lazy.spawn(
        "pactl set-sink-volume @DEFAULT_SINK@ -5%"
    )),
    Key([], "XF86AudioRaiseVolume", lazy.spawn(
        "pactl set-sink-volume @DEFAULT_SINK@ +5%"
    )),
    Key([], "XF86AudioMute", lazy.spawn(
        "pactl set-sink-mute @DEFAULT_SINK@ toggle"
    )),
]

def window_to_previous_screen(qtile, switch_group=False, switch_screen=False):
    i = qtile.screens.index(qtile.current_screen)
    if i != 0:
        group = qtile.screens[i - 1].group.name
        qtile.current_window.togroup(group, switch_group=switch_group)
        if switch_screen == True:
            qtile.cmd_to_screen(i - 1)

def window_to_next_screen(qtile, switch_group=False, switch_screen=False):
    i = qtile.screens.index(qtile.current_screen)
    if i + 1 != len(qtile.screens):
        group = qtile.screens[i + 1].group.name
        qtile.current_window.togroup(group, switch_group=switch_group)
        if switch_screen == True:
            qtile.cmd_to_screen(i + 1)

# Move window to screen
keys.extend([
    Key([mod, "shift"], "Right", lazy.function(window_to_next_screen,
        switch_screen=True), desc='Move window to right screen'),
    Key([mod, "shift"], "Left", lazy.function(window_to_previous_screen,
        switch_screen=True), desc='Move window to left screen'),
])

#  ", "   ", "   ", "   ", "  ", "   ", "   ", "   ", "   ", 

groups = [
    Group("1", label="1", layout='columns', spawn=browser),
    Group("2", label="2", layout='columns'),
    Group("3", label="3", layout='columns'),
    Group("4", label="6"),
    Group("5", label="9"),
    Group("6", label=""),
    Group("7", label="ﭮ"),
    Group("8", label=""),
    Group("9", label=""),
]

for i in groups:
    keys.extend([
        # Switch workspace
        Key([mod], i.name, lazy.group[i.name].toscreen(),
            desc=f'Switch to workspace {i.name}'),
        Key([mod], "Tab", lazy.screen.next_group(),
            desc='Switch to next workspace'),
        Key([mod, "shift"], "Tab", lazy.screen.prev_group(),
            desc='Switch to previous workspace'),

        # Move window to workspace and follow
        Key([mod, "shift"], i.name, lazy.window.togroup(i.name), lazy.group[i.name].toscreen(),
            desc='Move window to workspace and follow'),

        # Move window to workspace and stay
        # Key([mod, "shift"], i.name, lazy.window.togroup(i.name)),
    ])

groups.append(ScratchPad('scratchpad', [
    DropDown('term', term, width=0.8, height=0.8, x=0.1, y=0.1),
    DropDown('files', file_manager, width=0.35, height=0.8, x=0.3, y=0.1),
    DropDown('search', 'firefox', width=0.6, height=0.8, x=0.2, y=0.1),
]))

keys.extend([
    Key(['mod1'], '1', lazy.group['scratchpad'].dropdown_toggle('term')),
    Key(['mod1'], '2', lazy.group['scratchpad'].dropdown_toggle('files')),
    Key(['mod1'], '3', lazy.group['scratchpad'].dropdown_toggle('search')),
])

main_theme = {
    "margin": 5,
    "single_border_width": 0,
    "border_width": 1,
    "border_focus": "#71a381",
    "border_normal": "#4c566a",
}

columns_theme = {
    'margin': 2,
    'margin_on_single': 5,
    'border_on_single': False,
    "border_width": 1,
    "border_focus": "#71a381",
    "border_normal": "#4c566a",
}

layouts = [
    layout.Columns(**columns_theme),
    layout.MonadTall(**main_theme),
    layout.MonadWide(**main_theme),
    layout.Floating(**main_theme),
    # layout.RatioTile(**layout_theme),
    # layout.Tile(shift_windows=True, **layout_theme),
    # layout.Max(**layout_theme),
    # layout.Bsp(**layout_theme),
    # layout.Stack(stacks=2, **layout_theme),
    # layout.VerticalTile(**layout_theme),
    # layout.Matrix(**layout_theme),
    # layout.Zoomy(**layout_theme)
]

def init_widgets_screen1():
    widgets_screen1 = init_widgets_list()
    return widgets_screen1

def init_widgets_screen2():
    widgets_screen2 = init_widgets_list()
    return widgets_screen2

widgets_screen1 = init_widgets_screen1()
widgets_screen2 = init_widgets_screen2()

# Mouse config
mouse = [
    Drag([mod], "Button1", lazy.window.set_position_floating(),
         start=lazy.window.get_position()),
    Drag([mod], "Button3", lazy.window.set_size_floating(),
         start=lazy.window.get_size()),
    Click([mod], "Button2", lazy.window.bring_to_front())
]

def init_screens():
    return [Screen(top=bar.Bar(widgets=init_widgets_screen1(), size=18, opacity=1, margin=[0, 0, 0, 0])),
            Screen(top=bar.Bar(widgets=init_widgets_screen2(), size=18, opacity=1, margin=[0, 0, 0, 0]))
            ]

if __name__ in ["config", "__main__"]:
    screens = init_screens()
    widgets_list = init_widgets_list()
    widgets_screen1 = init_widgets_screen1()
    widgets_screen2 = init_widgets_screen2()

dgroups_key_binder = None
dgroups_app_rules = []
follow_mouse_focus = True
bring_front_click = False
cursor_warp = False
auto_fullscreen = True
focus_on_window_activation = 'focus'
reconfigure_screens = True

def window_to_prev_group(qtile):
    if qtile.currentWindow is not None:
        i = qtile.groups.index(qtile.currentGroup)
        qtile.currentWindow.togroup(qtile.groups[i - 1].name)

def window_to_next_group(qtile):
    if qtile.currentWindow is not None:
        i = qtile.groups.index(qtile.currentGroup)
        qtile.currentWindow.togroup(qtile.groups[i + 1].name)

def switch_screens(qtile):
    i = qtile.screens.index(qtile.current_screen)
    group = qtile.screens[i - 1].group
    qtile.current_screen.set_group(group)

@hook.subscribe.client_new
def set_floating(window):
    if (window.window.get_wm_transient_for()
            or window.window.get_wm_type() in floating_types):
        window.floating = True

floating_types = ["notification", "toolbar", "splash", "dialog"]

floating_layout = layout.Floating(float_rules=[
    # Run the utility of `xprop` to see the wm class and name of an X client.
    *layout.Floating.default_float_rules,
    Match(wm_class='confirmreset'),  # gitk
    Match(wm_class='makebranch'),  # gitk
    Match(wm_class='maketag'),  # gitk
    Match(wm_class='ssh-askpass'),  # ssh-askpass
    Match(title='branchdialog'),  # gitk
    Match(title='pinentry'),  # GPG key password entry
    Match(wm_class='confirm'),
    Match(wm_class='dialog'),
    Match(wm_class='download'),
    Match(wm_class='error'),
    Match(wm_class='file_progress'),
    Match(wm_class='notification'),
    Match(wm_class='splash'),
    Match(wm_class='toolbar'),
    Match(wm_class='Arandr'),
    Match(wm_class='feh'),
    Match(wm_class='Galculator'),
    Match(wm_class='arcolinux-logout'),
    Match(wm_class='xfce4-terminal'),
])

# Startup
@hook.subscribe.startup_once
def start_once():
    home = os.path.expanduser('~')
    subprocess.call([home + '/.config/qtile/scripts/autostart.sh'])

wmname = "LG3D"


#!/usr/bin/env python
"""
cs115_proj_1 Tax Calculator
Andrew Seith Miller
Release Date: 1/4/2016

This module supplies one function cal_total_with_tax(). For example,

>>> cal_total_with_tax()
Please input the amount of purchase: 100
Amount of purchase:               100.00
State tax:                          5.00
County tax:                         2.50
County tax:                       107.50

Know Limitation: accepts floats with more then 2 decimal places
but formats output down to just 2 decimal places
"""

def cal_total_with_tax():
    """prompt the user to input their "amount of purchase",
    calculate the state, and county tax for their purchase,
    print a receipt.
    """

    my_format = '{0:<20}{1:>20,.2f}'  # set your desired output format

    """input: prompts user for amount of purchase"""
    purchase_amount = float(input('Please input the amount of purchase: '))

    """calculation: does all the maths"""
    state_tax = 0.05 * purchase_amount
    county_tax = 0.025 * purchase_amount
    total_of_sale = purchase_amount + state_tax + county_tax

    """output: print the receipt"""
    print(my_format.format('Amount of purchase:', purchase_amount))
    print(my_format.format('State tax:', state_tax))
    print(my_format.format('County tax:', county_tax))
    print(my_format.format('County tax:', total_of_sale))

if __name__ == "__main__":
    cal_total_with_tax()


'''
This is the beginning of the book Data Science from Scratch, by Joel Grus (O'Reilly)
'''

users = [
    {"id":0, "name": "Hero"},
    {"id":1, "name": "Dunn"},
    {"id":2, "name": "Sue"},
    {"id":3, "name": "Chi"},
    {"id":4, "name": "Tjor"},
    {"id":5, "name": "Clive"},
    {"id":6, "name": "Hicks"},
    {"id":7, "name": "Devin"},
    {"id":8, "name": "Kate"},
    {"id":9, "name": "Klein"}]

friendships = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 4),
               (4, 5), (5, 6), (5, 7), (6, 8), (7, 8), (8, 9)]

for user in users:
    user["friends"] = []

for i, j in friendships:
    # this works only because users[i] is the user whose id is i
    users[i]["friends"].append(users[j]) # add i as a friend of j
    users[j]["friends"].append(users[i]) # add j as a friend of i

def number_of_friends(user):
    """how many friends does this _user_ have?"""
    return len(user["friends"])

total_connections = sum(number_of_friends(user) for user in users)
num_users = len(users)

avg_connections = total_connections / num_users

# let's find the most connected people

# create a list (user_is, number of friends)
num_friends_by_id = [(user["id"], number_of_friends(user)) for user in users]

sorted(num_friends_by_id, key=lambda num_friends_by_id: num_friends_by_id[1], reverse=True)

################################
#                              #
# DATA SCIENTISTS YOU MAY KNOW #
#                              #
################################

def friends_of_friends_ids_bad(user):
    return [foaf["id"] for friend in user["friends"] for foaf in friend["friends"]]

from collections import Counter

def not_the_same(user, other_user):
    # two users are not the same if they don'' share the same id
    return user["id"] != other_user["id"]

def not_friends(user, other_user):
    """other user is not a friend if he is not in user["friends"]; that is, if he'' not_the_same as all the people in user["friends"]"""
    return all(not_the_same(friend, other_user) for friend in user["friends"])

def friends_of_friends_ids(user):
    return Counter(foaf["id"]
                   for friend in user["friends"]
                   for foaf in friend["friends"]
                   if not_the_same(user, foaf)
                   and not_friends(user, foaf))
print(friends_of_friends_ids(users[3]))

##########      MUTUAL INTERESTS

interests = [
    (0, "Hadoop"), (0, "Big Data"), (0, "HBase"), (0, "Java"),
    (0, "Spark"), (0, "Storm"), (0, "Cassandra"),
    (1, "NoSQL"), (1, "MongoDB"), (1, "Cassandra"), (1, "HBase"),
    (1, "Postgres"), (2, "Python"), (2, "scikit-learn"), (2, "scipy"),
    (2, "numpy"), (2, "statsmodels"), (2, "pandas"), (3, "R"), (3, "Python"),
    (3, "statistics"), (3, "regression"), (3, "probability"),
    (4, "machine learning"), (4, "regression"), (4, "decision trees"),
    (4, "libsvm"), (5, "Python"), (5, "R"), (5, "Java"), (5, "C++"),
    (5, "Haskell"), (5, "programming languages"), (6, "statistics"),
    (6, "probability"), (6, "mathematics"), (6, "theory"),
    (7, "machine learning"), (7, "scikit-learn"), (7, "Mahout"),
    (7, "neural networks"), (8, "neural networks"), (8, "deep learning"),
    (8, "Big Data"), (8, "artificial intelligence"), (9, "Hadoop"),
    (9, "Java"), (9, "MapReduce"), (9, "Big Data")
]

def data_scientists_who_like(target_interest):
    return [user_id
            for user_id, user_interest in interests
            if user_interest == target_interest]

from collections import defaultdict

# keys are interests, values are lists of user_ids with that interest
user_ids_by_interest = defaultdict(list)

for user_id, interest in interests:
    user_ids_by_interest[interest].append(user_id)

# keys are user_ids, values are lists of interests for that user_id

interests_by_user_id = defaultdict(list)

for user_id, interest in interests:
    interests_by_user_id[user_id].append(interest)

'''
To find who has the most interests in common with a given user:
- iterate over the user's interests
- for each interest, iterate over the other users with that interest
- keep count of how many times we see each other user
'''

def most_common_interests_with(user):
    return Counter(interested_user_id
                   for interest in interests_by_user_id[user["id"]]
                   for interested_user_id in user_ids_by_interest[interest]
                   if interested_user_id != user["id"])

################################
#                              #
#    SALARIES AND EXPERIENCE   #
#                              #
################################

salaries_and_tenures = [(83000, 8.7), (88000, 8.1),
                        (48000, 0.7), (76000, 6),
                        (69000, 6.5), (76000, 7.5),
                        (60000, 2.5), (83000, 10),
                        (48000, 1.9), (63000, 4.2)]

def tenure_bucket(tenure):
    if tenure < 2:
        return "less than 2"
    elif tenure < 5:
        return "between 2 and 5"
    else:
        return "more than 5"

# keys are tenure buckets, values are lists of salaries for that bucket
salary_by_tenure_bucket = defaultdict(list)

for salary, tenure in salaries_and_tenures:
    bucket = tenure_bucket(tenure)
    salary_by_tenure_bucket[bucket].append(salary)

# compute the avarage salary for each bucket

# keys are tenure buckets, values are average salary for that bucket
average_salary_by_bucket = {
    tenure_bucket : sum(salaries) / len(salaries)
    for tenure_bucket, salaries in salary_by_tenure_bucket.items()
}

print(average_salary_by_bucket)

################################
#                              #
#         PAID ACCOUNT         #
#                              #
################################

def predict_paid_or_unpaid(years_experience):
    if years_experience < 3.0:
        return "paid"
    elif years_experience < 8.5:
        return "unpaid"
    else:
        return "paid"

################################
#                              #
#      TOPICS OF INTEREST      #
#                              #
################################

words_and_counts = Counter (word
                            for user, interest in interests
                            for word in interest.lower().split())

for word, count in words_and_counts.most_common():
    if count > 1:
        print(word, count)


import csv
import datetime as dt
import os
import pickle
import sqlite3
import wx

# Import forsteri modules.
from forsteri.interface import data as idata
from forsteri.interface import sql as isql

# Create global labels.
LABELS = ["product", "sku", "account", "class", "category", "subcategory"]

class OpenDialog(wx.Dialog):
    """
    A dialog containing all products that are contained within the master
    database. Also, a sorting feature based on the product's description is
    included. From this dialog products can be altered, added, and removed.
    This is the location where reports will be generated and products will be
    opened.

    Extends:
      wx.Dialog

    To Do:
      1) Make the updating of list items occur without removing all items and
        adding new back.
      2) Add ways to search for products. Being by chemical or component.
      3) Make the header clickable and sort by that column when clicked.
    """

    def __init__(self, *args, **kwargs):
        """
        Initialize the open products dialog.

        Args:
          *args (tuple of object): Any arguments to be passed directly to the
            super's constructor.
          **kwargs (dictionary of name: object): Any keyword arguments to be
            passed to the super's constructor.

        Returns:
          OpenDialog
        """

        ## Frame
        # Initialize by the parent's constructor.
        super(OpenDialog, self).__init__(*args, **kwargs)

        # Create the sieve.
        self.sieve = dict.fromkeys(LABELS)

        # Create the master panel.
        masterPanel = wx.Panel(self)

        # Create the master sizer.
        masterSizer = wx.BoxSizer(wx.HORIZONTAL)

        ## Search By
        # Create the search by static box.
        searchSB = wx.StaticBox(masterPanel, label="Search by")

        # Create the search sizer.
        searchSizer = wx.StaticBoxSizer(searchSB, wx.VERTICAL)

        # Create the name type sizer.
        nameSizer = wx.BoxSizer(wx.HORIZONTAL)

        # Create the name type radio buttons.
        self.productRB = wx.RadioButton(masterPanel, label="Product",
            style=wx.RB_GROUP)
        skuRB = wx.RadioButton(masterPanel, label="Sku")

        # Add the name type radio buttons to the name type sizer.
        nameSizer.AddMany([(5, 0), self.productRB, (25, 0), skuRB, (5, 0)])

        # Bind the radio buttons to a function.
        self.productRB.Bind(wx.EVT_RADIOBUTTON, self.updateList)
        skuRB.Bind(wx.EVT_RADIOBUTTON, self.updateList)

        # Get the label strings and combo box choices.
        choices = self.getChoices()

        # Create the text labels and input boxes.
        textLabels = [None] * 4
        self.inputs = [None] * 5

        # Create the text entry for the name.
        self.inputs[0] = wx.TextCtrl(masterPanel, size=(150, -1))

        # Add the name type and text entry to the search sizer.
        searchSizer.AddMany([(0, 10), nameSizer, (0, 5)])
        searchSizer.Add(self.inputs[0], flag=wx.LEFT|wx.RIGHT, border=5)

        # Bind text entry to a function.
        self.inputs[0].Bind(wx.EVT_TEXT, self.updateList)

        # Create subsequent label and combo boxes, add them to the search
        # sizer, and bind them to functions.
        for i in range(0, 3):
            textLabels[i] = wx.StaticText(masterPanel,
                label=LABELS[i + 2].title())
            self.inputs[i + 1] = wx.ComboBox(masterPanel, size=(150, -1),
                choices=choices[i], style=wx.CB_READONLY|wx.CB_SORT)
            searchSizer.AddSpacer(10)
            searchSizer.Add(textLabels[i], flag=wx.LEFT|wx.BOTTOM, border=5)
            searchSizer.Add(self.inputs[i + 1], flag=wx.LEFT|wx.RIGHT,
                border=5)
            self.inputs[i + 1].Bind(wx.EVT_COMBOBOX, self.updateList)

        ## Selection
        # Create the selection sizer.
        selectSizer = wx.BoxSizer(wx.VERTICAL)

        ## List Control
        # Create the list control.
        self.productList = wx.ListCtrl(masterPanel, size=(710, 400),
            style=wx.LC_REPORT|wx.LC_HRULES|wx.LC_VRULES|wx.BORDER_SUNKEN)

        # Add columns to the list control.
        self.productList.InsertColumn(0, "Product", width=136)
        self.productList.InsertColumn(1, "Account", width=136)
        self.productList.InsertColumn(2, "Class", width=136)
        self.productList.InsertColumn(3, "Category", width=136)
        #self.productList.InsertColumn(4, "Subcategory", width=136)

        # Bind the selection of an item to a function.
        self.productList.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSelected)
        self.productList.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.onSelected)
        self.productList.Bind(wx.EVT_LEFT_DCLICK, self.onOpen)

        ## Manipulate Buttons
        # Create the manipulate sizer.
        manipSizer = wx.BoxSizer(wx.HORIZONTAL)

        # Create the buttons.
        self.addButton = wx.Button(masterPanel, id=wx.ID_ADD)
        self.editButton = wx.Button(masterPanel, id=wx.ID_EDIT)
        self.deleteButton = wx.Button(masterPanel, id=wx.ID_DELETE)

        # Add the buttons to the manipulate sizer.
        manipSizer.AddMany([self.addButton, (5, 0), self.editButton, (5, 0),
            self.deleteButton])

        # Create a timer for edit.
        self.timer = wx.Timer(self)

        # Bind the timer to a function.
        self.Bind(wx.EVT_TIMER, self.onTimer)

        # Bind button presses to functions.
        self.addButton.Bind(wx.EVT_ENTER_WINDOW, self.onMouseOverAdd)
        self.addButton.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseOffAdd)
        self.addButton.Bind(wx.EVT_BUTTON, self.onAdd)
        self.editButton.Bind(wx.EVT_BUTTON, self.onEdit)
        self.deleteButton.Bind(wx.EVT_BUTTON, self.onDelete)

        # Add tool tips to the buttons.
        self.addButton.SetToolTipString("Add a product to the database. " +\
            "Hover over to switch to multi-add mode.")
        self.editButton.SetToolTipString("Edit the selected product(s).")
        self.deleteButton.SetToolTipString("Delete the selected product(s).")

        ## Finish Buttons
        # Create the finish sizer.
        finishSizer = wx.BoxSizer(wx.HORIZONTAL)

        # Create the buttons.
        reportButton = wx.Button(masterPanel, label="&Report")
        openButton = wx.Button(masterPanel, id=wx.ID_OPEN)
        applyButton = wx.Button(masterPanel, id=wx.ID_APPLY)
        cancelButton = wx.Button(masterPanel, id=wx.ID_CANCEL)

        # Set the ok button to be the dafault button.
        openButton.SetDefault()

        # Add the buttons to the finish sizer.
        finishSizer.AddMany([reportButton, (5, 0), openButton, (5, 0),
            applyButton, (5, 0), cancelButton, (5, 0)])

        # Bind the button presses to function.
        reportButton.Bind(wx.EVT_BUTTON, self.onReport)
        openButton.Bind(wx.EVT_BUTTON, self.onOpen)
        applyButton.Bind(wx.EVT_BUTTON, self.onApply)
        cancelButton.Bind(wx.EVT_BUTTON, self.onCancel)

        # Add tool tips to the buttons.
        reportButton.SetToolTipString("Generate a forecast report for the " +\
            "selected product(s).")
        openButton.SetToolTipString("Open the selected product.")
        applyButton.SetToolTipString("Record any changes to products.")
        cancelButton.SetToolTipString("Cancel any changes to products and " +\
            "close.")

        ## Key Bindings
        # Create a new id for selecting all.
        selectAllId = wx.NewId()

        # Bind the id to a function.
        self.Bind(wx.EVT_MENU, self.selectAll, id=selectAllId)

        # Create a new accelerator table and set it to the frame.
        accelT = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord("A"), selectAllId)])
        self.SetAcceleratorTable(accelT)

        # Add the items to the selection sizer.
        selectSizer.Add(self.productList,
            flag=wx.LEFT|wx.RIGHT|wx.TOP, border=5)
        selectSizer.AddSpacer(10)
        selectSizer.Add(manipSizer, flag=wx.ALIGN_CENTER)
        selectSizer.AddSpacer(9)
        selectSizer.Add(wx.StaticLine(masterPanel, size=(710, 2)),
            flag=wx.ALIGN_CENTER)
        selectSizer.AddSpacer(9)
        selectSizer.Add(finishSizer, flag=wx.ALIGN_RIGHT)
        selectSizer.AddSpacer(5)

        ## Frame Operations
        # Add everything to the master sizer.
        masterSizer.Add(searchSizer,
            flag=wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_TOP|wx.EXPAND, border=5)
        masterSizer.Add(selectSizer, flag=wx.EXPAND)

        # Open a connection to the database.
        self.connection = sqlite3.connect(isql.MASTER)

        # Update the displayed list.
        self.updateList(None)

        # Set the sizer for the main panel.
        masterPanel.SetSizer(masterSizer)

        # Set window properties.
        self.SetSize((900-136, 528))
        self.Centre()

    """
    Manipulate Functions
    """
    def getSelection(self):
        """
        """

        # Get the first selected index.
        productIndex = self.productList.GetFirstSelected()

        # Determine how many products are selected.
        count = self.productList.GetSelectedItemCount()

        # Create a list of products.
        selected = []

        # Iterate over all selected products.
        index = 1
        while index <= count:
            # Add the next product to the list of products.
            selected.append(self.productList.GetItemText(productIndex))

            # Find the next selected index.
            productIndex = self.productList.GetNextSelected(productIndex)

            # Increment the index.
            index += 1

        return selected

    """
    Helper Functions
    """
    def getChoices(self):
        """
        Pull the possible choices for the combo boxes from the database.

        Args:
          None

        Returns:
          list of list of str: The lists of choices for each combo box in the
            dialog box.
        """

        # Get the list of tiers.
        tiers = isql.getTiers()

        # Get each list associated with each tier.
        connect = []
        for tier in tiers:
            tierList = isql.getForTier(tier)

            # Add an empty string for selection.
            tierList.append("")

            # Append the entire list to the returned list.
            connect.append(tierList)

        # Switch the indices of category and class.
        connect[1], connect[2] = connect[2], connect[1]

        return connect

    def readAddData(self, path):
        """
        """

        # Open the file and save it in the data variable.
        newData = []
        newProducts = []
        with open(path) as csvFile:
            reader = csv.reader(csvFile, delimiter=',', quotechar='|')
            for row in reader:
                # Find the length of the row.
                rowLength = len(row)

                # If the row is shorter than 6, pad the end with empty strings.
                if rowLength < 6:
                    for i in range(rowLength, 6):
                        row.append("")

                # Append the data and product list with the input data.
                newData.append({"product": row[0], "sku": row[1],
                    "account": row[2], "class": row[3], "category": row[4],
                    "subcategory": row[5]})
                newProducts.append(row[0])

        return newData, newProducts

    def siftForecast(self, forecast):
        """
        """

        final = []
        today = dt.date(1, 1, 1).today()

        for i in range(1, 13):
            if i > today.month:
                year = today.year
            else:
                year = today.year + 1
            try:
                final.append(round(forecast[dt.datetime(year, i, 1)]))
            except KeyError:
                final.append("")

        return final

    """
    Event Handler Functions
    """
    def updateList(self, event):
        """
        To Do:
          1) Get the scroll bar to not change location when updating.
        """

        # Get the search criterion.
        if self.productRB.GetValue():
            self.sieve["product"] = self.inputs[0].GetValue()
            self.sieve["sku"] = ''
        else:
            self.sieve["product"] = ''
            self.sieve["sku"] = self.inputs[0].GetValue()
        self.sieve["account"] = self.inputs[1].GetStringSelection()
        self.sieve["class"] = self.inputs[2].GetStringSelection()
        self.sieve["category"] = self.inputs[3].GetStringSelection()
        #self.sieve["subcategory"] = self.inputs[4].GetStringSelection()

        # Get all of the products from the database.
        data = isql.getData(self.sieve, self.connection)

        # Set the title of the frame.
        self.SetTitle("Open/Manage: " + str(len(data)) + " Products")

        # Reset the color of the edit and delete buttons.
        self.editButton.SetBackgroundColour(wx.NullColour)
        self.deleteButton.SetBackgroundColour(wx.NullColour)

        # Remove all items from the list control and reset the index.
        self.productList.DeleteAllItems()
        index = 0

        # Add the items to the list control.
        for product in data:
            self.productList.InsertStringItem(index, product[0])
            self.productList.SetStringItem(index, 1, product[2])
            self.productList.SetStringItem(index, 2, product[3])
            self.productList.SetStringItem(index, 3, product[4])
            #self.productList.SetStringItem(index, 4, product[5])
            index += 1

    def onSelected(self, event):
        """
        """

        # If multiple products are selected, set the edit and delete buttons
        # to be yellow.
        if self.productList.GetSelectedItemCount() > 1:
            self.editButton.SetBackgroundColour("Yellow")
            self.deleteButton.SetBackgroundColour("Yellow")
        # If only one product is selected, set the edit and delete buttons
        # to be the default color.
        else:
            self.editButton.SetBackgroundColour(wx.NullColour)
            self.deleteButton.SetBackgroundColour(wx.NullColour)

    def selectAll(self, event):
        """
        """

        # Iterate through the items in the list selecting each.
        for i in range(0, self.productList.GetItemCount()):
            self.productList.Select(i)

    def onMouseOverAdd(self, event):
        """
        """

        # Start the timer.
        self.timer.Start(1500)

        # Continue processing events.
        event.Skip()

    def onMouseOffAdd(self, event):
        """
        """

        # Stop the timer.
        self.timer.Stop()

        # Reset the color of the add button.
        self.addButton.SetBackgroundColour(wx.NullColour)

        # Continue processing events.
        event.Skip()

    def onTimer(self, event):
        """
        """

        # Change the color of the add button.
        self.addButton.SetBackgroundColour("Yellow")

    def onAdd(self, event):
        """
        """

        # Stop the timer.
        self.timer.Stop()

        # If the add button is yellow, pass to the multi function.
        if self.addButton.GetBackgroundColour() == "Yellow":
            # Reset the color of the add button.
            self.addButton.SetBackgroundColour(wx.NullColour)

            # Call the multi add function.
            self.onAddMulti(event)

            return

        # Create the custom text entry dialog box.
        addDialog = InputDialog(self, title="Add Product")

        # If OK is not pressed, return false.
        if addDialog.ShowModal() != wx.ID_OK:
            return

        # Get the text from the dialog box.
        addProductData = addDialog.getTextEntry(missing=False)

        # Do nothing if the length of the inputted data is zero.
        if len(addProductData) == 0:
            return

        # If nothing is input for product send an error and return false.
        if "product" not in addProductData.keys():
            errorDialog = wx.MessageDialog(self,
                "Product cannot be empty.", "Error", wx.OK|wx.ICON_ERROR)
            errorDialog.ShowModal()

            return

        # Destroy the dialog box.
        addDialog.Destroy()

        # Add the inputted product data to the database.
        isql.addProduct(addProductData, self.connection)

        # Update the list.
        self.updateList(None)

    def onAddMulti(self, event, overwrite=True):
        """
        """

        # Create the open file dialog box.
        openFileDialog = wx.FileDialog(self, "Select a Mass Add File", "", "",
            "CSV files (*.csv)|*.csv|TXT files (*txt)|*.txt|XLSX and XLS " +
            "files (*.xlsx, *.xls)|*.xslx*.xls",
            style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)

        # If open is not pressed, return false.
        if openFileDialog.ShowModal() != wx.ID_OK:
            return

        # Read the data from the file.
        (data, newProducts) = self.readAddData(openFileDialog.GetPath())

        # Destroy the dialog box
        openFileDialog.Destroy()

        # Add the products to the database.
        isql.addProducts(newProducts, data, overwrite, self.connection)

        # Update the list.
        self.updateList(None)

    def onEdit(self, event):
        """
        """

        # Check if multiple items are selected.
        count = self.productList.GetSelectedItemCount()

        # If more than one item is selected, pass to the multi function.
        if count > 1:
            # Call the multi edit function.
            self.onEditMulti(event, count)

            return
        # If nothing is selected, send an error.
        elif count == 0:
            errorDialog = wx.MessageDialog(self, "No item was selected.",
                "Error", wx.OK|wx.ICON_ERROR)
            errorDialog.ShowModal()

            return

        # Get the selected item index from the list.
        productIndex = self.productList.GetFirstSelected()

        # Get the string value of the old product.
        product = self.productList.GetItemText(productIndex)

        # Extract the attributes from the database.
        oldProductData = isql.getProduct(product, self.connection)

        # Create the custom text entry dialog box.
        editDialog = InputDialog(self, title="Edit Product")

        # Set the initial text to be the old product.
        editDialog.setTextEntry(oldProductData)

        # If OK is not pressed, return false.
        if editDialog.ShowModal() != wx.ID_OK:
            return

        # Get the text from the dialog box.
        newProductData = editDialog.getTextEntry(missing=True)

        # If nothing is input for product send an error and return false.
        if newProductData["product"] == '':
            errorDialog = wx.MessageDialog(self,
                "Product cannot be empty.", "Error", wx.OK|wx.ICON_ERROR)
            errorDialog.ShowModal()

            return

        # Destroy the dialog box.
        editDialog.Destroy()

        # Iterate over the inputs and delete unchanged values.
        for index in range(0, len(newProductData)):
            if newProductData[LABELS[index]] == oldProductData[index]:
                del newProductData[LABELS[index]]

        # Do nothing if the length of the inputted data is zero.
        if len(newProductData) == 0:
            return

        # Add the inputted product data to the database.
        isql.setProduct(oldProductData[0], newProductData, self.connection)

        # Update the list.
        self.updateList(None)

    def onEditMulti(self, event, count=None):
        """
        """

        # Create the custom text entry dialog box.
        editDialog = InputDialog(self, title="Edit Products")

        # Change the edit dialog for multiple edits.
        editDialog.setMultiEdit()

        # If OK is not pressed, return false.
        if editDialog.ShowModal() != wx.ID_OK:
            return

        # Get the text from the dialog box.
        newProductData = editDialog.getTextEntry()

        # Destroy the dialog box.
        editDialog.Destroy()

        # Reset the color of the edit and delete buttons.
        self.editButton.SetBackgroundColour(wx.NullColour)
        self.deleteButton.SetBackgroundColour(wx.NullColour)

        # If the number of selected items was not inputted, find it.
        if count is None:
            count = self.productList.GetSelectedItemCount()

        # Get the list of products that have been selected.
        products = []
        productIndex = self.productList.GetFirstSelected()
        for index in range(0, count):
            products.append(self.productList.GetItemText(productIndex))
            productIndex = self.productList.GetNextSelected(productIndex)

        # Update the values input in the database.
        isql.setProducts(products, newProductData, self.connection)

        # Update the list.
        self.updateList(None)

    def onDelete(self, event):
        """
        """

        # Get the first selected product index from the list.
        productIndex = self.productList.GetFirstSelected()

        # Send an error if nothing is selected.
        if productIndex == -1:
            errorDialog = wx.MessageDialog(self, "No item was selected.",
                "Error", wx.OK|wx.ICON_ERROR)
            errorDialog.ShowModal()
            return

        # Get the number of selected products.
        count = self.productList.GetSelectedItemCount()

        # Create the confimation dialog box.
        confirmDialog = wx.MessageDialog(self,
            "You are about to delete " + str(count) +
            " product(s). Continue?",
            "Delete Confirmation", wx.YES_NO)

        # If no is selected, return false.
        if confirmDialog.ShowModal() != wx.ID_YES:
            return

        # Destroy the dialog box.
        confirmDialog.Destroy()

        # Reset the color of the edit and delete buttons.
        self.editButton.SetBackgroundColour(wx.NullColour)
        self.deleteButton.SetBackgroundColour(wx.NullColour)

        # Create the progress dialog box.
        progressDialog = wx.ProgressDialog("Deleting Products",
            "Processing products, please wait.", maximum=100, parent=self,
            style=wx.PD_CAN_ABORT|wx.PD_APP_MODAL|wx.PD_ELAPSED_TIME
            |wx.PD_REMAINING_TIME|wx.PD_SMOOTH)

        # Initialize aspects of the progress dialog box.
        keepGoing = True
        progress = 0

        # Remove all selected items.
        delta = 99 / count
        index = 1
        while keepGoing and index <= count:
            # Get the product text.
            product = self.productList.GetItemText(productIndex)

            # Remove the selected item.
            isql.removeProduct(product, self.connection)

            # Get the next selected item index.
            productIndex = self.productList.GetNextSelected(productIndex)

            # Update the dialog box.
            progress += delta
            (keepGoing, skip) = progressDialog.Update(progress,
                "Finished deleting " + product + ".")

            # Increment the index.
            index += 1

        # Final update to the dialog box.
        (keepGoing, skip) = progressDialog.Update(100, "Delete complete.")

        # Destroy the dialog box.
        progressDialog.Destroy()

        # Update the list.
        self.updateList(None)

    def onReport(self, event):
        """
        """

        # Get the list of selected items.
        products = self.getSelection()

        # Get the preferences for reporting.
        pref = pickle.load(open(os.path.join(idata.DATA, "Forsteri",
            "pref.p"), "rb"))

        # Get the method type.
        method = pref["report_type"].lower()
        if method == "auto":
            method = None

        # Open a connection to the data database.
        dataConnection = sqlite3.connect(idata.MASTER)

        # Iterate over the products selected.
        data = {}
        for product in products:
            data[product] = idata.getForecast(product, method,
                connection=dataConnection)

        # Create the file dialog box.
        fileDialog = wx.FileDialog(self, "Save file as", "", "",
            "CSV files (*.csv)|*.csv", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)

        # Show the file dialog box.
        if fileDialog.ShowModal() == wx.ID_CANCEL:
            return

        # Get the location of the save.
        loc = fileDialog.GetPath()

        # Write the data to a file.
        with open(loc, 'w') as csvfile:
            writer = csv.writer(csvfile, delimiter=',', quotechar='|')
            writer.writerow(["Product", "January", "February", "March",
                "April", "May", "June", "July", "August", "September",
                "October", "November", "December"])
            for product in products:
                temp = [product]
                temp.extend(self.siftForecast(data[product]))
                writer.writerow(temp)

        # Close the database connections.
        self.connection.close()
        dataConnection.close()

        # End the modal and return the print id.
        self.EndModal(wx.ID_PRINT)

    def onOpen(self, event):
        """
        """

        # Commit the changes to the database.
        self.connection.commit()

        # Close the database.
        self.connection.close()

        # End the modal and return the ok id.
        self.EndModal(wx.ID_OPEN)

    def onApply(self, event):
        """
        """

        # Commit the changes to the database.
        self.connection.commit()

    def onCancel(self, event):
        """
        """

        # Close the database.
        self.connection.close()

        # End the modal and return the cancel id.
        self.EndModal(wx.ID_CANCEL)

"""
Input Dialog Box Class
"""
class InputDialog(wx.Dialog):
    """
    A dialog containing the input boxes for an item. This dialog is used for
    adding and editing a single item and can be used to edit multiple items.

    Extends:
      wx.Dialog
    """

    def __init__(self, *args, **kwargs):
        """
        Initialize the input dialog.

        Args:
          *args (tuple of object): Any arguments to be passed directly to the
            super's constructor.
          **kwargs (dictionary of name: object): Any keyword arguments to be
            passed to the super's constructor.

        Returns:
          InputDialog
        """

        # Initialize by the parent's constructor.
        super(InputDialog, self).__init__(*args, **kwargs)

        # Create the master panel.
        masterPanel = wx.Panel(self)

        # Create the master sizer.
        masterSizer = wx.BoxSizer(wx.VERTICAL)

        # Create the content sizer.
        contentSizer = wx.FlexGridSizer(6, 2, 5, 10)

        # Get the choices for the combo boxes.
        choices = self.pullChoices()

        # Create the text control and combo box inputs.
        self.inputObjects = []
        for i in range(0, 5):
            if i < 2:
                self.inputObjects.append(wx.TextCtrl(masterPanel,
                    size=(150, -1)))
            else:
                self.inputObjects.append(wx.ComboBox(masterPanel,
                    size=(150, -1), choices=choices[i - 2],
                    style=wx.CB_READONLY|wx.CB_SORT))

            # Add the labels and text control inputs to the content sizer.
            contentSizer.AddMany([wx.StaticText(masterPanel,
                label=LABELS[i].title()), self.inputObjects[i]])

        # Create the button sizer.
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)

        # Create the buttons.
        okButton = wx.Button(masterPanel, id=wx.ID_OK)
        cancelButton = wx.Button(masterPanel, id=wx.ID_CANCEL)

        # Set the OK button to be the dafault button.
        okButton.SetDefault()

        # Add the buttons to the button sizer.
        buttonSizer.AddMany([okButton, (5, 0), cancelButton, (5, 0)])

        # Bind the button presses to functions.
        okButton.Bind(wx.EVT_BUTTON, self.onOK)
        cancelButton.Bind(wx.EVT_BUTTON, self.onCancel)

        # Add everything to the master sizer.
        masterSizer.Add((0, 5))
        masterSizer.Add(contentSizer, flag=wx.ALL|wx.ALIGN_CENTER, border=5)
        masterSizer.AddSpacer(9)
        masterSizer.Add(wx.StaticLine(masterPanel, size=(280, 2)),
            flag=wx.ALIGN_CENTER)
        masterSizer.AddSpacer(9)
        masterSizer.Add(buttonSizer, flag=wx.ALIGN_RIGHT)
        masterSizer.Add((0, 5))

        # Set the master sizer.
        masterPanel.SetSizer(masterSizer)

        # Set the size of the window.
        self.SetSize((300, 233))

    """
    Manipulate Functions
    """
    def getTextEntry(self, missing=True):
        """
        Get the inputted values from the dialog box.

        Args:
          missing (bool, optional): True if the missing inputs are to be
            preserved as None, otherwise false.

        Retruns:
          dict of {str: str}: The inputted values in the form attribute: value.
        """

        # Initialize the returned inputs dictionary.
        inputs = dict()

        # Iterate over the input objects.
        index = 0
        for inputObject in self.inputObjects:
            # Get the input value.
            entered = inputObject.GetValue()

            # If the missing flag is false and the entered value is an empty
            # string, increment the index and move to the next loop iteration.
            if not missing and entered == '':
                # Increment the index and skip to the next loop iteration.
                index += 1
                continue

            # Set the correct label to the inputted value.
            inputs[LABELS[index]] = entered

            # Increment the index.
            index += 1

        return inputs

    def setTextEntry(self, text):
        """
        Set the values in input dialog box.

        Args:
          text (list of str): A list containing the values to be input into the
            entry fields.

        Returns:
          bool: True if successful, false otherwise.
        """

        # Iterate over the text control inputs and set their value.
        index = 0
        for inputObject in self.inputObjects:
            inputObject.SetValue(text[index])
            index += 1

        # Set the first text control input to have its text selected.
        self.inputObjects[0].SelectAll()

        return True

    def setMultiEdit(self):
        """
        Set the dialog box to be for multiple edits. This disables anything
        that is unique to a product.

        Args:
          None

        Returns:
          bool: True if successful, false otherwise.
        """

        # Set the first two fields as disabled.
        self.inputObjects[0].Disable()
        self.inputObjects[1].Disable()

        return True

    """
    Helper Functions
    """
    def pullChoices(self):
        """
        Pull the possible choices for the combo boxes from the database.

        Args:
          None

        Returns:
          list of list of str: The lists of choices for each combo box in the
            dialog box.
        """

        # Get the list of tiers.
        tiers = isql.getTiers()

        # Get each list associated with each tier.
        connect = []
        for tier in tiers:
            tierList = isql.getForTier(tier)

            # Add an empty string for selection.
            tierList.append("")

            # Append the entire list to the returned list.
            connect.append(tierList)

        # Switch the indices of category and class.
        connect[1], connect[2] = connect[2], connect[1]

        return connect

    """
    Event Handler Functions
    """
    def onOK(self, event):
        """
        What to do when the OK button is pressed.

        Args:
          event(wx._core.CommandEvent): The triggered event when the OK button
            is pressed.

        Returns:
          None
        """

        self.EndModal(wx.ID_OK)

    def onCancel(self, event):
        """
        What to do when the cancel button is pressed.

        Args:
          event(wx._core.CommandEvent): The triggered event when the cancel
            button is pressed.

        Returns:
          None
        """

        self.EndModal(wx.ID_CANCEL)

if __name__ == '__main__':
    app = wx.App()
    dialog = OpenDialog(None,
        style=wx.DEFAULT_FRAME_STYLE^wx.RESIZE_BORDER)
    dialog.ShowModal()


import pandas as pd
import numpy as np
from math import radians, cos, sin, asin, sqrt, floor
import time
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import GradientBoostingClassifier
import matplotlib.pyplot as plt

def get_distance(lng1, lat1, lng2, lat2):
    lng1, lat1, lng2, lat2 = map(radians, [lng1, lat1, lng2, lat2])
    dlon = lng2 - lng1
    dlat = lat2 - lat1
    a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
    dis = 2 * asin(sqrt(a)) * 6371 * 1000
    return dis

def get_gongcan_map(gongcanDf):
    tmpMap = {}
    for i in range(len(gongcanDf)):
        key = gongcanDf.iloc[i]['RNCID'] + '_' + gongcanDf.iloc[i]['CellID']
        value = [gongcanDf.iloc[i]['Longitude'], gongcanDf.iloc[i]['Latitude']]
        tmpMap[key] = value
    return tmpMap

def process_data(dataDf):
    rnc_ids = dataDf.groupby(['RNCID_1', 'CellID_1'])
    rnc_id_nos = list(rnc_ids.indices.keys())
    datas = []
    data_labels = []
    # Statistic the each point
    for index in range(len(rnc_ids)):
        key = rnc_id_nos[index][0] + '_' + rnc_id_nos[index][1]
        base_longitude = gongcanMap[key][0]
        base_latitude = gongcanMap[key][1]

        rncDf = rnc_ids.get_group(rnc_id_nos[index])
        labels = []
        data = np.zeros((len(rncDf), 25))
        for j in range(len(rncDf)):
            lon = rncDf.iloc[j]['Longitude']
            lat = rncDf.iloc[j]['Latitude']
            label = [int((lon - base_longitude) * pow(10, 20)), int((lat - base_latitude) * pow(10, 20)), lon, lat]
            labels.append(label)
            num_connected = rncDf.iloc[j]['Num_connected']
            tmp = [rncDf.iloc[j]['IMSI'], rncDf.iloc[j]['MRTime']] + [base_longitude, base_latitude]
            for k in range(num_connected):
                location = gongcanMap.get(
                    rncDf.iloc[j]['RNCID_' + str(k + 1)] + '_' + rncDf.iloc[j]['CellID_' + str(k + 1)])
                if location is not None:
                    tmp += [location[0], location[1], rncDf.iloc[j]['RSSI_' + str(k + 1)]]
            for item in range(len(tmp)):
                data[j][item] = tmp[item]
        datas.append(data)
        data_labels.append(np.array(labels))
    return datas, data_labels

def make_picture(errors, labels, color):
    plt.figure(figsize=(15, 8))
    for index in range(len(errors)):
        x = range(len(errors[index]))
        plt.plot(x, errors[index], label='group_' + str(labels[index]), linewidth=0.5, color=color, marker='o',
                 markerfacecolor='blue', markersize=1)
    plt.xlabel('number')
    plt.ylabel('average error')
    plt.title('Average error probability distribution diagram')
    plt.legend()
    plt.show()

def make_time_picture(times):
    plt.figure(figsize=(15, 8))
    plt.bar(x=range(5, 15), height=times, width=0.7, color="lightblue")
    plt.xlabel('number')
    plt.ylabel('cost(s)')
    plt.title('Time performance bar diagram')
    plt.legend()
    plt.show()

def make_total_picture(errors):
    plt.figure(figsize=(15, 8))
    x = range(len(errors[0]))
    for index in range(len(errors)):
        plt.plot(x, errors[index], label='K=' + str(index + 5), linewidth=0.5, color='r', marker='o',
                 markerfacecolor='blue', markersize=1)
    plt.xlabel('number')
    plt.ylabel('average error')
    plt.title('Average error probability distribution diagram')
    plt.legend()
    plt.show()

def train(classifier, data, label, top_data=None, top_data_label=None):
    distances = []
    for number in range(10):
        # split data
        X_train, X_test, y_train, y_test = train_test_split(data, label, test_size=0.2, random_state=number)
        if top_data is not None and top_data_label is not None:
            X_train = np.vstack((X_train, top_data))
            y_train = np.vstack((y_train, top_data_label))
        classifier.fit(X_train[:, 4:], y_train[:, 0:2])
        y_pred = classifier.predict(X_test[:, 4:])
        locations = []
        for index in range(len(y_pred)):
            locations.append([X_test[index][2] + y_pred[index][0] / pow(10, 20),
                              X_test[index][3] + y_pred[index][1] / pow(10, 20)])
        tmp = []
        for index in range(len(y_pred)):
            tmp.append(get_distance(y_test[index][2], y_test[index][3],
                                    locations[index][0],
                                    locations[index][1]))
        distances.append(sorted(tmp))
    errors = []
    matrix = np.array(distances)
    for index in range(matrix.shape[1]):
        errors.append(np.mean(matrix[:, index]))
    return errors

def merge_data(group_medians, datas, data_labels, k):
    sorted_group_median = sorted(group_medians.items(), key=lambda d: d[1])
    merged_datas = []
    merged_data_labels = []
    top_k_data = datas[sorted_group_median[0][0]]
    top_k_label = data_labels[sorted_group_median[0][0]]
    for index in range(k):
        merged_datas.append(datas[sorted_group_median[index][0]])
        merged_data_labels.append(data_labels[sorted_group_median[index][0]])
        # merge
        if index > 0:
            top_k_data = np.vstack((datas[sorted_group_median[index][0]], top_k_data))
            top_k_label = np.vstack((data_labels[sorted_group_median[index][0]], top_k_label))
    for index in range(k, len(datas)):
        # merge_data = np.vstack((datas[sorted_group_median[index][0]], top_k_data))
        # merge_data_label = np.vstack((data_labels[sorted_group_median[index][0]], top_k_label))
        merged_datas.append(datas[sorted_group_median[index][0]])
        merged_data_labels.append(data_labels[sorted_group_median[index][0]])
    return merged_datas, merged_data_labels, top_k_data, top_k_label

if __name__ == "__main__":
    # read data
    dataDf = pd.read_csv('../data_2g.csv', header=0, dtype={'RNCID_1': np.object, 'CellID_1': np.object,
                                                         'RNCID_2': np.object, 'CellID_2': np.object,
                                                         'RNCID_3': np.object, 'CellID_3': np.object,
                                                         'RNCID_4': np.object, 'CellID_4': np.object,
                                                         'RNCID_5': np.object, 'CellID_5': np.object,
                                                         'RNCID_6': np.object, 'CellID_6': np.object,
                                                         'RNCID_7': np.object, 'CellID_7': np.object})
    gongcanDf = pd.read_csv('../2g_gongcan.csv', header=0, dtype={'RNCID': np.object, 'CellID': np.object})
    # get gongcan data
    gongcanMap = get_gongcan_map(gongcanDf)

    size = len(dataDf)
    # Get the matrix
    minLatitude = dataDf['Latitude'].min()
    maxLatitude = dataDf['Latitude'].max()
    minLongitude = dataDf['Longitude'].min()
    maxLongitude = dataDf['Longitude'].max()

    datas, data_labels = process_data(dataDf)
    average_errors = []
    group_medians = {}
    for index in range(len(datas)):
        rfc = RandomForestClassifier()
        average_error = train(rfc, datas[index], data_labels[index])
        median = np.median(average_error)
        group_medians[index] = median
        average_errors.append(average_error)

    # top k data
    total_errors = []
    exec_times = []
    for k in range(5, 15):
        merged_datas, merged_data_labels, top_k_data, top_k_label = merge_data(group_medians, datas, data_labels, k)
        total_error = []
        average_errors = []
        start = time.time()
        for index in range(len(merged_datas)):
            rfc = RandomForestClassifier()
            if index >= k:
                average_error = train(rfc, merged_datas[index], merged_data_labels[index],
                                      top_data=top_k_data, top_data_label=top_k_label)
            else:
                average_error = train(rfc, merged_datas[index], merged_data_labels[index])
            average_errors.append(average_error)
            total_error += average_error
        color = 'r'
        end = time.time()
        exec_time = round(end - start, 2)
        exec_times.append(exec_time)
        # make_picture(average_errors, range(len(merged_datas)), color)
        print('K:', k, 'Total error:', sum(total_error))
        total_errors.append(sorted(total_error))
    # make_total_picture(total_errors)
    make_time_picture(exec_times)


from rest_framework import serializers
from rest_framework.validators import UniqueValidator

from .models import User, Team, EventStatus

class UserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(
        validators=[UniqueValidator(queryset=User.objects.all())]
    )

    class Meta:
        model = User
        fields = [
            "id",
            "username",
            "password",
            "first_name",
            "last_name",
            "email",
            "phone",
            "is_staff",
            "team",
        ]

    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

class TeamSerializer(serializers.ModelSerializer):
    class Meta:
        model = Team
        fields = ["id", "name"]

class EventStatusSerializer(serializers.ModelSerializer):
    class Meta:
        model = EventStatus
        fields = ["id", "name"]


import os
import json
import requests

description_directory = 'supplier-data/descriptions/'
image_directory = 'supplier-data/images/'

list_of_descriptions = []
image_names = []
list_of_descriptions_json = []

# Processes the text files
# Gets the individual contents of a file and adds them to a list line by line
# Adds each file that has been converted into a list to another list
def process_txt_files():
    for file in os.listdir(description_directory):
        full_path = description_directory + file
        with open(full_path, 'r') as description:
            single_description_contents = []
            for line in description.readlines():
                single_description_contents.append(line.strip())
        list_of_descriptions.append(single_description_contents)

# Gets the names of all the images in the 'supplier-data/images/' directory and adds them to a list
def get_image_names():
    for image in os.listdir(image_directory):
        image_names.append(image)

# Creates dictionaries based on each description
# Adds the image name generated from the previous function as part of the dictionary's fields
# Converts each dictionary to JSON and adds it to a list
def generate_json():
    i = 0
    for description in list_of_descriptions:
        description_dict =  {}
        description_dict['name'] = description[0]
        description_dict['weight'] = int(description[1].strip(' lbs'))
        description_dict['description'] = description[2]
        description_dict['image_name'] = image_names[i]
        list_of_descriptions_json.append(json.dumps(description_dict))
        i += 1

# Iterates over the list containing the JSON structures and posts the content to a web server
def post_to_web_service():
    url = 'http://[linux-instance-external-IP]/fruits'
    for description in list_of_descriptions_json:
        requests.post(url, data=description)

process_txt_files()
get_image_names()
generate_json()
post_to_web_service()


from deeplake.core.dataset import Dataset

from deeplake.constants import MB
from deeplake.core.storage.gcs import GCSProvider
from deeplake.enterprise.util import raise_indra_installation_error  # type: ignore
from deeplake.core.storage import S3Provider
from deeplake.core.storage.azure import AzureProvider
from deeplake.util.remove_cache import get_base_storage
from deeplake.util.exceptions import EmptyTokenException

from deeplake.util.dataset import try_flushing  # type: ignore
import importlib
import jwt

# Load lazy to avoid cycylic import.
INDRA_API = None

def import_indra_api_silent():
    global INDRA_API
    if INDRA_API:
        return INDRA_API
    if not importlib.util.find_spec("indra"):
        return None
    try:
        from indra import api  # type: ignore

        INDRA_API = api
        return api
    except Exception as e:
        return e

def import_indra_api():
    api = import_indra_api_silent()

    if api is None:
        raise_indra_installation_error()  # type: ignore
    elif isinstance(api, Exception):
        raise_indra_installation_error(api)
    else:
        return api

INDRA_INSTALLED = bool(importlib.util.find_spec("indra"))

def _get_indra_ds_from_azure_provider(
    path: str,
    token: str,
    provider: AzureProvider,
):
    if provider is None:
        return None

    api = import_indra_api()
    account_name = provider.account_name
    account_key = provider.account_key
    sas_token = provider.get_sas_token()
    expiration = str(provider.expiration) if provider.expiration else None

    return api.dataset(
        path,
        origin_path=provider.root,
        token=token,
        account_name=account_name,
        account_key=account_key,
        sas_token=sas_token,
        expiration=expiration,
    )

def _get_indra_ds_from_gcp_provider(
    path: str,
    token: str,
    provider: GCSProvider,
):
    if provider is None:
        return None

    api = import_indra_api()
    creds = provider.get_creds()
    anon = creds.get("anon", "")
    expiration = creds.get("expiration", "")
    access_token = creds.get("access_token", "")
    json_credentials = creds.get("json_credentials", "")
    endpoint_override = creds.get("endpoint_override", "")
    scheme = creds.get("scheme", "")
    retry_limit_seconds = creds.get("retry_limit_seconds", "")

    return api.dataset(
        path,
        origin_path=provider.root,
        token=token,
        anon=anon,
        expiration=expiration,
        access_token=access_token,
        json_credentials=json_credentials,
        endpoint_override=endpoint_override,
        scheme=scheme,
        retry_limit_seconds=retry_limit_seconds,
    )

def _get_indra_ds_from_s3_provider(
    path: str,
    token: str,
    provider: S3Provider,
):
    if provider is None:
        return None

    api = import_indra_api()

    creds_used = provider.creds_used
    if creds_used == "PLATFORM":
        provider._check_update_creds()
        return api.dataset(
            path,
            origin_path=provider.root,
            token=token,
            aws_access_key_id=provider.aws_access_key_id,
            aws_secret_access_key=provider.aws_secret_access_key,
            aws_session_token=provider.aws_session_token,
            region_name=provider.aws_region,
            endpoint_url=provider.endpoint_url,
            expiration=str(provider.expiration),
        )
    elif creds_used == "ENV":
        return api.dataset(
            path,
            origin_path=provider.root,
            token=token,
            profile_name=provider.profile_name,
        )
    elif creds_used == "DICT":
        return api.dataset(
            path,
            origin_path=provider.root,
            token=token,
            aws_access_key_id=provider.aws_access_key_id,
            aws_secret_access_key=provider.aws_secret_access_key,
            aws_session_token=provider.aws_session_token,
            region_name=provider.aws_region,
            endpoint_url=provider.endpoint_url,
        )

def dataset_to_libdeeplake(hub2_dataset: Dataset):
    """Convert a hub 2.x dataset object to a libdeeplake dataset object."""
    try_flushing(hub2_dataset)
    api = import_indra_api()
    path: str = hub2_dataset.path

    token = (
        hub2_dataset.client.get_token()
        if (hub2_dataset._token is None or hub2_dataset._token == "")
        and hub2_dataset.client
        else hub2_dataset._token
    )
    if token is None or token == "":
        raise EmptyTokenException
    if hub2_dataset.libdeeplake_dataset is None:
        libdeeplake_dataset = None
        if path.startswith("gdrive://"):
            raise ValueError("Gdrive datasets are not supported for libdeeplake")
        elif path.startswith("mem://"):
            raise ValueError("In memory datasets are not supported for libdeeplake")
        elif path.startswith("hub://"):
            provider = hub2_dataset.storage.next_storage
            if isinstance(provider, S3Provider):
                libdeeplake_dataset = _get_indra_ds_from_s3_provider(
                    path=path, token=token, provider=provider
                )

            elif isinstance(provider, GCSProvider):
                libdeeplake_dataset = _get_indra_ds_from_gcp_provider(
                    path=path, token=token, provider=provider
                )

            elif isinstance(provider, AzureProvider):
                libdeeplake_dataset = _get_indra_ds_from_azure_provider(
                    path=path, token=token, provider=provider
                )
            else:
                raise ValueError("Unknown storage provider for hub:// dataset")

        elif path.startswith("s3://"):
            libdeeplake_dataset = _get_indra_ds_from_s3_provider(
                path=path, token=token, provider=hub2_dataset.storage.next_storage
            )

        elif path.startswith(("gcs://", "gs://", "gcp://")):
            provider = get_base_storage(hub2_dataset.storage)

            libdeeplake_dataset = _get_indra_ds_from_gcp_provider(
                path=path, token=token, provider=provider
            )

        elif path.startswith(("az://", "azure://")):
            az_provider = get_base_storage(hub2_dataset.storage)
            libdeeplake_dataset = _get_indra_ds_from_azure_provider(
                path=path, token=token, provider=az_provider
            )

        else:
            org_id = hub2_dataset.org_id
            org_id = (
                org_id or jwt.decode(token, options={"verify_signature": False})["id"]
            )
            libdeeplake_dataset = api.dataset(path, token=token, org_id=org_id)

        hub2_dataset.libdeeplake_dataset = libdeeplake_dataset
    else:
        libdeeplake_dataset = hub2_dataset.libdeeplake_dataset

    assert libdeeplake_dataset is not None
    libdeeplake_dataset._max_cache_size = max(
        hub2_dataset.storage.cache_size, libdeeplake_dataset._max_cache_size
    )
    commit_id = hub2_dataset.pending_commit_id
    libdeeplake_dataset.checkout(commit_id)
    slice_ = hub2_dataset.index.values[0].value
    if slice_ != slice(None):
        if isinstance(slice_, tuple):
            slice_ = list(slice_)
        libdeeplake_dataset = libdeeplake_dataset[slice_]
    return libdeeplake_dataset


def aggregate_all(data):
    courses = []
    lessons = []
    posts = []
    users = []
    for obj in data:
        if obj['_index'] == 'courses':
            courses.append(obj['_source'])
        if obj['_index'] == 'lessons':
            lessons.append(obj['_source'])
        if obj['_index'] == 'posts':
            posts.append(obj['_source'])
        if obj['_index'] == 'users':
            users.append(obj['_source'])
    response = {
        "courses": courses,
        "lessons": lessons,
        "posts": posts,
        "users": users
                }
    return response

def aggregate(es_data,page,size, count):
    data={}
    for obj in es_data:
        index = obj['_index']
        if index not in data:
            data[index]=[]
        data[index].append(obj['_source'])
    response = {}
    response['data']=data
    response['meta']={
        "current_page": page,
        "per_page": size,
        "total_items": count,
    }
    return response