#!/usr/bin/env python3

import os
import random
import signal
import socket
import struct
import sys
import threading
import time
from datetime import datetime
from datetime import timedelta

Z = 2
W = 3
X = 3
T = 1
M = 3
# Packet_type

REG_REQ = 0xa0
REG_ACK = 0xa1
REG_NACK = 0xa2
REG_REJ = 0xa3
REG_INFO = 0xa4
INFO_ACK = 0xa5
INFO_NACK = 0xa6
INFO_REJ = 0xa7
ALIVE_NACK = 0xb1
ALIVE_REJ = 0xb2
SEND_DATA = 0xc0
DATA_ACK = 0xc1
DATA_NACK = 0xc2
DATA_REJ = 0xc3
SET_DATA = 0xc4
GET_DATA = 0xc5

# Client-server state

DISCONNECTED = 0xf0
NOT_REGISTERED = 0xf1
WAIT_ACK_REG = 0xf2
WAIT_INFO = 0xf3
WAIT_ACK_INFO = 0xf4
REGISTERED = 0xf5
SEND_ALIVE = 0xf6
ALIVE = 0xb0

class Server:
    def __init__(self):
        self.id = None
        self.port_UDP = None
        self.port_TCP = None

class Clients:
    def __init__(self):
        self.id = None
        self.ip = None
        self.id_comm = None
        self.all_elements = None
        self.element_and_value = [[]]
        self.status = None
        self.udp_port = None
        self.tcp_port = None
        self.udp_socket = None
        self.consecutive_alive = 0
        self.receive_alive = False
        self.first_alive_recv = False

class Socket:
    def __init__(self):
        self.udp_socket = None
        self.tcp_socket = None
        self.connection_socket = None

# GLobal Functions
allowed_client = []
debug_mode = False
sock = Socket()
server_inf = Server()

# ----------------------------SOCKETS------------------------------------------#
def udp_socket():
    # Funcio que obra socket amb el port UDP de les dades del servidor
    global server_inf
    global sock
    sock = Socket()
    sock.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.udp_socket.bind(("", server_inf.port_UDP))

def client_udp_socket(client):
    # Funcio que obra socket amb el port UDP aleatori per intercambiar el REG_INFO amb el client

    global server_inf
    client.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    client.udp_socket.bind(("", 0))
    ip, port = client.udp_socket.getsockname()

    if (debug_mode == True):
        print_message("Port UDP : " + str(port) + " obert al client: " + client.id)

    return port

def tcp_socket():
    # Funcio que obra socket amb el port TCP del servidor
    global sock
    global server_inf
    sock.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.tcp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.tcp_socket.bind(("", server_inf.port_TCP))
    sock.tcp_socket.listen(5)

def client_tcp_socket(client):
    # Funcio que obra socket amb el port TCP rebut del client
    client.tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_address = (client.ip, int(client.tcp_port))
    client.tcp_socket.connect(client_address)
    print_message("Iniciant protocol TCP al port: " + str(client.tcp_port) + " per al client: " + client.id)

# -----------------------------REGISTER && ALIVE FUNCTIONS------------------------------------------#
def udp_loop():
    """ Funcio que continuament esta rebent els paquets UDP dels diferents clients
    connectats.Per cada paquet es crea un fil que tractara el paquet segons el seu tipus.
    Per aqui s'haurien de rebre sol REG_REQ i ALIVES """
    global sock
    while (1):
        try:
            sock.udp_socket.settimeout(2)
            recieved_pck_udp, client_ip, client_port = receive_udp_packet(84, sock.udp_socket)
            pack_ack = threading.Thread(target=register_loop, args=(recieved_pck_udp, client_ip, client_port))
            pack_ack.start()
        except socket.error as socketerror:
            """Com a altres funcions, he decidit optar per utilitzar el .settimeout()
            que retorna una exepcio en cas de no rebre res en el temps esmentat.En el nostre cas
            la manera de tractar el error es ignorarlo, ya que rebem una excepcio per cada paquet no rebut"""
            error = "ignore"

def register_loop(recieved_pck_udp, client_ip, client_port):
    """ Funcio cridada per UDP_loop(), tracta cada tipus de paquet(REG_REQ i ALIVE),
    cridant les seves respectives funcions de tractament """
    pack_type = recieved_pck_udp[0]
    if pack_type == REG_REQ:
        register_reg(recieved_pck_udp, client_ip, client_port)
    if pack_type == ALIVE:
        alive_phase(recieved_pck_udp)

def register_reg(received_package, client_ip, client_udp_port):
    """Tracta els paquets REG_REQ que rep, en cas de ser ivalids enviem REG_REJ.
    Si es valid i el client esta en DISCONNECTED,
    pasarem de fase per completar el registre del client"""

    global sock
    client_id_transm = received_package[1].decode().split("\x00")[0]
    client_id_comm = received_package[2].decode().split("\x00")[0]
    client_dades = received_package[3].decode(errors="ignore").split("\x00")[0]
    if not client_id_and_id_comm_valid(client_id_transm, client_id_comm) and len(client_dades) > 0:
        print_message("ERROR -> Paquet del client: " + client_id_transm + " no valid, enviant REG_REJ....")
        send_pck = reg_rej_pack_maker("Dades incorrectes")
        sock.udp_socket.sendto(send_pck, (client_ip, client_udp_port))
        return

    valid_client = get_client_by_Id(client_id_transm)
    valid_client.ip = client_ip
    valid_client.id_comm = client_id_comm
    valid_client.udp_port = client_udp_port

    if valid_client.status == DISCONNECTED:
        reg_ack_phase(valid_client)
    else:
        """En cas de barrejar estats i rebre un reg_req en un estat incorrecte,
        tornem el client a DISCONNECTED"""

        print_message("Rebut paquet REG_REQ en estat diferent a Disconnected")
        change_status(valid_client.id, DISCONNECTED)

def reg_ack_phase(valid_client):
    """Tractament complet del REG_REQ"""
    global sock
    # Creo id_comm i nou port per on iniciarem l'intercanvi del REG_INFO
    rand_num = random.randint(1111111111, 9999999999)
    valid_client.id_comm = str(rand_num)

    # Obrim socket per rebre el REG_INFO
    port_aleatori = client_udp_socket(valid_client)

    # Envio REG_ACK amb el port creat anteriorment
    send_pck = reg_ack_pack_maker(rand_num, port_aleatori)
    send_udp_packet(valid_client, send_pck)
    change_status(valid_client.id, WAIT_INFO)

    """Aqui obtenim el REG_INFO amb el socket obert anteriorment,
    i li afegim un temps Z * T per rebrel"""
    try:
        valid_client.udp_socket.settimeout(Z * T)
        reg_info, client_ip, client_port = receive_udp_packet(84, valid_client.udp_socket)
    except socket.error as socketerror:
        print_message("Paquet REG_INFO no rebut")
        valid_client.udp_socket.close()
        change_status(valid_client.id, DISCONNECTED)
        return
    valid_client.udp_socket.close()
    # Tanquem socket i tractem el REG_INFO

    pack_type = reg_info[0]
    client_id_comm = reg_info[2].decode().split("\x00")[0]
    client_dades = reg_info[3].decode(errors="ignore").split("\x00")[0]

    # Tractament del REG_INFO
    if pack_type == REG_INFO and client_ip == valid_client.ip and client_id_comm == valid_client.id_comm \
            and len(client_dades) > 10 and valid_client.status == WAIT_INFO:

        set_reg_client_data(valid_client, client_dades)
        send_info_ack = info_ack_pack_maker(valid_client.id_comm)
        send_udp_packet(valid_client, send_info_ack)
        change_status(valid_client.id, REGISTERED)

        # Si completem registre, obrim fil del controlador periodic de comunicació amb el client (wait_alive())
        alive_timeout = datetime.now() + timedelta(seconds=3)
        alive_treatment = threading.Thread(target=wait_alives, args=(valid_client.id, alive_timeout))
        alive_treatment.start()
        return
    else:
        print_message("Paquet REG_INFO incorrecte")
        send_info_nack = info_nack_pack_maker("Dades incorrectes", valid_client.id_comm)
        send_udp_packet(valid_client, send_info_nack)
        change_status(valid_client.id, DISCONNECTED)
        return

def alive_phase(recv_pack):
    """Funcio que tracta els paquets ALIVES rebuts per l'UDP_loop.
    La variable self.first_alive_recv controla que el primer paquet s'hagui rebut,
    i la self.receive_alive serveix per sincronitzar l'estat amb el fil wait_alives,
    per saber si rep ALIVES en el temps demanat"""

    client_id_transm = recv_pack[1].decode().split("\x00")[0]
    client_id_comm = recv_pack[2].decode().split("\x00")[0]
    client_dades = recv_pack[3].decode("latin-1").split("\x00")[0]
    alive_client = get_client_by_Id(client_id_transm)

    if alive_client.status == REGISTERED or alive_client.status == SEND_ALIVE:
        if alive_client.id_comm == client_id_comm and len(client_dades) == 0:
            if alive_client.status == REGISTERED:
                alive_client.first_alive_recv = True
            alive_client.receive_alive = True
            alive_pck = alive_pack_maker(alive_client.id, alive_client.id_comm)
            send_udp_packet(alive_client, alive_pck)
            return
        elif alive_client.status == REGISTERED:
            print("INFO -> 1r Alive no valid: ", alive_client.id)
            alive_rej_pck = alive_rej_pack_maker(alive_client.id, alive_client.id_comm)
            send_udp_packet(alive_client, alive_rej_pck)
            change_status(alive_client.id, DISCONNECTED)
            return
        else:
            print("SERVER -> ALIVE no valid ")
            alive_rej_pck = alive_rej_pack_maker(alive_client.id, alive_client.id_comm)
            send_udp_packet(alive_client, alive_rej_pck)
            change_status(alive_client.id, DISCONNECTED)
            return
    else:
        print("SERVER -> ALIVE del client: " + client_id_transm + " no acceptat, client no esta REGISTERED o SEND_ALIVE ")
        return

def wait_alives(client_id, alive_timeout):
    """Aquesta funcio controla la comunicacio periodica del client.
    Com hem esmentat anteriorment, self.receive_alive controla si el paquet es rep en el minim de temps,
    si no es rep es suma 1 a ALIVES consecutius no rebuts( alive_client.consecutive_alive ).
    Als tres ALIVES no rebuts, client pasa a DISCONNECTED"""

    alive_client = get_client_by_Id(client_id)
    if alive_client.status == REGISTERED:
        """Controlem si el primer paquet s'ha rebut,
        si no es rep client es pasa a DISCONNECTED"""
        received_first_packet = False
        while datetime.now() < alive_timeout:
            if alive_client.first_alive_recv == True and alive_client.receive_alive:
                received_first_packet = True
                change_status(client_id, SEND_ALIVE)
                break
        if not received_first_packet:
            print_message("Primer Paquet ALIVE ha arribat a temps")
            change_status(client_id, DISCONNECTED)
            return

    while alive_client.status == SEND_ALIVE:
        send_alive_timeout = datetime.now() + timedelta(seconds=2)
        alive_client.receive_alive = False
        received_alive = False
        while datetime.now() < send_alive_timeout:
            if alive_client.receive_alive:
                alive_client.consecutive_alive = 0
                received_alive = True
        if not received_alive:
            alive_client.consecutive_alive += 1

        if alive_client.consecutive_alive == 3:
            print("No s'han rebut 3 ALIVE consecutius del client: ", alive_client.id)
            alive_client.consecutive_alive = 0
            change_status(client_id, DISCONNECTED)
            return

# -----------------------------TCP && SET/GET FUNCTIONS------------------------------------------#
def tcp_loop():
    """ Funcio que continuament esta rebent els paquets TCP dels diferents clients
    connectats. Per cada paquet es crea un fil que tractara el paquet.
    Per aqui s'haurien de rebre SEND_DATA"""
    global sock
    while 1:
        try:
            sock.tcp_socket.settimeout(3)
            private_socket, (client_ip, client_port) = sock.tcp_socket.accept()
            received_pck_tcp = receive_tcp_packet(127, private_socket)

            if received_pck_tcp:
                pack_procedure = threading.Thread(target=tcp_pack_procedure, args=(received_pck_tcp, private_socket))
                pack_procedure.start()
        except socket.error as socket_error:
            socket_error = "error"

def tcp_pack_procedure(packet, sockets):
    """ Funcio feta fil per TCP_LOOP(), tracta els SEND_DATA.
    SI rebes algun tipus de paquet incorrecte no el tractaria"""

    client_id = packet[1].decode().split("\x00")[0]
    if packet[0] == SEND_DATA:
        send_data_procedure(packet, sockets)

# -----------------------------SEND && RECEIVE UDP/TCP------------------------------------------#
def send_udp_packet(client, packet):
    #Funcio per enviar paquets amb UDP
    sock.udp_socket.sendto(packet, (client.ip, client.udp_port))

    received_package_unpacked = struct.unpack('B11s11s61s', packet)
    pack_type = received_package_unpacked[0]
    client_id_transm = received_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = received_package_unpacked[2].decode().split("\x00")[0]
    client_dades = received_package_unpacked[3].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("UDP PACKET Send -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Dades: " + client_dades)

def receive_udp_packet(num_bytes, sockets):
    #Funcio per rebre paquets amb UDP
    global sock
    global debug_mode
    received_pck_udp, (client_ip, client_port) = sockets.recvfrom(num_bytes)
    received_package_unpacked = struct.unpack('B11s11s61s', received_pck_udp)
    pack_type = received_package_unpacked[0]
    client_id_transm = received_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = received_package_unpacked[2].decode().split("\x00")[0]
    client_dades = received_package_unpacked[3].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("UDP PACKET Recv -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Dades: " + client_dades)
    return received_package_unpacked, client_ip, client_port

def receive_tcp_packet(num_bytes, sockets):
    #Funcio per rebre paquets amb TCP
    global sock
    global debug_mode
    recieved_pck_tcp = sockets.recv(num_bytes)

    if recieved_pck_tcp == b'':
        print("Paquet TCP no arribat")
        return False

    received_package_unpacked = struct.unpack('B11s11s8s16s80s', recieved_pck_tcp)
    pack_type = received_package_unpacked[0]
    client_id_transm = received_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = received_package_unpacked[2].decode().split("\x00")[0]
    client_element = received_package_unpacked[3].decode().split("\x00")[0]
    client_valor = received_package_unpacked[4].decode(errors="ignore").split("\x00")[0]
    client_info = received_package_unpacked[5].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("TCP PACKET Recv -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Element: " + client_element + ", " +
                      "valor: " + client_valor + ", " +
                      "info: " + client_info)
    return received_package_unpacked

def send_tcp_packet(packet, sockets):
    #Funcio per enviar paquets amb TCP
    global sock
    global debug_mode

    sockets.sendall(packet)

    send_package_unpacked = struct.unpack('B11s11s8s16s80s', packet)
    pack_type = packet[0]
    client_id_transm = send_package_unpacked[1].decode().split("\x00")[0]
    client_id_comm = send_package_unpacked[2].decode().split("\x00")[0]
    client_element = send_package_unpacked[3].decode().split("\x00")[0]
    client_valor = send_package_unpacked[4].decode(errors="ignore").split("\x00")[0]
    client_info = send_package_unpacked[5].decode(errors="ignore").split("\x00")[0]

    if debug_mode:
        print_message("TCP PACKET Send -> Type: " + str_status(pack_type) + ", " +
                      "Id_transm: " + client_id_transm + ", " +
                      "Id_comm: " + client_id_comm + ", " +
                      "Element: " + client_element + ", " +
                      "valor: " + client_valor + ", " +
                      "info: " + client_info)
    return

# -----------------------------ERROR CONTROL && PACKET MAKERS------------------------------------------#
"""En aquesta seccio trobarem tots el paquets
que revisen els condicionals de les funcions
o constructors de paquets per enviar durant
el proces de registre o paquets per enviar amb TCP"""

def client_id_and_id_comm_valid(client_id, client_id_comm):
    if get_client_by_Id(client_id):
        return client_id_comm == "0000000000"
    return False

def random_comm_and_id_valid(client, client_id_comm, client_id):
    if client.id_comm == client_id_comm:
        return client_id == client.ip
    return False

def reg_ack_pack_maker(random_comm, client_port):
    reg_ack_pck = struct.pack('B11s11s61s', REG_ACK, bytes(server_inf.id, 'ascii'), bytes(str(random_comm), 'ascii'),
                              bytes(str(client_port), 'ascii'))
    return reg_ack_pck

def info_ack_pack_maker(id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', INFO_ACK, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(server_inf.port_TCP), 'ascii'))
    return reg_ack_pck

def reg_rej_pack_maker(motiu):
    reg_ack_pck = struct.pack('B11s11s61s', REG_REJ, bytes(server_inf.id, 'ascii'), bytes("0000000000", 'ascii'),
                              bytes(motiu, 'ascii'))
    return reg_ack_pck

def info_nack_pack_maker(motiu, id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', INFO_NACK, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(motiu, 'ascii'))
    return reg_ack_pck

def alive_pack_maker(client_id, id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', ALIVE, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(client_id, 'ascii'))
    return reg_ack_pck

def alive_rej_pack_maker(client_id, id_comm):
    reg_ack_pck = struct.pack('B11s11s61s', ALIVE_REJ, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(client_id, 'ascii'))
    return reg_ack_pck

def data_ack_pack_maker(client_id, id_comm, element, valor):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', DATA_ACK, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(element), 'ascii'), bytes(str(valor), 'ascii'), bytes(client_id, 'ascii'))
    return reg_ack_pck

def data_rej_pack_maker(motiu):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', DATA_REJ, bytes(server_inf.id, 'ascii'), bytes("", 'ascii'),
                              bytes("", 'ascii'), bytes("", 'ascii'), bytes(motiu, 'ascii'))
    return reg_ack_pck

def set_data_maker(client_id, id_comm, element, valor):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', SET_DATA, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(element), 'ascii'), bytes(str(valor), 'ascii'), bytes(client_id, 'ascii'))
    return reg_ack_pck

def get_data_pack_maker(client_id, id_comm, element):
    reg_ack_pck = struct.pack('B11s11s8s16s80s', GET_DATA, bytes(server_inf.id, 'ascii'), bytes(str(id_comm), 'ascii'),
                              bytes(str(element), 'ascii'), bytes("", 'ascii'), bytes(client_id, 'ascii'))
    return reg_ack_pck

def element_exist(client, element):
    token = client.all_elements.split(";")

    for true_element in token:
        if element == true_element:
            return True
    return False

# -----------------------------TCP DATA TREATMENT------------------------------------------#
def send_data_procedure(data_pack, socket):
    """Tracta els SEND_DATA rebuts via TCP pel port del client.
    Si tot es correcte la funcio data_maker crea i guarda els diferents canvies en els elements en un "client_id".data"""
    client_id = data_pack[1].decode().split("\x00")[0]
    client_id_comm = data_pack[2].decode().split("\x00")[0]
    client_element = data_pack[3].decode().split("\x00")[0]
    client_valor = data_pack[4].decode("latin-1").split("\x00")[0]

    data_client = get_client_by_Id(client_id)
    if not data_client:
        for clients in allowed_client:
            if clients.id_comm == client_id_comm:
                send_package = data_rej_pack_maker("ID del client incorrecte")
                socket.send(send_package)
                change_status(clients.id, DISCONNECTED)
        return

    if client_id_comm == data_client.id_comm and element_exist(data_client, client_element):
        data_maker(client_id, str_status(data_pack[0]), client_element, client_valor, 0)
        send_package = data_ack_pack_maker(client_id, client_id_comm, client_element, client_valor)
        socket.send(send_package)
        return
    else:
        send_package = data_rej_pack_maker("Dades del dispositiu incorrectes")
        socket.send(send_package)
        change_status(client_id, DISCONNECTED)
        return

def set_call(argument):
    """Tracta la comanda set del servidor. Si rep resposta, pasa a la funcio set_get_rec_procedure que tractara el paquet rebut.
    Si no rep resposta es considera com que el client ha perdut contacte i es pasa a DISCONNECTED"""

    if len(argument.split(" ")) != 4:
        print("Us de la comanda: set <identificador_dispositiu> <identificador_element> <nou_valor>")
        return
    client_id = argument.split(" ")[1]
    element = argument.split(" ")[2]
    valor_element = argument.split(" ")[3]
    client = get_client_by_Id(client_id)

    if client is not False and element_exist(client, element):
        if element.split("-")[2] == "I":
            client_tcp_socket(client)
            send_pck = set_data_maker(client_id, client.id_comm, element, valor_element)
            send_tcp_packet(send_pck, client.tcp_socket)

            try:
                client.tcp_socket.settimeout(M)
                recv_packet = receive_tcp_packet(127, client.tcp_socket)
                if not recv_packet:
                    return
                set_get_rec_procedure(recv_packet, client, element, SET_DATA)
                client.tcp_socket.close()
                return

            except socket.error as socketerror:
                """Tractem l'excepcio del .settimeout com a resposta no rebuda
                i canviem client a DISCONNECTED"""

                client.tcp_socket.close()
                print_message("Resposta al SET_DATA no rebuda")
                change_status(client_id, DISCONNECTED)
                return
        print_message("L'element anomenat: " + element + " és un sensor i no permet establir el seu valor")
        return
    else:
        print_message("SET_DATA no realitzat: Dades incorrectes o estat diferent a SEND_ALIVE")
    print("Us de la comanda: set <identificador_dispositiu> <identificador_element> <nou_valor>")

def get_call(argument):
    """Tracta la comanda get del servidor. Si rep resposta, pasa a la funcio set_get_rec_procedure que tractara el paquet rebut.
    Si no rep resposta es considera com que el client ha perdut contacte i es pasa a DISCONNECTED"""

    if len(argument.split(" ")) != 3:
        print("Us de la comanda: get <identificador_dispositiu> <identificador_element>")
        return

    client_id = argument.split(" ")[1]
    element = argument.split(" ")[2]

    client = get_client_by_Id(client_id)

    if client is not False and client.status == SEND_ALIVE and element_exist(client, element):

        client_tcp_socket(client)
        send_pck = get_data_pack_maker(client.id, client.id_comm, element)
        send_tcp_packet(send_pck, client.tcp_socket)

        try:
            client.tcp_socket.settimeout(M)
            recv_packet = receive_tcp_packet(127, client.tcp_socket)
            if not recv_packet:
                return
            set_get_rec_procedure(recv_packet, client, element, GET_DATA)
            client.tcp_socket.close()
            return

        except socket.error as socketerror:
            #Mateixa explicacio que el set_call
            client.tcp_socket.close()
            print_message("Resposta al GET_DATA no rebuda")
            change_status(client_id, DISCONNECTED)
            return
    else:
        print_message("GET_DATA no realitzat: Dades incorrectes o estat diferent a SEND_ALIVE")
    print("Us de la comanda: get <identificador_dispositiu> <identificador_element>")

def set_get_rec_procedure(recv_packet, client, element, procedure_type):
    """Tracta els tres tipus de resposta de set i get (DATA_ACK, DATA_NACK, DATA_REJ)"""
    pack_type = recv_packet[0]
    client_id = recv_packet[1].decode().split("\x00")[0]
    client_id_comm = recv_packet[2].decode().split("\x00")[0]
    element_recv = recv_packet[3].decode().split("\x00")[0]
    valor = recv_packet[4].decode(errors="ignore").split("\x00")[0]
    client_info = recv_packet[5].decode(errors="ignore").split("\x00")[0]

    if client.id == client_id and client.id_comm == client_id_comm and element == element_recv:
        if pack_type == DATA_ACK:
            data_maker(client_id, str_status(procedure_type), element, valor, client_info)
            print_message("Operacio: " + str_status(procedure_type) + " correcte, element :" + element + " actualitzat")
        elif pack_type == DATA_NACK:
            print_message(
                "Operacio: " + str_status(procedure_type) + " fallida, element :" + element + " no actualitzat")
        elif pack_type == DATA_REJ:
            change_status(client_id, DISCONNECTED)
        return
    else:
        print_message("SERVER -> Paquet : " + str_status(pack_type) + " no valid. No s'han actualitzat les dades")
        return

# -----------------------------SAVE_FILES AND GLOBAL FUNCTIONS------------------------------------------#

def data_maker(client_id, pack_type, element, value, time_from_client):
    """Crea .data i guarda totes les actualitzacions
    dels element rebuts per send (client), set i get"""

    name_file = str(client_id) + ".data"
    file = open(name_file, "a+")
    file.read()

    if len(value) == 0:
        value = "NO-VALUE"

    current_time = time.strftime("%Y-%m-%d;%H:%M:%S", time.localtime(time.time()))
    if time_from_client != 0:
        current_time = time_from_client
    file.write(current_time + ";" + pack_type + ";" + element + ";" + value)
    file.write('\n')
    file.close()

    print_message("Paquet : " + pack_type + " rebut, " + " Element: " + element + " actualitzat")
    return

def set_reg_client_data(client, data):
    """Guarda la info rebuda per REG_INFO"""
    token = data.split(",")
    client.tcp_port = token[0]
    client.all_elements = token[1]

def arg_treatment(argv):
    """Tracta tots els arguments rebuts al executar el codi via terminal"""

    config_file = None
    allowed_clients = None
    for i in range(len(argv)):
        if argv[i] == "-d":
            global debug_mode
            debug_mode = True
            print_message("Debug mode activat")
        elif argv[i] == "-c" and len(argv) > i + 1:
            try:
                config_file = open(argv[i + 1], 'r')
            except IOError:
                print_message("Error al obrir la configuració del server, utilitzant server.cfg per defecte")
        elif argv[i] == "-u" and len(argv) > i + 1:
            try:
                allowed_clients = open(argv[i + 1], 'r')
            except IOError:
                print_message("Error al obrir la base de dades, utilitzant bbdd_dev.dat per defecte")
    if debug_mode:
        print_message("Llegint configuracions...")

    if config_file is None:
        try:
            config_file = open("server.cfg", 'r')
        except IOError:
            print_message("Error al obrir client.cfg ")
            exit(1)

    if allowed_clients is None:
        try:
            allowed_clients = open("bbdd_dev.dat", 'r')
        except IOError:
            print_message("Error al obrir la base de dades dels clients amb permisos")
            exit(1)

    save_client_database(allowed_clients)
    save_config(config_file)
    if debug_mode:
        print_message("LLegint configuracions i permisos")

def print_message(message):
    #Print missatges amb hora al inici del missatge
    current_time = time.strftime("%H:%M:%S", time.localtime(time.time()))
    print(str(current_time) + " MSG: " + message)
    sys.stdout.flush()

def save_client_database(database_file):
    """Guarda tota la configuracio dels clients
    de la base de dades rebuda com argument"""
    global allowed_client
    num_clients = 0
    for line in database_file:
        if line != "\n":
            token = line.split("\n")[0].split(" ")[0]
            client = Clients()
            client.id = token
            client.status = DISCONNECTED
            client.ip = client.ip
            client.all_elements = client.all_elements
            client.id_comm = client.id_comm
            allowed_client.append(client)
            num_clients += 1
    database_file.close()

def save_config(config_file):
    """Guarda la configuracio del archiu .cfg del servidor"""
    global server_inf

    for line in config_file:
        if line != "\n":
            argument = line.split("\n")[0].split(" ")
            if argument[0] == "Id":
                server_inf.id = argument[2]
            elif argument[0] == "UDP-port":
                server_inf.port_UDP = int(argument[2])
            elif argument[0] == "TCP-port":
                server_inf.port_TCP = int(argument[2])
    config_file.close()

def client_list():
    """Mostra per terminal la llista de clients, amb l'estat, ip, id_comm i elements de cadascun"""
    if allowed_client:
        print("    ID     -     IP      -  ID.COMM   -    ESTAT     -        ELEMENTS        -")
        print("-----------|-------------|------------|--------------|-------------------------")
        for client in allowed_client:
            print(client.id, "-", str(9 * " " if client.ip is None else client.ip),
                  "  -", str(10 * " " if client.id_comm is None else client.id_comm),
                  "-", str_status(client.status), str((11 - len(str_status(client.status))) * " "), "-",
                  str(10 * " " if client.all_elements is None else client.all_elements))

def str_status(status):
    """Segons el tipus de paquet/ estat del client rebut el torna en forma de string.
    Si rep un tipus incorrecte, retorna ERR_TYPE"""
    if status == DISCONNECTED:
        return "DISCONNECTED"
    elif status == NOT_REGISTERED:
        return "NOT_REGISTERED"
    elif status == WAIT_ACK_REG:
        return "WAIT_ACK_REG"
    elif status == WAIT_INFO:
        return "WAIT_INFO"
    elif status == WAIT_ACK_INFO:
        return "WAIT_ACK_INFO"
    elif status == REGISTERED:
        return "REGISTERED"
    elif status == SEND_ALIVE:
        return "SEND_ALIVE"
    elif status == ALIVE:
        return "ALIVE"
    elif status == REG_ACK:
        return "REG_ACK"
    elif status == REG_REQ:
        return "REG_REQ"
    elif status == REG_NACK:
        return "REG_NACK"
    elif status == REG_REJ:
        return "REG_REJ"
    elif status == REG_INFO:
        return "REG_INFO"
    elif status == INFO_ACK:
        return "INFO_ACK"
    elif status == INFO_NACK:
        return "INFO_NACK"
    elif status == INFO_REJ:
        return "INFO_REJ"
    elif status == ALIVE_NACK:
        return "ALIVE_NACK"
    elif status == ALIVE_REJ:
        return "ALIVE_REJ"
    elif status == SEND_DATA:
        return "SEND_DATA"
    elif status == DATA_ACK:
        return "DATA_ACK"
    elif status == DATA_NACK:
        return "DATA_NACK"
    elif status == DATA_REJ:
        return "DATA_REJ"
    elif status == SET_DATA:
        return "SET_DATA"
    elif status == GET_DATA:
        return "GET_DATA"
    else:
        return "ERR_TYPE"

def command_treatment():
    """Tracta les comandes rebudes per terminal"""
    global sock
    try:
        while True:
            line = sys.stdin.readline().strip('\n')
            command = line.split(" ")[0]
            if command == "list":
                client_list()
            elif command == "get":
                get_call(line)
            elif command == "set":
                set_call(line)
            elif command == "quit":
                """Tanquem tots els sockets oberts i enviem senyal SIGTERM als fils per matarlos
                i poder iniciar el server una altra vegada sense rebre errors dels sockets"""

                print_message("Tancant server...")
                sock.udp_socket.close()
                sock.tcp_socket.close()
                os.kill(os.getpid(), signal.SIGTERM)
            else:
                print_message("ERROR! Comanda no trobada: " + command)
    except(KeyboardInterrupt, SystemExit):
        return

def get_client_by_Id(id_transm):
    """Retorna el client segons una id donada"""
    global allowed_client

    for client in allowed_client:
        if client.id == id_transm:
            return client
    return False

def change_status(client_id, new_state):
    """Canvia el estat del client donat al estat rebut com argument"""
    client = get_client_by_Id(client_id)
    client.status = new_state

    print_message("SERVER -> Client " + client_id + " cambia al estat: "
                  + str_status(new_state))

# -----------------------------MAIN FUNCTION------------------------------------------#
def main():
    global sock
    global allowed_client
    try:
        #Lleguim arguments
        arg_treatment(sys.argv)
        #Creem fil que tractara comandes
        command_thread = threading.Thread(target=command_treatment)
        command_thread.daemon = True
        command_thread.start()
        #Obrim sockets TCP i UDP
        udp_socket()
        tcp_socket()
        #Obrim els UDP_loop i TCP_loop per tractar els paquets dels clients
        udp_connection = threading.Thread(target=udp_loop)
        udp_connection.start()
        tcp_connection = threading.Thread(target=tcp_loop)
        tcp_connection.start()

    except(KeyboardInterrupt, SystemExit):
        #En cas d'error a l'hora dexecutar el programa tancarem tots els sockets
        print_message("Error al executar el servidor, tancant...")
        sock.udp_socket.close()
        sock.tcp_socket.close()
        exit(1)

if __name__ == "__main__":
    main()


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('webapp', '0009_auto_20141216_0118'),
    ]

    operations = [
        migrations.AlterField(
            model_name='openinghours',
            name='weekday',
            field=models.IntegerField(choices=[(1, b'Monday'), (2, b'Tuesday'), (3, b'Wednesday'), (4, b'Thursday'), (5, b'Friday'), (6, b'Saturday'), (7, b'Sunday')]),
            preserve_default=True,
        ),
        migrations.AlterUniqueTogether(
            name='openinghours',
            unique_together=set([('weekday', 'store')]),
        ),
    ]


#!/usr/bin/env python3
'''
Perform classification of a corpus using CountVectorizer.
Displays the metrics from the classification.
'''

import codecs as cs
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import cross_validation
from sklearn import metrics
from sklearn.datasets import load_files

if __name__ == '__main__':
    corpus = "corpus5"
    label_names = ['relevant', 'spam']

    notices = load_files(corpus, categories=label_names, load_content=False, random_state=123)
    data = [cs.open(filename,'r','UTF-8').read() for filename in notices.filenames]

    n_samples = len(data)
    print("text read:{0}".format(n_samples))
    Y = notices.target

    tfidf = CountVectorizer(stop_words="english", max_df=0.8, ngram_range=(1,2))
    X = tfidf.fit_transform(data).todense()

    vocab = tfidf.vocabulary_
    print("vocab len=", len(vocab))

    test_size = 0.6
    X_train, X_test, y_train, y_test = \
        cross_validation.train_test_split(X, Y,
                                          test_size=test_size, random_state=0)

    print("--------------------------")
    print("TF (MultinomialNB)")
    print("--------------------------")
    #
    clf = MultinomialNB().fit(X_train, y_train)
    print("MultinomialNB score=", clf.score(X_test, y_test))
    y_pred = clf.predict(X_test)

    print(metrics.classification_report(y_test, y_pred, target_names=label_names))
    print(metrics.confusion_matrix(y_test, y_pred))

    cv = cross_validation.ShuffleSplit(X_train.shape[0], n_iter=10, test_size=test_size, random_state=0)

    CVscores = cross_validation.cross_val_score(clf, X_train, y_train, cv=cv, score_func=metrics.accuracy_score)
    print("svm.SVC crossvalidated score=", CVscores)

    print("Accuracy: %0.2f (+/- %0.2f)" % (CVscores.mean(), CVscores.std() / 2))
    CVscores = cross_validation.cross_val_score(clf, X_train, y_train, cv=cv, score_func=metrics.recall_score)
    print("Recall: %0.2f (+/- %0.2f)" % (CVscores.mean(), CVscores.std() / 2))
    CVscores = cross_validation.cross_val_score(clf, X_train, y_train, cv=cv, score_func=metrics.f1_score)
    print("F1: %0.2f (+/- %0.2f)" % (CVscores.mean(), CVscores.std() / 2))


import requests

def get_and_filter_data(api_url, filter_params):
    response = requests.get(api_url)

    if response.status_code == 200:
        data = response.json()

        filtered_data = [item for item in data if all(item.get(key) == value for key, value in filter_params.items())]

        return filtered_data
    else:
        print(f"Помилка при запиті: {response.status_code}")
        return None

api_url = "https://celestrak.org/NORAD/elements/gp.php?GROUP=last-30-days&FORMAT=json"
filter_params = {"OBJECT_NAME": "PSYCHE"}

filtered_data = get_and_filter_data(api_url, filter_params)

print(filtered_data)


# -*- coding: utf-8 -*-
""" Class to store Units and perform conversion

This script requires that `logging` be installed within the Python
environment you are running this script in.
"""
import logging
import json
from os import path
import logging.config

class Unit:
    """It represents the physical unit
         It has the following methods
                *convert(): It converts the given unit of quantity to the specified one
    """

    # Units of time
    SECONDS = "seconds"
    MINUTES = "minutes"
    HOURS = "hours"

    # Units of length
    METER = "meter"
    KILOMETER = "kilometer"
    INCH = "inch"
    FOOT = "foot"
    CENTIMETER = "centimeter"

    # Units of mass
    GRAM = "gram"
    KILOGRAM = "kilogram"
    MILLIGRAM = "milligram"
    TONNE = "tonne"

    # Temperature
    KELVIN = "kelvin"
    CELSIUS = "celsius"

    # Custom Units
    ONE = "one"
    NEW = "new"

    def __init__(self, value, unit, conversion_data):

        if unit == self.__class__.CELSIUS:
            if value < -273.15:
                logger.error("Celsius cannot be below -273.15", exc_info=True)
                raise Exception("Celsius cannot be below -273.15")
            else:
                self.value = value
                self.unit = unit
                self.conversion_data = conversion_data
        elif value < 0:
            logger.error(f"{unit} cannot be below 0", exc_info=True)
            raise Exception(f"{unit} cannot be below 0")
        else:
            self.value = value
            self.unit = unit
            self.conversion_data = conversion_data

    def convert(self, to_unit):
        """

        :param to_unit: The conversion unit
        :return Unit: New instance of the unit class with value and unit equal to the conversion
        """
        if self.unit == to_unit:
            logger.info("Same Unit Conversion")
            return Unit(self.value, self.unit, self.conversion_data)
        try:
            coef = self.conversion_data[self.unit][to_unit]
            result = coef[0]

            for i in range(1, len(coef)):
                result = (result * self.value) + coef[i]

            logger.info("Successfully Converted")
            return Unit(result, to_unit, self.conversion_data)
        except Exception:
            logger.error("Unit conversion not compatible", exc_info=True)

    def __str__(self):
        return f"{self.value}-{self.unit}"

def log():
    """
    Creates a custom logger from the configuration dictionary
    """
    with open('UnitsLog.json', 'r') as f:
        config = json.load(f)
        logging.config.dictConfig(config)
    global logger
    logger = logging.getLogger(__name__)

def main():
    """
        Main function to store units
    """
    log()

    file = 'conversion.json'
    if not path.exists(file):
        logger.error("The given file does not exist")
        return
    with open(file) as f:
        data = json.load(f)
    try:
        g = Unit(273.15, Unit.GRAM, data)
        print(g)
        Tk = g.convert(g.KELVIN)
        print(Tk)
    except Exception:
        logger.error("Error Occurred", exc_info=True)

if __name__ == '__main__':
    main()


from copy import deepcopy
import requests

from c2corg_api.legacy.converter import convert_from_legacy_doc, convert_to_legacy_doc
from c2corg_api.schemas import schema_validator

def test_converter(document_id, document_type):
    legacy_doc = requests.get(f"https://api.camptocamp.org/{document_type}s/{document_id}", timeout=10).json()

    v7_doc = convert_from_legacy_doc(deepcopy(legacy_doc), document_type, {})

    try:
        schema_validator.validate(v7_doc["data"], f"{document_type}.json")
    except:  # pylint: disable=bare-except
        print(document_id)
        # with open(f"migrations/documents/{document_id}.json", mode="w", encoding="utf-8") as f:
        #     json.dump(legacy_doc, f, indent=4)

    convert_to_legacy_doc(v7_doc)

def crawl(document_type, pages):
    params = {"offset": 0, "limit": 100}
    url = f"https://api.camptocamp.org/{document_type}s"

    while pages > 0:
        pages -= 1
        r = requests.get(url, params=params, timeout=10).json()
        print(f"{document_type} {params['offset']}/{r['total']}")
        documents = r["documents"]

        if len(documents) == 0:
            return

        for document in documents:
            yield document["document_id"]

        params["offset"] += 100

def main():
    for document_type, pages in (("article", 3), ("xreport", 5)):
        for document_id in crawl(document_type, pages):
            test_converter(document_id, document_type)

main()


from math import fabs
from platform import platform
from tkinter.tix import Tree
import pygame
import os
import random
import time

class Setting:
    window_width = 750
    window_height = 900
    frames = 60
    path_file = os.path.dirname(os.path.abspath(__file__))
    image_path = os.path.join(path_file, "Images")
    sound_path = os.path.join(path_file, "Sounds")
    score = "score.txt"
    title = "Spiel mit Sprung"
    jump_speed = 0
    punkte = 0
    gravity = 0.2
    upscroll = False
    hit = False
    loose = False
    count_plat = 0
    max_plat = 25
    scale_x = 125
    scale_y = 15
    play_music = True
    score = 0
    highscore = 0

class Button:
    def __init__(self, image, pos, text_input, font, base_color, hovering_color):
        self.image = image
        self.x_pos = pos[0]
        self.y_pos = pos[1]
        self.font = font
        self.base_color, self.hovering_color = base_color, hovering_color
        self.text_input = text_input
        self.text = self.font.render(self.text_input, True, self.base_color)
        if self.image is None:
            self.image = self.text
        self.rect = self.image.get_rect(center=(self.x_pos, self.y_pos))
        self.text_rect = self.text.get_rect(center=(self.x_pos, self.y_pos))

    def update(self, screen):
        if self.image is not None:
            screen.blit(self.image, self.rect)
        screen.blit(self.text, self.text_rect)

    def checkForInput(self, position):
        if position[0] in range(self.rect.left, self.rect.right) and position[1] in range(self.rect.top, self.rect.bottom):
            return True
        return False

    def changeColor(self, position):
        if position[0] in range(self.rect.left, self.rect.right) and position[1] in range(self.rect.top, self.rect.bottom):
            self.text = self.font.render(
                self.text_input, True, self.hovering_color)
        else:
            self.text = self.font.render(
                self.text_input, True, self.base_color)

class Background:
    def __init__(self, filename="background.png") -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, filename)).convert()
        self.image = pygame.transform.scale(
            self.image, (Setting.window_width, Setting.window_height))

    def draw(self, screen):
        screen.blit(self.image, (0, 0))

    def update(self):
        pass

class First_Plat(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = Setting.window_width//2
        self.rect.centery = Setting.window_height

    def update(self):

        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat += 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class Movingp(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.xspeed = 1 or -1
        self.xmove = self.xspeed
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)

    def update(self):

        if self.rect.right == Setting.window_width:
            self.xmove = self.xspeed * -1
        if self.rect.left == 0:
            self.xmove = self.xspeed * 1

        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        self.rect.move_ip((self.xmove, 0))
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class Plattform(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)

    def update(self):
        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class BreakingPlat(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)

    def update(self):
        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class BreakingPlat_move(pygame.sprite.Sprite):
    def __init__(self, picturefile) -> None:
        super().__init__()
        self.image = pygame.image.load(os.path.join(
            Setting.image_path, picturefile)).convert_alpha()
        self.scalex = Setting.scale_x
        self.scaley = Setting.scale_y
        self.imageindex = 0
        self.image = pygame.transform.scale(
            self.image, (self.scalex, self.scaley))
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = random.randint(10, Setting.window_width - 10)
        self.rect.centery = random.randint(10, Setting.window_height / 1.5)
        self.xspeed = 1 or -1
        self.xmove = self.xspeed

    def update(self):
        if self.rect.right == Setting.window_width:
            self.xmove = self.xspeed * -1
        if self.rect.left == 0:
            self.xmove = self.xspeed * 1

        if Setting.upscroll == True:
            if Setting.jump_speed <= 0:
                self.rect.centery += Setting.jump_speed*-1
        self.rect.move_ip((self.xmove, 0))
        if self.rect.top >= Setting.window_height:
            self.kill()
            Setting.punkte += 1
            Setting.count_plat -= 1
        if Setting.loose == True:
            self.kill()
            Setting.count_plat -= 1

class Spieler(pygame.sprite.Sprite):
    def __init__(self) -> None:
        super().__init__()
        self.image_org = pygame.image.load(os.path.join(
            Setting.image_path, "jumper.png")).convert_alpha()
        self.image = self.image_org
        self.rect = self.image.get_rect()
        self.radius = self.rect.width // 2
        self.imageindex = 0
        self.mask = pygame.mask.from_surface(self.image)
        self.rect.centerx = Setting.window_width // 2
        self.rect.centery = Setting.window_height // 2
        self.speed = 0
        self.x_movement = 0

    def update(self):

        if Setting.hit == False:
            Setting.jump_speed += Setting.gravity
        if Setting.hit == True:
            Setting.jump_speed = -13
            Setting.hit = False
        if self.rect.left >= Setting.window_width:
            self.rect.centerx = 0
        if self.rect.right < 0:
            self.rect.centerx = Setting.window_width
        self.rect.move_ip((self.x_movement, Setting.jump_speed))

    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def left(self):
        self.x_movement = -5
        self.image = pygame.transform.flip(self.image_org, True, False)

    def right(self):
        self.x_movement = 5
        self.image = self.image_org

    def check_pos(self):
        if self.rect.top <= 0:
            Setting.upscroll = True
        else:
            Setting.upscroll = False

    def loose(self):
        if self.rect.top >= Setting.window_height:
            Setting.loose = True

class Game(object):
    def __init__(self) -> None:
        super().__init__()
        os.environ['SDL_VIDEO_WINDOW_POS'] = "50,30"

        pygame.init()
        pygame.display.set_caption(Setting.title)
        self.screen = pygame.display.set_mode(
            (Setting.window_width, Setting.window_height))
        self.clock = pygame.time.Clock()
        self.running = False
        self.counter = 0
        self.duration = 120
        self.spieler = Spieler()
        self.first = pygame.sprite.Group()
        self.breakingp = pygame.sprite.Group()
        self.all_obstacles = pygame.sprite.Group()
        self.font = pygame.font.Font(pygame.font.get_default_font(), 24)
        self.breakingp_move = pygame.sprite.Group()
        self.all_obstacles.add(Plattform("platform.png"))
        self.sound()
        self.background = Background()
        self.score = 0

    def get_font(size):  # Returns Press-Start-2P in the desired size
        return pygame.font.Font("assets/font.ttf", size)

    def draw(self, screen):
        screen.blit(self.image, (0, 0))

    def sound(self):
        self.volume = 0.4
        self.jump_sound = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "Jump.mp3"))
        self.background_music = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "background.mp3"))
        self.background_music = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "background.mp3"))
        self.break_sound = pygame.mixer.Sound(
            os.path.join(Setting.sound_path, "break.mp3"))
        self.background_music.set_volume(self.volume)
        self.jump_sound.set_volume(self.volume)
        self.break_sound.set_volume(self.volume)
        self.background_music.play(-1)

    def mute(self):
        if Setting.play_music == False:
            self.volume = 0
            self.background_music.set_volume(self.volume)

    def unmute(self):
        if Setting.play_music == True:
            self.volume = 0.5
            self.background_music.set_volume(self.volume)

    def scores(self):
        while True:
            OPTIONS_MOUSE_POS = pygame.mouse.get_pos()

            self.screen.blit(self.background.image, (0, 0))
            OPTIONS_TEXT = self.font.render(
                "Highscore", True, "Black")
            OPTIONS_RECT = OPTIONS_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height//5))

            NOWW_TEXT = self.font.render(
                "Letzter Score", True, "Black")
            NOWW_RECT = OPTIONS_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height/2.5))

            SCORE_TEXT = self.font.render(
                str(Setting.highscore), True, "Black")
            SCORE_RECT = SCORE_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height//4))

            NOW_TEXT = self.font.render(str(Setting.punkte), True, "Black")
            NOW_RECT = SCORE_TEXT.get_rect(
                center=(Setting.window_width/2, Setting.window_height//2))

            OPTIONS_BACK = Button(image=None, pos=(640, 850),
                                  text_input="BACK", font=self.font, base_color="Black", hovering_color="Green")

            PLAY = Button(image=None, pos=(Setting.window_width/2, 850),
                          text_input="PLAY", font=self.font, base_color="Black", hovering_color="Green")

            OPTIONS_BACK.changeColor(OPTIONS_MOUSE_POS)
            OPTIONS_BACK.update(self.screen)
            PLAY.changeColor(OPTIONS_MOUSE_POS)
            PLAY.update(self.screen)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        self.run()

                if event.type == pygame.MOUSEBUTTONDOWN:
                    if OPTIONS_BACK.checkForInput(OPTIONS_MOUSE_POS):
                        self.main_menu()
                    if PLAY.checkForInput(OPTIONS_MOUSE_POS):
                        self.run()
                        break

            self.screen.blit(OPTIONS_TEXT, OPTIONS_RECT)
            self.screen.blit(SCORE_TEXT, SCORE_RECT)
            self.screen.blit(NOWW_TEXT, NOWW_RECT)
            self.screen.blit(NOW_TEXT, NOW_RECT)
            pygame.display.flip()

            pygame.display.update()

    def main_menu(self):
        while True:

            self.screen.blit(self.background.image, (0, 0))

            MENU_MOUSE_POS = pygame.mouse.get_pos()

            MENU_TEXT = self.font.render("MAIN MENU", True, "Black")
            MENU_RECT = MENU_TEXT.get_rect(
                center=(Setting.window_width // 2, 100))

            PLAY_BUTTON = Button(image=None, pos=(Setting.window_width // 2, 250),
                                 text_input="Play", font=self.font, base_color="Black", hovering_color="White")
            OPTIONS_BUTTON = Button(image=None, pos=(Setting.window_width // 2, 400),
                                    text_input="Score", font=self.font, base_color="Black", hovering_color="White")
            QUIT_BUTTON = Button(image=None, pos=(Setting.window_width // 2, 550),
                                 text_input="Quit", font=self.font, base_color="Black", hovering_color="White")
            if Setting.play_music == True:
                VOLUME_BUTTON = Button(image=pygame.image.load(os.path.join(
                    Setting.image_path, "play.png")), pos=(Setting.window_width // 2, 800),
                    text_input="-", font=self.font, base_color="Black", hovering_color="Green")
            if Setting.play_music == False:
                VOLUME_BUTTON = Button(image=pygame.image.load(os.path.join(
                    Setting.image_path, "mute.png")), pos=(Setting.window_width // 2, 800),
                    text_input="-", font=self.font, base_color="Black", hovering_color="Green")

            self.screen.blit(MENU_TEXT, MENU_RECT)

            for button in [PLAY_BUTTON, OPTIONS_BUTTON, QUIT_BUTTON, VOLUME_BUTTON]:
                button.changeColor(MENU_MOUSE_POS)
                button.update(self.screen)

            pygame.display.update()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if PLAY_BUTTON.checkForInput(MENU_MOUSE_POS):
                        self.run()

                    if OPTIONS_BUTTON.checkForInput(MENU_MOUSE_POS):
                        self.scores()
                    if VOLUME_BUTTON.checkForInput(MENU_MOUSE_POS):
                        if Setting.play_music == True:
                            Setting.play_music = False
                            self.mute()

                            pygame.mixer.music.pause()
                        elif Setting.play_music == False:
                            Setting.play_music = True
                            self.unmute()

                            pygame.mixer.music.unpause()
                    if QUIT_BUTTON.checkForInput(MENU_MOUSE_POS):
                        pygame.quit()

            pygame.display.update()
            pygame.display.flip()

    def groupcollide(self):
        if pygame.sprite.spritecollide(self.spieler, self.all_obstacles, False):
            Setting.hit = True
            self.jump_sound.play()
        elif pygame.sprite.spritecollide(self.spieler, self.first, False):
            Setting.hit = True
            self.jump_sound.play()
        elif pygame.sprite.spritecollide(self.spieler, self.breakingp, True):
            Setting.hit = True
            self.break_sound.play()
        elif pygame.sprite.spritecollide(self.spieler, self.breakingp_move, True):
            Setting.hit = True
            self.break_sound.play()
        else:
            Setting.hit = False

    def reset(self):
        self.spieler.rect.x = Setting.window_width // 2
        self.spieler.rect.y = Setting.window_height // 2
        Setting.jump_speed = 0
        self.spieler.x_movement = 0
        self.screen.blit(self.background.image, (0, 0))
        Setting.loose = False
        self.all_obstacles.empty()
        self.breakingp_move.empty()
        self.breakingp.empty()
        self.first.add(First_Plat("platform.png"))
        Setting.count_plat =  0
        self.running= True

    def highscore(self):
        if Setting.punkte >= Setting.highscore:
            Setting.highscore = Setting.punkte
        else:
            pass

    def read_score(self):
        self.file = open("score.txt", "r")
        self.read = self.file.read()
        Setting.highscore = int(self.read)
        self.file.close()
        return self.score

    def write_score(self):
        self.file = open("score.txt", "w")
        if Setting.score > Setting.highscore:

            self.file.write(str(Setting.score))
            self.file.close()
        else:
            self.file.close()

    def run(self):
        self.reset()
        Setting.punkte = 0
        self.screen.blit(self.background.image, (0, 0))

        while self.running:
            self.clock.tick(Setting.frames)

            # Eventverarbeitung
            self.watch_for_events()
            # Update
            self.all_obstacles.update()
            self.spieler.update()
            self.first.update()
            self.breakingp.update()
            self.breakingp_move.update()

            # Bildschirmausgabe
            self.background.draw(self.screen)
            self.all_obstacles.draw(self.screen)
            self.spieler.draw(self.screen)
            self.first.draw(self.screen)
            self.breakingp.draw(self.screen)
            self.breakingp_move.draw(self.screen)
            text_surface_modus = self.font.render(
                "Punktzahl: {0}".format(Setting.punkte), True, (0, 0, 0))
            self.screen.blit(text_surface_modus, dest=(
                10, Setting.window_height-900))

            self.groupcollide()
            self.more()
            self.spieler.check_pos()
            self.spieler.loose()
            self.end()
            self.mute()
            self.unmute()
            pygame.display.flip()

    def watch_for_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
            elif self.running == True:
                if event.type == pygame.KEYDOWN:

                    if event.key == pygame.K_LEFT:
                        self.spieler.left()
                    elif event.key == pygame.K_RIGHT:
                        self.spieler.right()

    def end(self):
        if Setting.loose == True:
            self.highscore()
            #self.write_score()
            self.scores()

    def more(self):
        self.spawnrate = 5
        self.counter += 1
        if self.counter >= self.duration:
            if Setting.count_plat <= Setting.max_plat:
                if Setting.punkte >= 15:
                    for i in range(1):

                        if Setting.punkte >= 15:
                            self.all_obstacles.add(Movingp("platform_move.png"))
                            Setting.count_plat += 1
                            self.counter = 0
                        if Setting.punkte >= 30:
                            self.breakingp.add(BreakingPlat("platform_break.png"))
                            Setting.count_plat += 1
                            self.counter = 0
                        if Setting.punkte >= 40:
                            self.breakingp_move.add(BreakingPlat_move("platform_break_move.png"))
                            Setting.count_plat += 1
                            self.counter = 0

                else:
                    for i in range(2):
                        self.all_obstacles.add(Plattform("platform.png"))
                        self.counter = 0
                        Setting.count_plat += 1

if __name__ == "__main__":
    game = Game()
    game.main_menu()

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

                #       #

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

#################################
# Menu with help from yt https://www.youtube.com/watch?v=GMBqjxcKogA&ab_channel=BaralTech
# Jumper Graphic from https://favpng.com/png_view/doodle-vector-doodle-jump-kinect-video-game-iphone-png/UVAWVSjC
# Jump Sound https://www.youtube.com/watch?v=cxPQ2vk-oDk&ab_channel=LatifKhan
# Breaking Sound https://www.youtube.com/watch?v=5kdSouOn09M&ab_channel=Music%26SoundsEffectLibrary
# Hintergrundmusik https://www.youtube.com/watch?v=MF_zoKQysfI&ab_channel=AudioLibrary%E2%80%94Musicforcontentcreator


def COOKEweights(SQ_array, TQ_array, realization, alpha, background_measure,
                 overshoot, cal_power):
    """Compute the weights with Cooke formulation

    Parameters
    ----------
    SQ_array : numpy array
        Array with answers to seed questions
    TQ_array : numpy array
        Array with answers to seed questions
    realization : list
        Python list with realization of the seed questions
    alpha : float
        Significance
    background_measure:
        Python list
    overshoot : float
    cal_power : float

    Returns
    -------
    W : numpy array
        an array with weights

    This function is based on the Matlab package
    ANDURIL (Authors:  Georgios Leontaris and
    Oswaldo Morales-Napoles)
    """

    import numpy as np

    # number of Seed questions
    N = SQ_array.shape[2]
    # number of experts
    E = SQ_array.shape[0]
    # number of realization in every bin
    M = np.zeros((E, 4))
    # score
    C = np.zeros((E))
    # unNormalized weight
    w = np.zeros((E))
    # array with information, score and normalized weight for each expert
    W = np.zeros((E, 5))

    # create numpy array M with the number of realizations captured in every
    # expert's bin that is formed by the provided quantiles
    for ex in np.arange(E):
        for i in np.arange(N):
            if realization[i] < SQ_array[ex, 0, i]:

                M[ex, 0] = M[ex, 0] + 1

            elif realization[i] == SQ_array[ex, 0, i]:

                M[ex, 0] = M[ex, 0] + 0.5
                M[ex, 1] = M[ex, 1] + 0.5

            elif realization[i] < SQ_array[ex, 1, i]:

                M[ex, 1] = M[ex, 1] + 1

            elif realization[i] == SQ_array[ex, 1, i]:

                M[ex, 1] = M[ex, 1] + 0.5
                M[ex, 2] = M[ex, 2] + 0.5

            elif realization[i] < SQ_array[ex, 2, i]:

                M[ex, 2] = M[ex, 2] + 1

            elif realization[i] == SQ_array[ex, 2, i]:

                M[ex, 2] = M[ex, 2] + 0.5
                M[ex, 3] = M[ex, 3] + 0.5

            else:

                M[ex, 3] = M[ex, 3] + 1
    """

    # create numpy array M with the number of realizations captured in every
    # expert's bin that is formed by the provided quantiles
    for ex in np.arange(E):
        for i in np.arange(N):
            if realization[i] < SQ_array[ex, 0, i]:

                M[ex, 0] = M[ex, 0] + 1

            elif realization[i] < SQ_array[ex, 1, i]:

                M[ex, 1] = M[ex, 1] + 1

            elif realization[i] < SQ_array[ex, 2, i]:

                M[ex, 2] = M[ex, 2] + 1

            else:

                M[ex, 3] = M[ex, 3] + 1

    """

    # calculate calibration and information score for every expert
    [I_real, I_tot] = calculate_information(SQ_array, TQ_array, realization,
                                            overshoot, background_measure)

    for ex in np.arange(E):

        C[ex] = calscore(M[ex, :], cal_power)

        W[ex, 0] = C[ex]
        W[ex, 1] = I_tot[ex]
        W[ex, 2] = I_real[ex]

        w[ex] = C[ex] * I_real[ex]

    # unNormalized weight
    W[:, 3] = w.T

    # set to zero based on calibration score
    w[C < alpha] = 0.0

    # set to zero based on weight
    # w[ (w/np.sum(w)) < alpha] = 0.0

    # Normalized weight
    W[:, 4] = w / np.sum(w)

    return W, C, I_real

def calscore(M, cal_power):
    """Compute single expert score

    Parameters
    ----------
    M : numpy array
        Number of realizations captured in every expert's bin
        that is formed by the provided quantiles
    cal_power : float

    Returns
    -------
    CS : float
         Score

    This function is based on the Matlab package
    ANDURIL (Authors:  Georgios Leontaris and
    Oswaldo Morales-Napoles)
    """

    import numpy as np
    from scipy.stats import chi2

    N = np.sum(M)  # number of seed items
    S = M / N

    if np.sum(np.isnan(S)) == len(S):

        CS = np.nan

    else:
        if len(S) == 4:
            P = np.array([0.05, 0.45, 0.45, 0.05])
        elif len(S) == 6:
            P = np.array([0.05, 0.20, 0.25, 0.25, 0.20, 0.05])

        E1 = S * np.log(S / P)
        MI = np.sum(E1[~np.isnan(E1)])
        E = 2.0 * N * MI * cal_power
        CS = chi2.sf(E, len(S) - 1)

    return CS

def calculate_information(SQ_array, TQ_array, realization, k,
                          background_measure):
    """
    This function is based on the Matlab package
    ANDURIL (Authors:  Georgios Leontaris and
    Oswaldo Morales-Napoles)
    """

    import numpy as np

    p = [0.05, 0.45, 0.45, 0.05]
    N = SQ_array.shape[2]
    E = SQ_array.shape[0]
    N_P = len(p)
    suma = np.zeros((N, E))
    x = np.zeros((E, N_P + 1))

    Nq = TQ_array.shape[2]

    lowval = np.zeros(N + Nq)
    highval = np.zeros(N + Nq)

    x_o = np.zeros(N + Nq)
    x_n = np.zeros(N + Nq)

    info_per_variable = np.zeros((N + Nq, E))
    Info_score_real = np.zeros((E))
    Info_score_tot = np.zeros((E))

    for i in np.arange(N):

        lowval[i] = np.minimum(np.amin(SQ_array[:, :, i]), realization[i])
        highval[i] = np.maximum(np.amax(SQ_array[:, :, i]), realization[i])

        for e in np.arange(E):

            if background_measure[i] == "uni":

                x_o[i] = lowval[i] - k * (highval[i] - lowval[i])
                x_n[i] = highval[i] + k * (highval[i] - lowval[i])

                tmp = np.insert(SQ_array[e, :, i], 0, x_o[i])
                tmp2 = np.append(tmp, x_n[i])
                x[e, :] = tmp2

            elif background_measure[i] == "log":

                if lowval[i] < 0 or highval[i] < 0:

                    raise ValueError(
                        "Log-Uniform background measure cannot be used "
                        "for item %d because an expert provided "
                        "negative values",
                        i,
                    )

                x_o[i] = np.log(
                    lowval[i]) - k * (np.log(highval[i]) - np.log(lowval[i]))
                x_n[i] = np.log(
                    highval[i]) + k * (np.log(highval[i]) - np.log(lowval[i]))
                tmp = np.insert(np.log(SQ_array[e, :, i]), 0, x_o[i])
                tmp2 = np.append(tmp, x_n[i])
                x[e, :] = tmp2

            for j in np.arange(N_P):

                suma[i, e] = suma[i, e] + p[j] * \
                    np.log(p[j] / (x[e, j + 1] - x[e, j]))

            info_per_variable[i, e] = np.log(x_n[i] - x_o[i]) + suma[i, e]

    for e in np.arange(E):
        # for the overall information of every expert take the average of each
        # expert e for all calibration variables N
        Info_score_real[e] = np.sum(info_per_variable[:, e]) / N

    N_items_tot = SQ_array.shape[2] + TQ_array.shape[2]
    sumb = np.zeros((N_items_tot, E))

    for i in np.arange(SQ_array.shape[2], N_items_tot):

        if not realization[i]:  # information of Target Questions

            lowval[i] = np.amin(TQ_array[:, :, i - SQ_array.shape[2]])
            highval[i] = np.amax(TQ_array[:, :, i - SQ_array.shape[2]])

            for e in np.arange(E):

                if background_measure[i] == "uni":

                    x_o[i] = lowval[i] - k * (highval[i] - lowval[i])
                    x_n[i] = highval[i] + k * (highval[i] - lowval[i])

                    tmp = np.insert(TQ_array[e, :, i - SQ_array.shape[2]], 0,
                                    x_o[i])
                    tmp2 = np.append(tmp, x_n[i])
                    x[e, :] = tmp2

                elif background_measure[i] == "log":

                    if lowval[i] < 0 or highval[i] < 0:

                        raise ValueError(
                            "Log-Uniform background measure cannot be used "
                            "for item %d because an expert provided "
                            "negative values",
                            i,
                        )

                    x_o[i] = np.log(lowval[i]) - k * (np.log(highval[i]) -
                                                      np.log(lowval[i]))
                    x_n[i] = np.log(highval[i]) + k * (np.log(highval[i]) -
                                                       np.log(lowval[i]))

                    tmp = np.insert(
                        np.log(TQ_array[e, :, i - SQ_array.shape[2]]), 0,
                        x_o[i])
                    tmp2 = np.append(tmp, x_n[i])
                    x[e, :] = tmp2

                for j in np.arange(N_P):

                    sumb[i - SQ_array.shape[2],
                         e] = sumb[i - SQ_array.shape[2],
                                   e] + p[j] * np.log(p[j] /
                                                      (x[e, j + 1] - x[e, j]))

                info_per_variable[i, e] = (np.log(x_n[i] - x_o[i]) +
                                           sumb[i - SQ_array.shape[2], e])

    # compute total information score
    for e in np.arange(E):

        # for the overall information of every expert take the average of each
        # expert e for all calibration variables N_items_tot
        Info_score_tot[e] = np.sum(info_per_variable[:, e]) / N_items_tot

    return Info_score_real, Info_score_tot


import os
from unidecode import unidecode
from pathlib import Path
import argparse
import re

parser = argparse.ArgumentParser()
parser.add_argument("--path", type=str, required=True)
parser.add_argument("--remove_accent", type=bool, required=False, default=True)
parser.add_argument("--lower", type=bool, required=False, default=True)
parser.add_argument("--recursive", type=bool, required=False, default=False)
args = parser.parse_args()

path = args.path
remove_accent = args.remove_accent
lower = args.lower
recursive = args.recursive

def create_log_structure():
    if not os.path.exists('logs'):
        os.mkdir("logs")
    open("logs/folders_accessed.txt", "w").close()

def add_break_line(path_list: list):
    for item in path_list:
        yield item
        yield "\n"

def write_log(path_list: list) -> None:
    with open("logs/folders_accessed.txt", mode="a") as file:
        file.writelines(add_break_line(path_list))

def access_next_path(path: str) -> None:
    directory_log_list = []
    with open("logs/folders_accessed.txt", mode="a") as file:
        file.write(f"{path}\n")
        file.close()

    if not path.endswith("/"):
        path = path + "/"

    path_list = os.listdir(path)

    for path_item in path_list:
        path_item_name, extension = os.path.splitext(path_item)
        new_path = os.path.join(path, path_item_name) + "/"
        if not extension:
            try:
                directory_log_list.append(new_path)
                access_next_path(new_path)
            except:
                pass
        elif extension == ".ini":
            continue
        else:
            file_padronizer(
                path=path, remove_accent=remove_accent, lower=lower, recursive=recursive
            )
    write_log(path_list=directory_log_list)

def file_padronizer(
    path: str, remove_accent: bool, lower: bool, recursive: bool
) -> None:
    path_list = os.listdir(path)
    for file in path_list:
        name, extension = os.path.splitext(file)
        if name in [".git", ".git/"]:
            continue
        if extension and extension != ".ini":  # in program_formats or text_formats:
            new_name = name.strip()
            new_name = re.sub(pattern=r"\+|-|\(|\)|\.|\_|\__|\s|,|_{2,}|’|'",repl="_",string=new_name)
            new_name = re.sub(pattern=r"_{2,}",repl="_", string=new_name)
            new_name = re.sub(pattern=r"_+$",repl="",string=new_name)
            new_name = re.sub(pattern=r"^_+",repl="", string=new_name)
            if remove_accent:
                new_name = unidecode(unidecode(new_name))
            if lower:
                new_name = new_name.lower()
            elif not lower:
                new_name = new_name.upper()
            new_file = new_name + extension
            os.rename(src=f"{os.path.join(path,file)}", dst=f"{os.path.join(path,new_file)}")
        elif not extension and recursive:
            try:
                new_path = os.path.join(path, name) + "/"
                access_next_path(new_path)
            except:
                continue

if __name__ == "__main__":
    create_log_structure()
    file_padronizer(path, remove_accent, lower, recursive)


import sys

sys.path.insert(1, 'C:\\Users\\upcnet\\Repositoris\\neuroimatge\\nonlinear2')
sys.path.insert(1, '/Users/acasamitjana/Repositories/neuroimatge/nonlinear2')
from Fitters.GAM import GAM, SmootherSet, SplinesSmoother
import numpy as np
import numpy.random as R
# import matplotlib
# matplotlib.use('GTKAgg')
import matplotlib.pyplot as plt

standardize = lambda x: x  # (x - x.mean()) / x.std()
standarize = lambda x: (x - x.mean())  # / x.std()
nknots = 10
nobs = 129
t1 = R.standard_normal(nobs)
f1 = lambda x: 1 * np.sin(np.pi * np.sort(x))

t2 = t1
s2 = R.standard_normal(nobs)
f2 = lambda x2: (x2 + x2 ** 2)

y = 0.1 * R.standard_normal(nobs)  # np.zeros(nobs)#

z = f1(t1)  # + f2(t2)

y += z

regressor_smoother = SmootherSet()
corrector_smoother = SmootherSet()
# regressor_smoother.append(PolynomialSmoother(t1,order=2))
regressor_smoother.append(SplinesSmoother(t2, order=5, smoothing_factor=0.1))
# regressor_smoother.append(PolynomialSmoother(x3,order=2))

gam = GAM(corrector_smoothers=corrector_smoother, predictor_smoothers=regressor_smoother)
# gam.orthogonalize_all()
gam.fit(y)
y_pred_r = gam.predict()

plt.figure()
plt.plot(gam.correct(y), 'k.')
plt.plot(gam.correct(z), 'b-', label='true')
plt.plot(y_pred_r, 'r-', label='AdditiveModel')
plt.legend()
plt.title('gam.AdditiveModel')
plt.show()
reg_params = gam.prediction_parameters
indx_smthr = 0

plt.figure()
plt.subplot(2, 1, 1)
plt.plot(np.sort(t1), standarize(y - gam.alpha), 'k.')
plt.plot(np.sort(t1), standarize(
    gam.predict(gam.predictors[:, 0][..., None], reg_params[indx_smthr:indx_smthr + 2 + reg_params[indx_smthr + 1]])),
         'r-', label='AdditiveModel')
plt.plot(np.sort(t1), standarize(f1(t1)), 'b-', label='true', linewidth=2)
plt.legend()
plt.title(gam.df_model())

# plt.subplot(2,1,2)
# plt.plot(t2, standarize(y-gam.alpha-f1(t1)),'k.')
# plt.plot(t2, standarize(y-gam.predict(gam.regressors[:,0][...,None],
#                                                 reg_params[indx_smthr:indx_smthr+2+reg_params[indx_smthr+1]])),'g.')
# indx_smthr = 2+reg_params[indx_smthr+1]
# plt.plot(t2, standarize(gam.predict(gam.regressors[:,1][...,None],reg_params[indx_smthr:indx_smthr+2+reg_params[indx_smthr+1]])),
#          'r-', label='AdditiveModel')
# plt.plot(t2, standarize(f2(t2)),'b-',label='true', linewidth=2)
# plt.legend()

plt.show()
a = 1

# plt.figure()
# plt.plot(t1,y-standarize(f2(t2))-standarize(f3(x3))-smoother_results['mean'], 'k.')
# plt.plot(t1, standardize(gam.__predict__()), 'r-', label='AdditiveModel')
# plt.plot(t1, standarize(f1(t1)),label='true', linewidth=2)


import scipy.stats
import numpy as np

class UniformDist:
    def __init__(self, xmax=1., xmin=None):
        self.xmax = xmax
        self.xmin = - xmax if xmin is None else xmin
        self.prob = 1 / (self.xmax - self.xmin)

    def __call__(self, *args, **kwargs):
        return self.prob

    def __str__(self):
        return 'UniformDist(max={}, min={})'.format(self.xmax, self.xmin)

class DistBase:
    def __init__(self, dist, params):
        self.dist = dist
        self.params = params

    def __call__(self, x):
        """
        :x: input
        :return: P(x)
        """
        return np.exp(np.sum(self.dist.logpdf(x, **self.params)))

    def sample(self, size=10):
        return self.dist.rvs(size=size, **self.params)

    def __str__(self):
        return self.__class__.__name__ + '(' + ', '.join(['{}={}'.format(key, value)
                                                        for key, value in self.params.items()]) + ')'

class GaussianDist(DistBase):
    def __init__(self, loc=0, scale=0.1):
        """
        :param loc: location of gaussian distribution
        :param scale: var == scale ** 2
        """
        params = dict(loc=loc, scale=scale)
        dist = scipy.stats.norm
        super().__init__(dist=dist, params=params)

class BetaDist(DistBase):
    def __init__(self, a=0.5, b=0.5, loc=0, scale=1):
        params = dict(a=a, b=b, loc=loc, scale=scale)
        dist = scipy.stats.beta
        super().__init__(dist=dist, params=params)

class GammaDist(DistBase):
    def __init__(self, a=2, loc=0, scale=1):
        params = dict(a=a, loc=loc, scale=scale)
        dist = scipy.stats.gamma
        super().__init__(dist=dist, params=params)

if __name__ == '__main__':
    import matplotlib.pyplot as plt
    import os
    dists = (GaussianDist, BetaDist, GammaDist)
    for dist in dists:
        distribution = dist()
        samples = distribution.sample(size=100)
        plt.hist(samples)
        plt.title(distribution)
        path = '/' + os.path.join(*os.path.abspath(__file__).split('/')[:-3], 'results',
                                  '{}.png'.format(dist.__name__))
        plt.savefig(path)
        plt.cla()


''' Define the Layers '''
import torch.nn as nn
import torch.nn.functional as F
from Attention import MultiHeadAttention

class PositionwiseFeedForward(nn.Module):
    ''' A two-feed-forward-layer module '''

    def __init__(self, d_in, d_hid, dropout=0.1):
        super().__init__()
        self.w_1 = nn.Conv1d(d_in, d_hid, 1) # position-wise
        self.w_2 = nn.Conv1d(d_hid, d_in, 1) # position-wise
        self.layer_norm = nn.LayerNorm(d_in)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        residual = x
        output = x.transpose(1, 2)
        output = self.w_2(F.relu(self.w_1(output)))
        output = output.transpose(1, 2)
        output = self.dropout(output)
        output = self.layer_norm(output + residual)
        return output

class EncoderLayer(nn.Module):
    ''' Compose with two layers '''

    def __init__(self, d_model, d_inner, n_head, d_k, d_v, dropout=0.1):
        super(EncoderLayer, self).__init__()
        self.slf_attn = MultiHeadAttention(
            n_head, d_model, d_k, d_v, dropout=dropout)
        self.pos_ffn = PositionwiseFeedForward(d_model, d_inner, dropout=dropout)

    def forward(self, enc_input, non_pad_mask=None, slf_attn_mask=None):
        enc_output, enc_slf_attn = self.slf_attn(
            enc_input, enc_input, enc_input, mask=slf_attn_mask)
        enc_output *= non_pad_mask

        enc_output = self.pos_ffn(enc_output)
        enc_output *= non_pad_mask

        return enc_output, enc_slf_attn

class DecoderLayer(nn.Module):

    def __init__(self, d_o, d_inner, n_head, d_k, d_v, dropout=0.1):
        super(DecoderLayer, self).__init__()
        self.enc_attn = MultiHeadAttention(n_head, d_o, d_k, d_v, dropout=dropout)
        self.pos_ffn = PositionwiseFeedForward(d_o, d_inner, dropout=dropout)

    def forward(self, dec_input, enc_output):

        dec_output, dec_enc_attn = self.enc_attn(dec_input, enc_output, enc_output)
        dec_output = self.pos_ffn(dec_output)

        return dec_output, dec_enc_attn


#!/user/bin/env python3
# Note that all the tests in this module require dataset (either network access or cached)
import os
import glob
import shutil
import torchtext.data as data
from torchtext.datasets import AG_NEWS
import torch
from ..common.torchtext_test_case import TorchtextTestCase

def conditional_remove(f):
    for path in glob.glob(f):
        if os.path.isfile(path):
            os.remove(path)
        elif os.path.isdir(path):
            shutil.rmtree(path)

class TestDataset(TorchtextTestCase):
    def test_wikitext2_legacy(self):
        from torchtext.datasets import WikiText2
        # smoke test to ensure wikitext2 works properly

        # NOTE
        # test_wikitext2 and test_wikitext2_legacy have some cache incompatibility.
        # Keeping one's cache make the other fail. So we need to clean up the cache dir
        cachedir = os.path.join(self.project_root, ".data", "wikitext-2")
        conditional_remove(cachedir)

        ds = WikiText2
        TEXT = data.Field(lower=True, batch_first=True)
        train, valid, test = ds.splits(TEXT)
        TEXT.build_vocab(train)
        train_iter, valid_iter, test_iter = data.BPTTIterator.splits(
            (train, valid, test), batch_size=3, bptt_len=30)

        train_iter, valid_iter, test_iter = ds.iters(batch_size=4,
                                                     bptt_len=30)

        conditional_remove(cachedir)

    def test_wikitext2(self):
        from torchtext.experimental.datasets import WikiText2
        # smoke test to ensure wikitext2 works properly

        # NOTE
        # test_wikitext2 and test_wikitext2_legacy have some cache incompatibility.
        # Keeping one's cache make the other fail. So we need to clean up the cache dir
        cachedir = os.path.join(self.project_root, ".data", "wikitext-2")
        conditional_remove(cachedir)
        cachefile = os.path.join(self.project_root, ".data", "wikitext-2-v1.zip")
        conditional_remove(cachefile)

        train_dataset, test_dataset, valid_dataset = WikiText2()
        self.assertEqual(len(train_dataset), 2049990)
        self.assertEqual(len(test_dataset), 241859)
        self.assertEqual(len(valid_dataset), 214417)

        vocab = train_dataset.get_vocab()
        tokens_ids = [vocab[token] for token in 'the player characters rest'.split()]
        self.assertEqual(tokens_ids, [2, 286, 503, 700])

        conditional_remove(cachedir)
        conditional_remove(cachefile)

    def test_penntreebank_legacy(self):
        from torchtext.datasets import PennTreebank
        # smoke test to ensure penn treebank works properly
        TEXT = data.Field(lower=True, batch_first=True)
        ds = PennTreebank
        train, valid, test = ds.splits(TEXT)
        TEXT.build_vocab(train)
        train_iter, valid_iter, test_iter = data.BPTTIterator.splits(
            (train, valid, test), batch_size=3, bptt_len=30)

        train_iter, valid_iter, test_iter = ds.iters(batch_size=4,
                                                     bptt_len=30)

    def test_penntreebank(self):
        from torchtext.experimental.datasets import PennTreebank
        # smoke test to ensure penn treebank works properly
        train_dataset, test_dataset, valid_dataset = PennTreebank()
        self.assertEqual(len(train_dataset), 924412)
        self.assertEqual(len(test_dataset), 82114)
        self.assertEqual(len(valid_dataset), 73339)

        vocab = train_dataset.get_vocab()
        tokens_ids = [vocab[token] for token in 'the player characters rest'.split()]
        self.assertEqual(tokens_ids, [2, 2550, 3344, 1125])

    def test_text_classification(self):
        # smoke test to ensure ag_news dataset works properly

        datadir = os.path.join(self.project_root, ".data")
        if not os.path.exists(datadir):
            os.makedirs(datadir)
        ag_news_train, ag_news_test = AG_NEWS(root=datadir, ngrams=3)
        self.assertEqual(len(ag_news_train), 120000)
        self.assertEqual(len(ag_news_test), 7600)
        self.assertEqual(ag_news_train[-1][1][:10],
                         torch.tensor([3525, 319, 4053, 34, 5407, 3607, 70, 6798, 10599, 4053]).long())
        self.assertEqual(ag_news_test[-1][1][:10],
                         torch.tensor([2351, 758, 96, 38581, 2351, 220, 5, 396, 3, 14786]).long())

    def test_imdb(self):
        from torchtext.experimental.datasets import IMDB
        from torchtext.vocab import Vocab
        # smoke test to ensure imdb works properly
        train_dataset, test_dataset = IMDB()
        self.assertEqual(len(train_dataset), 25000)
        self.assertEqual(len(test_dataset), 25000)
        self.assertEqual(train_dataset[0][1][:10],
                         torch.tensor([13, 1568, 13, 246, 35468, 43, 64, 398, 1135, 92]).long())
        self.assertEqual(train_dataset[-1][1][:10],
                         torch.tensor([2, 71, 4555, 194, 3328, 15144, 42, 227, 148, 8]).long())
        self.assertEqual(test_dataset[0][1][:10],
                         torch.tensor([13, 125, 1051, 5, 246, 1652, 8, 277, 66, 20]).long())
        self.assertEqual(test_dataset[-1][1][:10],
                         torch.tensor([13, 1035, 14, 21, 28, 2, 1051, 1275, 1008, 3]).long())

        # Test API with a vocab input object
        old_vocab = train_dataset.get_vocab()
        new_vocab = Vocab(counter=old_vocab.freqs, max_size=2500)
        new_train_data, new_test_data = IMDB(vocab=new_vocab)

    def test_multi30k(self):
        from torchtext.experimental.datasets import Multi30k
        # smoke test to ensure multi30k works properly
        train_dataset, valid_dataset, test_dataset = Multi30k()
        self.assertEqual(len(train_dataset), 29000)
        self.assertEqual(len(valid_dataset), 1000)
        self.assertEqual(len(test_dataset), 1014)

        de_vocab, en_vocab = train_dataset.get_vocab()
        de_tokens_ids = [
            de_vocab[token] for token in
            'Zwei Männer verpacken Donuts in Kunststofffolie'.split()
        ]
        self.assertEqual(de_tokens_ids, [19, 29, 18703, 4448, 5, 6240])

        en_tokens_ids = [
            en_vocab[token] for token in
            'Two young White males are outside near many bushes'.split()
        ]
        self.assertEqual(en_tokens_ids,
                         [17, 23, 1167, 806, 15, 55, 82, 334, 1337])

        datafile = os.path.join(self.project_root, ".data", "train*")
        conditional_remove(datafile)
        datafile = os.path.join(self.project_root, ".data", "val*")
        conditional_remove(datafile)
        datafile = os.path.join(self.project_root, ".data", "test*")
        conditional_remove(datafile)
        datafile = os.path.join(self.project_root, ".data",
                                "multi30k_task*.tar.gz")
        conditional_remove(datafile)

    def test_udpos_sequence_tagging(self):
        from torchtext.experimental.datasets import UDPOS

        # smoke test to ensure imdb works properly
        train_dataset, valid_dataset, test_dataset = UDPOS()
        self.assertEqual(len(train_dataset), 12543)
        self.assertEqual(len(valid_dataset), 2002)
        self.assertEqual(len(test_dataset), 2077)
        self.assertEqual(train_dataset[0][0][:10],
                         torch.tensor([262, 16, 5728, 45, 289, 701, 1160, 4436, 10660, 585]).long())
        self.assertEqual(train_dataset[0][1][:10],
                         torch.tensor([8, 3, 8, 3, 9, 2, 4, 8, 8, 8]).long())
        self.assertEqual(train_dataset[0][2][:10],
                         torch.tensor([5, 34, 5, 27, 7, 11, 14, 5, 5, 5]).long())
        self.assertEqual(train_dataset[-1][0][:10],
                         torch.tensor([9, 32, 169, 436, 59, 192, 30, 6, 117, 17]).long())
        self.assertEqual(train_dataset[-1][1][:10],
                         torch.tensor([5, 10, 11, 4, 11, 11, 3, 12, 11, 4]).long())
        self.assertEqual(train_dataset[-1][2][:10],
                         torch.tensor([6, 20, 8, 10, 8, 8, 24, 13, 8, 15]).long())

        self.assertEqual(valid_dataset[0][0][:10],
                         torch.tensor([746, 3, 10633, 656, 25, 1334, 45]).long())
        self.assertEqual(valid_dataset[0][1][:10],
                         torch.tensor([6, 7, 8, 4, 7, 2, 3]).long())
        self.assertEqual(valid_dataset[0][2][:10],
                         torch.tensor([3, 4, 5, 16, 4, 2, 27]).long())
        self.assertEqual(valid_dataset[-1][0][:10],
                         torch.tensor([354, 4, 31, 17, 141, 421, 148, 6, 7, 78]).long())
        self.assertEqual(valid_dataset[-1][1][:10],
                         torch.tensor([11, 3, 5, 4, 9, 2, 2, 12, 7, 11]).long())
        self.assertEqual(valid_dataset[-1][2][:10],
                         torch.tensor([8, 12, 6, 15, 7, 2, 2, 13, 4, 8]).long())

        self.assertEqual(test_dataset[0][0][:10],
                         torch.tensor([210, 54, 3115, 0, 12229, 0, 33]).long())
        self.assertEqual(test_dataset[0][1][:10],
                         torch.tensor([5, 15, 8, 4, 6, 8, 3]).long())
        self.assertEqual(test_dataset[0][2][:10],
                         torch.tensor([30, 3, 5, 14, 3, 5, 9]).long())
        self.assertEqual(test_dataset[-1][0][:10],
                         torch.tensor([116, 0, 6, 11, 412, 10, 0, 4, 0, 6]).long())
        self.assertEqual(test_dataset[-1][1][:10],
                         torch.tensor([5, 4, 12, 10, 9, 15, 4, 3, 4, 12]).long())
        self.assertEqual(test_dataset[-1][2][:10],
                         torch.tensor([6, 16, 13, 16, 7, 3, 19, 12, 19, 13]).long())

        # Assert vocabs
        self.assertEqual(len(train_dataset.get_vocabs()), 3)
        self.assertEqual(len(train_dataset.get_vocabs()[0]), 19674)
        self.assertEqual(len(train_dataset.get_vocabs()[1]), 19)
        self.assertEqual(len(train_dataset.get_vocabs()[2]), 52)

        # Assert token ids
        word_vocab = train_dataset.get_vocabs()[0]
        tokens_ids = [word_vocab[token] for token in 'Two of them were being run'.split()]
        self.assertEqual(tokens_ids, [1206, 8, 69, 60, 157, 452])

    def test_conll_sequence_tagging(self):
        from torchtext.experimental.datasets import CoNLL2000Chunking

        # smoke test to ensure imdb works properly
        train_dataset, test_dataset = CoNLL2000Chunking()
        self.assertEqual(len(train_dataset), 8936)
        self.assertEqual(len(test_dataset), 2012)
        self.assertEqual(train_dataset[0][0][:10],
                         torch.tensor([11556, 9, 3, 1775, 17, 1164, 177, 6, 212, 317]).long())
        self.assertEqual(train_dataset[0][1][:10],
                         torch.tensor([2, 3, 5, 2, 17, 12, 16, 15, 13, 5]).long())
        self.assertEqual(train_dataset[0][2][:10],
                         torch.tensor([3, 6, 3, 2, 5, 7, 7, 7, 7, 3]).long())
        self.assertEqual(train_dataset[-1][0][:10],
                         torch.tensor([85, 17, 59, 6473, 288, 115, 72, 5, 2294, 2502]).long())
        self.assertEqual(train_dataset[-1][1][:10],
                         torch.tensor([18, 17, 12, 19, 10, 6, 3, 3, 4, 4]).long())
        self.assertEqual(train_dataset[-1][2][:10],
                         torch.tensor([3, 5, 7, 7, 3, 2, 6, 6, 3, 2]).long())

        self.assertEqual(test_dataset[0][0][:10],
                         torch.tensor([0, 294, 73, 10, 13582, 194, 18, 24, 2414, 7]).long())
        self.assertEqual(test_dataset[0][1][:10],
                         torch.tensor([4, 4, 4, 23, 4, 2, 11, 18, 11, 5]).long())
        self.assertEqual(test_dataset[0][2][:10],
                         torch.tensor([3, 2, 2, 3, 2, 2, 5, 3, 5, 3]).long())
        self.assertEqual(test_dataset[-1][0][:10],
                         torch.tensor([51, 456, 560, 2, 11, 465, 2, 1413, 36, 60]).long())
        self.assertEqual(test_dataset[-1][1][:10],
                         torch.tensor([3, 4, 4, 8, 3, 2, 8, 4, 17, 16]).long())
        self.assertEqual(test_dataset[-1][2][:10],
                         torch.tensor([6, 3, 2, 4, 6, 3, 4, 3, 5, 7]).long())

        # Assert vocabs
        self.assertEqual(len(train_dataset.get_vocabs()), 3)
        self.assertEqual(len(train_dataset.get_vocabs()[0]), 19124)
        self.assertEqual(len(train_dataset.get_vocabs()[1]), 46)
        self.assertEqual(len(train_dataset.get_vocabs()[2]), 24)

        # Assert token ids
        word_vocab = train_dataset.get_vocabs()[0]
        tokens_ids = [word_vocab[token] for token in 'Two of them were being run'.split()]
        self.assertEqual(tokens_ids, [970, 5, 135, 43, 214, 690])

    def test_squad1(self):
        from torchtext.experimental.datasets import SQuAD1
        from torchtext.vocab import Vocab
        # smoke test to ensure imdb works properly
        train_dataset, dev_dataset = SQuAD1()
        self.assertEqual(len(train_dataset), 87599)
        self.assertEqual(len(dev_dataset), 10570)
        self.assertEqual(train_dataset[100]['question'],
                         torch.tensor([7, 24, 86, 52, 2, 373, 887, 18, 12797, 11090, 1356, 2, 1788, 3273, 16]).long())
        self.assertEqual(train_dataset[100]['ans_pos'][0],
                         torch.tensor([72, 72]).long())
        self.assertEqual(dev_dataset[100]['question'],
                         torch.tensor([42, 27, 669, 7438, 17, 2, 1950, 3273, 17252, 389, 16]).long())
        self.assertEqual(dev_dataset[100]['ans_pos'][0],
                         torch.tensor([45, 48]).long())

        # Test API with a vocab input object
        old_vocab = train_dataset.get_vocab()
        new_vocab = Vocab(counter=old_vocab.freqs, max_size=2500)
        new_train_data, new_test_data = SQuAD1(vocab=new_vocab)

    def test_squad2(self):
        from torchtext.experimental.datasets import SQuAD2
        from torchtext.vocab import Vocab
        # smoke test to ensure imdb works properly
        train_dataset, dev_dataset = SQuAD2()
        self.assertEqual(len(train_dataset), 130319)
        self.assertEqual(len(dev_dataset), 11873)
        self.assertEqual(train_dataset[200]['question'],
                         torch.tensor([84, 50, 1421, 12, 5439, 4569, 17, 30, 2, 15202, 4754, 1421, 16]).long())
        self.assertEqual(train_dataset[200]['ans_pos'][0],
                         torch.tensor([9, 9]).long())
        self.assertEqual(dev_dataset[200]['question'],
                         torch.tensor([41, 29, 2, 66, 17016, 30, 0, 1955, 16]).long())
        self.assertEqual(dev_dataset[200]['ans_pos'][0],
                         torch.tensor([40, 46]).long())

        # Test API with a vocab input object
        old_vocab = train_dataset.get_vocab()
        new_vocab = Vocab(counter=old_vocab.freqs, max_size=2500)
        new_train_data, new_test_data = SQuAD2(vocab=new_vocab)