import io
import os
import torch
from torch import nn
from tqdm import tqdm
from torch.utils.data import Dataset, DataLoader
from transformers import (set_seed,
                          TrainingArguments,
                          Trainer,
                          GPT2Config,
                          GPT2Tokenizer,
                          AdamW,
                          get_linear_schedule_with_warmup,
                          GPT2ForSequenceClassification,
                          PreTrainedTokenizerFast)
from sklearn.metrics import classification_report, accuracy_score

from music_midi_dataset import MidiMusicDataset

def start():
    set_seed(123)
    epochs = 4
    batch_size = 8
    max_length = 60
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model_name_or_path = 'gpt2'
    labels_ids = {'cheerful': 0, 'tense': 1}
    n_labels = len(labels_ids)

    train_midi_data_dir = '../data/music_midi/emotion_midi_text/train'
    test_midi_data_dir = '../data/music_midi/emotion_midi_text/test'
    path_tokenizer = 'tokenizer.json'
    tokenizer = PreTrainedTokenizerFast(tokenizer_file=path_tokenizer)
    tokenizer.add_special_tokens({'pad_token': '[PAD]'})
    classes = ['cheerful', 'tense']
    pad_length = 128
    learning_rate = 0.001

    print('Loading configuraiton...')
    model_config = GPT2Config.from_pretrained(pretrained_model_name_or_path=model_name_or_path, num_labels=n_labels)
    print('Loading model...')
    model = GPT2ForSequenceClassification.from_pretrained(pretrained_model_name_or_path=model_name_or_path,
                                                          config=model_config)
    model.resize_token_embeddings(len(tokenizer))

    # fix model padding token id
    model.config.pad_token_id = model.config.eos_token_id

    # Load model to defined device.
    model.to(device)

    training_data = MidiMusicDataset(midi_data_dir=train_midi_data_dir,
                                     classes=classes,
                                     tokenizer=tokenizer,
                                     block_size=pad_length)
    test_data = MidiMusicDataset(midi_data_dir=test_midi_data_dir,
                                 classes=classes,
                                 tokenizer=tokenizer,
                                 block_size=pad_length)
    train_dataloader = DataLoader(training_data, batch_size=batch_size, shuffle=True)
    valid_dataloader = DataLoader(test_data, batch_size=batch_size, shuffle=True)

    optimizer = AdamW(model.parameters(),
                      lr=2e-5,  # default is 5e-5, our notebook had 2e-5
                      eps=1e-8  # default is 1e-8.
                      )

    # Total number of training steps is number of batches * number of epochs.
    # `train_dataloader` contains batched data so `len(train_dataloader)` gives
    # us the number of batches.
    total_steps = len(train_dataloader) * epochs

    # Create the learning rate scheduler.
    scheduler = get_linear_schedule_with_warmup(optimizer,
                                                num_warmup_steps=0,  # Default value in run_glue.py
                                                num_training_steps=total_steps)

    # Store the average loss after each epoch so we can plot them.
    all_loss = {'train_loss': [], 'val_loss': []}
    all_acc = {'train_acc': [], 'val_acc': []}

    for epoch in range(epochs):
        print(f'Epoch {epoch}')
        print('Training on batches...')
        # Perform one full pass over the training set.
        train_labels, train_predict, train_loss = train(train_dataloader, model, optimizer, scheduler, device)
        train_acc = accuracy_score(train_labels, train_predict)

        # Get prediction form model on validation data.
        print('Validation on batches...')
        valid_labels, valid_predict, val_loss = validation(valid_dataloader, model, device)
        val_acc = accuracy_score(valid_labels, valid_predict)

        # Print loss and accuracy values to see how training evolves.
        print("  train_loss: %.5f - val_loss: %.5f - train_acc: %.5f - valid_acc: %.5f" % (
        train_loss, val_loss, train_acc, val_acc))
        print()

        # Store the loss value for plotting the learning curve.
        all_loss['train_loss'].append(train_loss)
        all_loss['val_loss'].append(val_loss)
        all_acc['train_acc'].append(train_acc)
        all_acc['val_acc'].append(val_acc)

def train(dataloader, model, optimizer_, scheduler_, device_):
    predictions_labels = []
    true_labels = []

    total_loss = 0

    model.train()

    for batch in tqdm(dataloader):
        # print(batch)
        true_labels += batch['labels'].numpy().flatten().tolist()
        batch = {k: v.type(torch.long).to(device_) for k, v in batch.items()}
        model.zero_grad()
        outputs = model(**batch)
        loss, logits = outputs[:2]
        total_loss += loss.item()
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        optimizer_.step()
        scheduler_.step()
        logits = logits.detach().cpu().numpy()
        predictions_labels += logits.argmax(axis=-1).flatten().tolist()

    avg_epoch_loss = total_loss / len(dataloader)
    return true_labels, predictions_labels, avg_epoch_loss

def validation(dataloader, model, device_):
    predictions_labels = []
    true_labels = []
    total_loss = 0

    model.eval()

    for batch in tqdm(dataloader):
        true_labels += batch['labels'].numpy().flatten().tolist()
        batch = {k: v.type(torch.long).to(device_) for k, v in batch.items()}

        with torch.no_grad():
            outputs = model(**batch)
            loss, logits = outputs[:2]
            logits = logits.detach().cpu().numpy()
            total_loss += loss.item()
            predict_content = logits.argmax(axis=-1).flatten().tolist()
            predictions_labels += predict_content

    avg_epoch_loss = total_loss / len(dataloader)
    return true_labels, predictions_labels, avg_epoch_loss

if __name__ == '__main__':
    start()


# import urllib library
from urllib.request import urlopen

import json
import random

score = 0

import string

NUMBER_OF_ATTEMPTS = 2
ENTER_ANSWER = 'Hit %s for your answer\n'
TRY_AGAIN = 'Incorrect!!! Try again.'
CORRECT = 'Correct'
NO_MORE_ATTEMPTS = 'Incorrect!!! You ran out of your attempts'

def question(message, options, correct, attempts=NUMBER_OF_ATTEMPTS):
    print (message)
    while attempts > 0:
        response = input(ENTER_ANSWER % ', '.join(options))
        if response == correct:
            print (CORRECT)
            return True

        else:
            attempts -= 1
            print (TRY_AGAIN)

    print (NO_MORE_ATTEMPTS)
    return False

urlQuestion = "https://d-wwts.ext.hp.com/qna/questions.json"
urlAnswers = "https://d-wwts.ext.hp.com/qna/answers.json"

responseQuestionsAndAnswers = urlopen(urlQuestion)
responseQandA_json = json.loads(responseQuestionsAndAnswers.read())

responseCurrectAnswers = urlopen(urlAnswers)
responseUrlCurrectAnswers_json = json.loads(responseCurrectAnswers.read())

random_item = random.choice(responseQandA_json)

questionId = random_item['id'];
filterAnswer = [f for f in responseUrlCurrectAnswers_json if f["id"] == questionId]
ans = filterAnswer[0]['a'];
question2 = question(random_item['q'], random_item['a'], ans)


# -*- coding: utf-8 -*-
"""
Created on Fri Mar  1 20:30:54 2019

@author: Sunanda
"""
import argparse, re, decimal

parser = argparse.ArgumentParser(
        description='''The purpose of this application is to check
                        the COMP 472/6721 Winter 2019 Projects'''
        )

parser.add_argument('-c',
                    required = False,
                    action='store_true',
                    help="optional argument to check the format")

parser.add_argument( '-m',
                    required = False,
                    action='store_true',
                    help="check the trace files for minimax implementation")

parser.add_argument('-a',
                    required = False,
                    action='store_true',
                    help="check the trace files for alpha beta implementation")

parser.add_argument("-f", dest="filename", required=True,
                    help="output file from demos", metavar="FILE",
                    type=argparse.FileType('r'))

args = parser.parse_args()

content = args.filename.read().strip()

groups = re.split('(?:\r\n\r\n|\n\n)',content)

if args.m or args.a :
    print("\n\x1b[1;31;mACESS DENIED\x1b[0m ")
else:
    print("Checking format.. ")
    error = 0
    traceNo = 0
    for i,bunch in enumerate(groups,1):
        if bunch.startswith('\r') or bunch.startswith('\n'):
            error = 5
            break
        rows = bunch.split()
        if i % 2 == 1:
            traceNo += 1
            if len(rows) > 2:
                error = 1
                break
            elif len(rows) < 2:
                error = 2
                break
        for val in rows:
            try:
                float(val)
            except:
                error = 3
                break
            if decimal.Decimal(val).as_tuple().exponent < -1:
                error = 4
                break
        if error != 0 :
            break

    # print("done")
    if error == 1:
        print("\x1b[1;31;mERROR:\x1b[0m Too many values in the beginning (Trace No. "+ str(traceNo) +")")
    elif error == 2:
        print("\x1b[1;31;mERROR:\x1b[0m Not enough values in the beginning (Trace No. "+ str(traceNo) +")")
    elif error == 3:
        print("\x1b[1;31;mERROR:\x1b[0m Number expected (Trace No. "+ str(traceNo) +")")
    elif error == 4:
        print("\x1b[1;31;mERROR:\x1b[0m Upto one decimal point expected (Trace No. "+ str(traceNo) +")")
    elif error == 5:
        print("\x1b[1;31;mERROR:\x1b[0m Too many new lines (Trace No. "+ str(traceNo) +")")
    else:
        print("\x1b[1;32;mCORRECT FORMAT\x1b[0m")


import argparse
import numpy as np
import os
import torch
import torch.nn as nn
import datetime
import time
import matplotlib.pyplot as plt
from torchinfo import summary
import yaml
import json
import sys

sys.path.append("..")
from lib.utils import (
    MaskedMAELoss,
    print_log,
    seed_everything,
    set_cpu_num,
    CustomJSONEncoder,
)
from lib.metrics import MAE_RMSE, RMSE_MAE_MAPE
from lib.data_prepare import get_dataloaders_from_tvt
from models import model_select

@torch.no_grad()
def eval_model(model, valset_loader, criterion):
    model.eval()
    batch_loss_list = []
    for x_batch, y_batch in valset_loader:
        x_batch = x_batch.to(DEVICE)
        y_batch = y_batch.to(DEVICE)

        out_batch = model(x_batch)
        # out_batch = SCALER.inverse_transform(out_batch)
        loss = criterion(out_batch, y_batch)
        batch_loss_list.append(loss.item())

    return np.mean(batch_loss_list)

@torch.no_grad()
def predict(model, loader):
    model.eval()
    y = []
    out = []

    for x_batch, y_batch in loader:
        x_batch = x_batch.to(DEVICE)
        y_batch = y_batch.to(DEVICE)

        out_batch = model(x_batch)
        # out_batch = SCALER.inverse_transform(out_batch)

        out_batch = out_batch.cpu().numpy()
        y_batch = y_batch.cpu().numpy()
        out.append(out_batch)
        y.append(y_batch)

    out = np.vstack(out).squeeze()  # (samples, out_steps, num_nodes)
    y = np.vstack(y).squeeze()

    return y, out

def train_one_epoch(
    model, trainset_loader, optimizer, scheduler, criterion, clip_grad, log=None
):
    model.train()
    batch_loss_list = []
    for x_batch, y_batch in trainset_loader:
        x_batch = x_batch.to(DEVICE)
        y_batch = y_batch.to(DEVICE)

        out_batch = model(x_batch)
        # out_batch = SCALER.inverse_transform(out_batch)

        loss = criterion(out_batch, y_batch)
        batch_loss_list.append(loss.item())

        optimizer.zero_grad()
        loss.backward()
        if clip_grad:
            torch.nn.utils.clip_grad_norm_(model.parameters(), clip_grad)
        optimizer.step()

    epoch_loss = np.mean(batch_loss_list)
    scheduler.step()

    return epoch_loss

def train(
    model,
    trainset_loader,
    valset_loader,
    optimizer,
    scheduler,
    criterion,
    clip_grad=0,
    max_epochs=200,
    early_stop=10,
    compile_model=False,
    verbose=1,
    plot=False,
    log=None,
    save=None,
):
    if torch.__version__ >= "2.0.0" and compile_model:
        model = torch.compile(model)
    model = model.to(DEVICE)

    wait = 0
    min_val_loss = np.inf

    train_loss_list = []
    val_loss_list = []

    for epoch in range(max_epochs):
        train_loss = train_one_epoch(
            model, trainset_loader, optimizer, scheduler, criterion, clip_grad, log=log
        )
        train_loss_list.append(train_loss)

        val_loss = eval_model(model, valset_loader, criterion)
        val_loss_list.append(val_loss)

        if (epoch + 1) % verbose == 0:
            print_log(
                datetime.datetime.now(),
                "Epoch",
                epoch + 1,
                " \tTrain Loss = %.5f" % train_loss,
                "Val Loss = %.5f" % val_loss,
                log=log,
            )

        if val_loss < min_val_loss:
            wait = 0
            min_val_loss = val_loss
            best_epoch = epoch
            best_state_dict = model.state_dict()
        else:
            wait += 1
            if wait >= early_stop:
                break

    model.load_state_dict(best_state_dict)
    train_mae, train_rmse = MAE_RMSE(*predict(model, trainset_loader))
    val_mae, val_rmse = MAE_RMSE(*predict(model, valset_loader))

    out_str = f"Early stopping at epoch: {epoch+1}\n"
    out_str += f"Best at epoch {best_epoch+1}:\n"
    out_str += "Train Loss = %.5f\n" % train_loss_list[best_epoch]
    out_str += "Train MAE = %.5f, RMSE = %.5f\n" % (
        train_mae,
        train_rmse,
    )
    out_str += "Val Loss = %.5f\n" % val_loss_list[best_epoch]
    out_str += "Val MAE = %.5f, RMSE = %.5f" % (
        val_mae,
        val_rmse,
    )
    print_log(out_str, log=log)

    if plot:
        plt.plot(range(0, epoch + 1), train_loss_list, "-", label="Train Loss")
        plt.plot(range(0, epoch + 1), val_loss_list, "-", label="Val Loss")
        plt.title("Epoch-Loss")
        plt.xlabel("Epoch")
        plt.ylabel("Loss")
        plt.legend()
        plt.show()

    if save:
        torch.save(best_state_dict, save)
    return model

@torch.no_grad()
def test_model(model, testset_loader, log=None):
    model.eval()
    print_log("--------- Test ---------", log=log)

    start = time.time()
    y_true, y_pred = predict(model, testset_loader)
    end = time.time()

    (
        mae_all,
        rmse_all,
    ) = MAE_RMSE(y_true, y_pred)
    out_str = "Test MAE = %.5f, RMSE = %.5f\n" % (
        mae_all,
        rmse_all,
    )

    # (rmse_all, mae_all, mape_all) = RMSE_MAE_MAPE(y_true, y_pred)
    # out_str = "Test MAE = %.5f, RMSE = %.5f, MAPE = %.5f\n" % (
    #     rmse_all,
    #     mae_all,
    #     mape_all,
    # )

    print_log(out_str, log=log, end="")
    print_log("Inference time: %.2f s" % (end - start), log=log)

if __name__ == "__main__":
    # -------------------------- set running environment ------------------------- #

    parser = argparse.ArgumentParser()
    parser.add_argument("-n", type=int, default="500")
    parser.add_argument("-p", type=int, default="20")
    parser.add_argument("-m", "--model", type=str, default="gridgcn")
    parser.add_argument("-g", "--gpu_num", type=int, default=0)
    parser.add_argument("-c", "--compile", action="store_true")
    parser.add_argument("--seed", type=int, default=233)
    parser.add_argument("--cpus", type=int, default=1)
    args = parser.parse_args()

    seed_everything(args.seed)
    set_cpu_num(args.cpus)

    GPU_ID = args.gpu_num
    os.environ["CUDA_VISIBLE_DEVICES"] = f"{GPU_ID}"
    DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    n = args.n
    p = args.p
    dataset = f"n_{n}_p_{p}"
    data_path = f"../data/{dataset}"
    model_name = args.model.upper()

    model_class = model_select(model_name)
    model_name = model_class.__name__

    with open(f"../configs/{model_name}.yaml", "r") as f:
        cfg = yaml.safe_load(f)
    cfg = cfg[dataset]

    # -------------------------------- load model -------------------------------- #

    # cfg.get(key, default_value=None): no need to write in the config if not used
    # cfg[key]: must be assigned in the config, else KeyError
    if cfg.get("pass_device"):
        cfg["model_args"]["device"] = DEVICE

    model = model_class(**cfg["model_args"])

    # ------------------------------- make log file ------------------------------ #

    now = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
    log_path = f"../logs/{model_name}"
    if not os.path.exists(log_path):
        os.makedirs(log_path)
    log = os.path.join(log_path, f"{model_name}-{dataset}-{now}.log")
    log = open(log, "a")
    log.seek(0)
    log.truncate()

    # ------------------------------- load dataset ------------------------------- #

    print_log(dataset, log=log)
    (
        trainset_loader,
        valset_loader,
        testset_loader,
    ) = get_dataloaders_from_tvt(
        n,
        p,
        batch_size=cfg.get("batch_size", 32),
        log=log,
    )
    print_log(log=log)

    # --------------------------- set model saving path -------------------------- #

    save_path = f"../saved_models/{model_name}"
    if not os.path.exists(save_path):
        os.makedirs(save_path)
    save = os.path.join(save_path, f"{model_name}-{dataset}-{now}.pt")

    # ---------------------- set loss, optimizer, scheduler ---------------------- #

    # criterion = nn.SmoothL1Loss()
    # criterion = MaskedMAELoss()
    criterion = nn.MSELoss()

    optimizer = torch.optim.Adam(
        model.parameters(),
        lr=cfg["lr"],
        weight_decay=cfg.get("weight_decay", 0),
        eps=cfg.get("eps", 1e-8),
    )
    scheduler = torch.optim.lr_scheduler.MultiStepLR(
        optimizer,
        milestones=cfg.get("milestones", []),
        gamma=cfg.get("lr_decay_rate", 0.1),
        verbose=False,
    )

    # --------------------------- print model structure -------------------------- #

    print_log("---------", model_name, "---------", log=log)
    print_log(
        json.dumps(cfg, ensure_ascii=False, indent=4, cls=CustomJSONEncoder), log=log
    )
    print_log(
        summary(
            model,
            [
                cfg["batch_size"],
                cfg["num_grids_width"],
                cfg["num_grids_height"],
                cfg["model_args"]["input_dim"],
            ],
            verbose=0,
        ),
        log=log,
    )
    print_log(log=log)

    # --------------------------- train and test model --------------------------- #

    print_log(f"Loss: {criterion._get_name()}", log=log)
    print_log(log=log)

    model = train(
        model,
        trainset_loader,
        valset_loader,
        optimizer,
        scheduler,
        criterion,
        clip_grad=cfg.get("clip_grad"),
        max_epochs=cfg.get("max_epochs", 200),
        early_stop=cfg.get("early_stop", 10),
        compile_model=args.compile,
        verbose=1,
        log=log,
        save=save,
    )

    test_model(model, testset_loader, log=log)

    log.close()


from PyQt5.QtWidgets import QTableView, QPushButton, QHeaderView, QDialog, QVBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery

class HistoryWindow(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("History")
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

        self.db = None
        self.table_model = None

        self.table_view = QTableView()
        self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.table_view.horizontalHeader().setStretchLastSection(1)
        self.table_view.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.load_data()

        self.btn_clear_history = QPushButton("Clear")

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.table_view)
        self.layout.addWidget(self.btn_clear_history)
        self.setLayout(self.layout)

        self.setGeometry(400, 200, 400, 600)

        self.btn_clear_history.clicked.connect(self.clear_history)

    def load_data(self):
        self.db = QSqlDatabase.addDatabase('QSQLITE')
        self.db.setDatabaseName('history.db')
        self.db.open()

        self.table_model = QSqlTableModel()
        self.table_model.setTable("history")
        self.table_model.select()

        self.table_view.setModel(self.table_model)

    def clear_history(self):
        query = QSqlQuery()
        query.exec_("DELETE FROM history")
        if query.isActive():
            print("Records deleted successfully")
        else:
            print("Error deleting records: ", query.lastError().text())

        self.load_data()


from sys import argv
from special.mode import Mode
from special.settings import Settings

class BadMode(Exception):
    pass

class BadCommandLineArguments(Exception):
    pass

class Run:

    def __init__(self, mode: Mode):
        if len(argv) > 1:
            self.parse_arguments(argv[1:])
        else:
            self.parse_mode(mode)

    def parse_arguments(self, args):

        nicks_path = 'nicks_test'
        play_path = 'play_test'
        games_path = 'games_test'
        chat_path = 'chat_test'
        testing_data_path = 'testing'
        backup_testing_path = 'backup testing'
        network_name = 'neural network'

        if args[0] == '--unit-tests':
            Settings.game_mode = Mode.UnitTest
            self.start_unit_tests()

        elif args[0] == '--evolution-tests':
            from holdem.name_manager import NameManager
            from holdem.play.play_manager import PlayManager
            Settings.game_mode = Mode.Evolution
            NameManager.NicksPath = nicks_path
            PlayManager.PlayPath = play_path
            PlayManager.GenCount = 30
            self.start_evolution(100, 9, 27, 1000)
            NameManager.remove_folder()

        elif args[0] == '--parsing-tests':
            from data.game_parser import GameParser, PokerGame
            Settings.game_mode = Mode.Parse
            PokerGame.converted_games_folder = games_path
            PokerGame.converted_chat_folder = chat_path
            games = GameParser.parse_dir(testing_data_path, True, True)
            assert len(games) == 6
            GameParser.copy_dir(backup_testing_path, testing_data_path)
            PokerGame.load_dir(testing_data_path)

        elif args[0] == '--learning-tests':
            from learning.learning import Learning
            from learning.data_sets.decision_model.poker_decision import PokerDecision
            Settings.game_mode = Mode.Learning
            learn = Learning()
            learn.create_data_set(PokerDecision)
            learn.add_data_set(testing_data_path)
            learn.save_data_set(network_name)
            learn.load_data_set(network_name)
            learn.learning(network_name)

        elif args[0] == '--network-play-tests':
            from holdem.game.game import Game
            from holdem.play.play_manager import PlayManager
            from holdem.player.neural_network.net1_net2_player import Net1Net2Player
            Settings.game_mode = Mode.Testing
            PlayManager.PlayPath = play_path
            game = Game()
            for _ in range(8):
                game.add_bot_player()
            game.add_nn_player(network_name, Net1Net2Player)
            PlayManager.remove_folder()

        else:
            raise BadCommandLineArguments(str(args))

    def parse_mode(self, mode):
        Settings.game_mode = mode
        if mode == Mode.GameEngine:
            from holdem.game.game_manager import GameManager
            # PlayManager.standings()
            GameManager().run()

        elif mode == Mode.Parse:
            from data.game_parser import GameParser, PokerGame
            # GameParser.parse_dir('pack0')
            GameParser.parse_dir('pack1', False, False)
            # game.save()
            # game.convert()
            # print(game)
            # PokerGame.load('hh.txt')

        elif mode == Mode.Evolution:
            self.start_evolution(100000, 9, 999, 10000)

        elif mode == Mode.Testing:
            # from learning.neural_network import NeuralNetwork
            # NeuralNetwork.PokerDecision.Bubble(100, 9).show()
            from time import sleep
            from datetime import datetime
            from pickle import load
            from statistics import mean
            from holdem.game.game import Game
            from holdem.player.neural_network.net1_net2_player import Net1Net2Player
            from holdem.player.neural_network.net3_player import Net3Player
            from holdem.player.neural_network.net4_player import Net4Player
            from holdem.player.neural_network.net5_player import Net5Player
            from holdem.player.neural_network.net6_player import Net6Player
            from holdem.player.neural_network.net7_player import Net7Player
            from holdem.player.neural_network.net8_player import Net8Player
            from holdem.player.neural_network.net9_player import Net9Player
            from holdem.play.play_manager import PlayManager
            start_time = datetime.now()

            if 1:
                for _id in range(400):
                    game = Game(players=100)
                    for _ in range(92):
                        game.add_bot_player()
                    game.add_nn_player('nn2', Net1Net2Player)
                    game.add_nn_player('nn3', Net3Player)
                    game.add_nn_player('nn4', Net4Player)
                    game.add_nn_player('nn5', Net5Player)
                    game.add_nn_player('nn6', Net6Player)
                    game.add_nn_player('nn7', Net7Player)
                    game.add_nn_player('nn8', Net8Player)
                    game.add_nn_player('nn9', Net9Player)
                    print('Start game #', _id + 1)
                    while not game.game_finished:
                        sleep(0.01)

            plays = load(open('networks/plays', 'rb'))
            plays = sorted([(k, v) for k, v in plays.items()], key=lambda k: mean(k[1]))
            for i, play in enumerate(plays):
                pl = PlayManager.get_play_by_name(play[0])
                print(f'{i+1:>4}. {round(mean(play[1]), 2):>6} {play[0]:>10}  '
                      f'(ex {pl.exemplar:>6}) {"*" * pl.wins}')
            print('It took', datetime.now() - start_time)

        elif mode == Mode.UnitTest:
            self.start_unit_tests()

        elif mode == Mode.Learning:
            from learning.learning import Learning
            from learning.data_sets.decision_model.poker_decision_10 import PokerDecision10
            from data.game_parser import GameParser
            from datetime import datetime
            learn = Learning()
            learn.create_data_set(PokerDecision10)
            start = datetime.now()
            # GameParser.parse_dir('pack1', False, False)
            # learn.add_data_set('pack1')
            # learn.save_data_set('nn11 common cards.txt')
            learn.load_data_set('nn11 common cards.txt')
            learn.learning('nn11 200x100x100')
            end = datetime.now()
            print('Learning took', end - start)

        elif mode == Mode.Search:
            from data.game_parser import GameParser
            GameParser.search_in_dir('pack1', 'Seat 10')

        else:
            raise BadMode('Bad mode')

    @staticmethod
    def start_unit_tests():
        from unit_tests.testing import UnitTesting
        UnitTesting.test_all()

    @staticmethod
    def start_evolution(games: int, seats_on_table: int, players: int, start_money: int):
        from holdem.play.play_manager import PlayManager
        from learning.evolution import Evolution
        from core.blinds.scheme.schemes import Schemes
        PlayManager.standings()
        Evolution(games, seats_on_table, players, start_money, Schemes.Rapid.value).run()


import mob
import room
from time import sleep
import pygame

pygame.init()
size = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Bran's Cool Game")

# Define some colors
BLACK    = (   0,   0,   0)
WHITE    = ( 255, 255, 255)
GREEN    = (   0, 255,   0)
RED      = ( 255,   0,   0)
BLUE     = (   0,   0, 255)

# Player Initialization
player_state = 0    # none (0), inv (1), menu (2), event (3), movement (4), choice (5)
mc = mob.Mob("Bran")           # Initialize Player character
img = pygame.image.load("base.bmp").convert()   #Import image
img.set_colorkey(WHITE)  # bg transparency
mc_rect = img.get_rect() # Use this rect to do collision detection!
mc_rect.x = mc.x
mc_rect.y = mc.y
inv_open = 0
menu_wait = 0
# Move Rect first, check for collision, then move if safe

#Room Initialization
curr_room = 0        # Index of current room
rooms = []
rooms.append(room.Room("test_room"))

# Loop until the user clicks the close button.
done = False

# Used to manage how fast the screen updates
clock = pygame.time.Clock()

# -------- Main Program Loop -----------
pygame.key.set_repeat(1, 1)
while not done:
    # --- Main event loop
    if pygame.event.get(pygame.QUIT):
        done = True

    blocked = [0, 0, 0, 0]  # Down, Up, Left, and Right block states
    keys = pygame.key.get_pressed() # Returns a list of key statuses

    if keys[pygame.K_SPACE]:
        print("Rect", mc_rect.x, " ", mc_rect.y)
        print("MC", mc.x, " ", mc.y)

    if keys[pygame.K_x]:
        if inv_open == 1:
            inv_open = 0
            sleep(1)

        else:
            inv_open = 1
            sleep(1)

    if keys[pygame.K_DOWN]:
        # Loop through bounds, comparing y + 5 coord to list and change blocked to 1 if
        # a match is found. Then do an if to check if blocked[x] is 1 before continuing on.
        # After that, revert blocked
        mc_rect = mc_rect.move(0, 5)
        if mc_rect.collidelist(rooms[curr_room].rects) != -1:
            print("COLLISION D")
            mc_rect = mc_rect.move(0, -5)
        else:
            mc.y += 5

    if keys[pygame.K_UP]:
        mc_rect = mc_rect.move(0, -5)
        if mc_rect.collidelist(rooms[curr_room].rects) != -1:
            print("COLLISION U")
            mc_rect = mc_rect.move(0, 5)
        else:
            mc.y -= 5

    if keys[pygame.K_LEFT]:
        mc_rect = mc_rect.move(-5, 0)
        if mc_rect.collidelist(rooms[curr_room].rects) != -1:
            print("COLLISION L")
            mc_rect = mc_rect.move(5, 0)
        else:
            mc.x -= 5

    if keys[pygame.K_RIGHT]:
        mc_rect = mc_rect.move(5, 0)
        if mc_rect.collidelist(rooms[curr_room].rects) != -1:
            print("COLLISION R")
            mc_rect = mc_rect.move(-5, 0)
        else:
            mc.x += 5

    # --- Game logic should go here

    # Wall collision test

    # --- Drawing code should go here
    # bottom layer

    screen.fill(WHITE)
    rooms[curr_room].build_walls(screen)
    '''Draw room function'''
    '''Mobs and items draw functions'''
    '''MC draw function'''
    screen.blit(img, [mc.x, mc.y], [0, 0, 100, 100])  # x1, y1, w, h (of image)

    if inv_open == 1:
        pygame.draw.rect(screen, BLACK, [0, 400, 800, 750])  # Dialog/Inventory BlkBox
        pygame.draw.rect(screen, WHITE, [25, 425, 125, 150])  # Dialog/Inventory Pic

        pygame.draw.rect(screen, WHITE, [400, 450, 100, 100])  # Dialog/Inventory Box1
        pygame.draw.rect(screen, WHITE, [525, 450, 100, 100])  # Dialog/Inventory Box2
        pygame.draw.rect(screen, WHITE, [650, 450, 100, 100])  # Dialog/Inventory Box3
        pygame.draw.rect(screen, WHITE, [275, 450, 100, 100])  # Dialog/Inventory Box4
    # topmost layer

    # --- Go ahead and update the screen with what we've drawn.
    pygame.display.flip()

    # --- Limit to 60 frames per second
    clock.tick(60)

pygame.quit()


"""Test delete model
@Author: NguyenKhacThanh
"""

import pytest
from voluptuous import Schema, All, Required
from tests.api import APITestCase

@pytest.mark.usefixtures("inject_client", "inject_params_model_regression")
class DeleteModelTestCase(APITestCase):
    def url(self):
        return "/regression"

    def method(self):
        return "DELETE"

    def test_success(self):
        # push data
        res = self.client.post(
            "/api/v1/regression/huber",
            json=self.params["huber"]
        )
        code, body = self.call_api(
            url=f"/regression/{res.get_json()['id']}",
        )
        schema = Schema({
            Required("message"): str
        })

        schema(body)
        assert 200 == code, body["message"]

    def test_id_model_not_found(self):
        code, body = self.call_api(
            url="/regression/123456781234567812345678",
        )
        schema = Schema({
            Required("message"): str
        })
        schema(body)
        assert 400 == code, body["message"]


from utils import get_input_lines
from numpy import median
from collections import Counter

lines = get_input_lines("input7.txt")
input_list = [int(x) for x  in lines[0].split(",")]

# pt1
print(sum(abs(x - median(input_list)) for x in input_list))

# pt2
mi, mx = min(input_list), max(input_list)
fuel_required = Counter({ elem:0 for elem in range(mi, mx+1) })

sum_one_to_n = lambda n: (n * (n + 1)) // 2

for i in range(mi, mx+1):
    for e in input_list:
        fuel_required[i] += sum_one_to_n(abs(e - i))

print(fuel_required.most_common()[-1])


import os
import sys
import numpy as np
import pandas as pd
import argparse
import pybedtools
import re
import pyBigWig as pbw
import time
import urllib.request

def main():

    start = time.time()
    print("Generating consensus peak file...")
    args = parse_args()
    #for
    Input_peaks=pd.read_csv(args.Peaks, sep="\t")
    # Current peaks =
    for i in range(0, len(Input_peaks.index)):

        urllib.request.urlretrieve(Input_peaks.iloc[i]["URL"], "../tmp/tmp_peak.bed.gz")
        Current_peaks=pybedtools.BedTool("../tmp/tmp_peak.bed.gz")
        Current_peaks_pd=pd.read_table(Current_peaks.fn)
        Current_peaks_pd.to_csv("../tmp/Concat_peaks.bed", mode='a', header=False, sep="\t", index=False)

    # Formatted peaks =

    print(str(len(Input_peaks.index))+" peak files read in "+str(time.time()-start)+" seconds...")

    Concat_peaks=pybedtools.BedTool("../tmp/Concat_peaks.bed")
    Concat_peaks_sorted=Concat_peaks.sort()
    Concat_peaks_merged=Concat_peaks_sorted.merge(d=0)

    Concat_peaks_merged.saveas(args.outdir+args.prefix+"_Consensus_peaks.bed")

def parse_args():
    """ Load command line args """
    parser = argparse.ArgumentParser()
    parser.add_argument('--prefix', metavar="<str>", help=("Output prefix"), type=str, required=True)
    parser.add_argument('--Peaks', metavar="<str>", help=("Input peak URLs"), type=str, required=True)
    parser.add_argument('--outdir', metavar="<str>", help=("Output directory"), type=str, required=True)

    args = parser.parse_args()
    return args

if __name__ == '__main__':

    main()

# python Generate_consensus_peaks.py --prefix BLUEPRINT --Peaks ~/BLUEPRINT_peak_URLs.tsv --outdir ~/BLUEPRINT_peaks/
#


from __future__ import annotations

from typing import TYPE_CHECKING

from randovania.game_description.pickup import pickup_category
from randovania.game_description.pickup.pickup_entry import PickupEntry, PickupGeneratorParams, PickupModel
from randovania.game_description.resources.location_category import LocationCategory
from randovania.games.prime3.patcher import corruption_items
from randovania.generator.pickup_pool import PoolResults

if TYPE_CHECKING:
    from randovania.game_description.resources.resource_database import ResourceDatabase

ENERGY_CELL_CATEGORY = pickup_category.PickupCategory(
    name="energy_cell", long_name="Energy Cell", hint_details=("an ", "energy cell"), hinted_as_major=True, is_key=True
)

def add_energy_cells(
    resource_database: ResourceDatabase,
) -> PoolResults:
    """
    :param resource_database:
    :return:
    """
    item_pool: list[PickupEntry] = []

    for i in range(9):
        item_pool.append(create_energy_cell(i, resource_database))

    return PoolResults(item_pool, {}, [])

def create_energy_cell(
    cell_index: int,
    resource_database: ResourceDatabase,
) -> PickupEntry:
    return PickupEntry(
        name=f"Energy Cell {cell_index + 1}",
        progression=((resource_database.get_item(corruption_items.ENERGY_CELL_ITEMS[cell_index]), 1),),
        extra_resources=(
            (resource_database.get_item(corruption_items.ENERGY_CELL_TOTAL_ITEM), 1),
            (resource_database.get_item(corruption_items.PERCENTAGE), 1),
        ),
        model=PickupModel(
            game=resource_database.game_enum,
            name=corruption_items.ENERGY_CELL_MODEL,
        ),
        pickup_category=ENERGY_CELL_CATEGORY,
        broad_category=pickup_category.GENERIC_KEY_CATEGORY,
        generator_params=PickupGeneratorParams(
            preferred_location_category=LocationCategory.MAJOR,
            probability_offset=0.25,
        ),
    )


import os, subprocess, datetime, re, shlex

class TortoiseSVNManager:
    def __init__(self, tortoisesvn=None):
        if tortoisesvn == None:
            print("\n\n None Path - TortoiseProc.exe")
            os.system("Pause")
            sys.exit()
        else:
            self.tortoisesvn = tortoisesvn

    def makecommitmsg(self, buildversion, commitmsg):
        # Make Commit Message
        try:
            with open(r'./commitmsg.txt', "w") as f:
                buildversion = re.sub(",", ", ", buildversion)
                f.write(commitmsg + "\n\n" + buildversion)
        except FileNotFoundError:
            return False

        return True

    def commit(self, projectlist):
        # Ensure TortoiseProc exists
        if not os.path.isfile(self.tortoisesvn + '\\TortoiseProc.exe'):
            raise Exception('TortoiseProc.exe not found. path=' + self.tortoisesvn + '\\TortoiseProc.exe')

        commitmsgpath = os.getcwd()
        os.chdir(self.tortoisesvn)

        for project in projectlist:
            if project["isuse"] == "1":
                print("PROGRESSING COMMIT - " + project["project_path"] + "\n")
                command = 'TortoiseProc.exe'
                command += ' /command:commit'
                command += (' /path:' + project["project_path"])
                command += (' /logmsgfile:"' + commitmsgpath + '\\commitmsg.txt"')
                command += ' /closeonend:0'
                os.system(command)

        print("\n")
        return True

    def run(self, buildversion=None, projectlist=None, commitmsg=None):
        summary = ''

        # File header
        start = datetime.datetime.now()
        print('\n' * 3)
        summary += self.log('STARTED SVN COMMIT - ' + start.strftime("%Y-%m-%d %H:%M:%S"))

        # Make Commit Message
        if (buildversion is not None) and (commitmsg is not None):
            makeOk = self.makecommitmsg(buildversion, commitmsg)
            if not makeOk:
            	self.log('COMMIT: FAILED - FILE NOT FOUND', start)
            	sys.exit(100)
            summary += self.log('COMMIT: SUCCEEDED - MAKE COMMIT MESSAGE', start)
        else:
        	summary += self.log('COMMIT: NOT SPECIFIED')

        # Commit
        if projectlist is not None:
            commitOK = self.commit(projectlist)
            if not commitOK:
            	self.log('COMMIT: FAILED', start)
            	sys.exit(100)
            summary += self.log('COMMIT: SUCCEEDED', start)
        else:
        	summary += self.log('COMMIT: NOT SPECIFIED - PROJECT LIST')

        summary += self.log('COMMIT: *** FINISH ***', start)

        # Build summary
        print('\n\n' + '-' * 80)
        print(summary)
        print('-' * 80)

    def log(self, message, start=None):
    	timestamp = ''
    	numsecs = ''
    	if start is not None:
    		split = datetime.datetime.now()
    		diff = split - start
    		timestamp = split.strftime("%Y-%m-%d %H:%M:%S") + '\t'
    		numsecs = ' (' + str(diff.seconds) + ' seconds)'
    	msg = timestamp + message + numsecs + '\n\n'
    	print('=' * 10 + '> ' + msg)
    	return msg


from enum import Enum, unique

from sqlalchemy import (
    Column, Table, MetaData, Integer, String, ForeignKey, Enum as PgEnum, DateTime,
    PrimaryKeyConstraint,
    UniqueConstraint
)

convention = {
    'all_column_names': lambda constraint, table: '_'.join([
        column.name for column in constraint.columns.values()
    ]),
    'ix': 'ix__%(table_name)s__%(all_column_names)s',
    'uq': 'uq__%(table_name)s__%(all_column_names)s',
    'ck': 'ck__%(table_name)s__%(constraint_name)s',
    'fk': 'fk__%(table_name)s__%(all_column_names)s__%(referred_table_name)s',
    'pk': 'pk__%(table_name)s'
}

metadata = MetaData(naming_convention=convention)

@unique
class ShopUnitType(Enum):
    OFFER = 'OFFER'
    CATEGORY = 'CATEGORY'

shop_unit_ids_table = Table(
    'shop_unit_ids', metadata,
    Column('id', String, primary_key=True),
)

shop_unit_revisions_table = Table(
    'shop_unit_revisions', metadata,
    Column('id', Integer, primary_key=True, autoincrement=True),
    Column('date', DateTime, nullable=False),
    Column('shop_unit_id', String,
           ForeignKey('shop_unit_ids.id', ondelete='CASCADE', onupdate='RESTRICT'), nullable=False),
    Column('name', String, nullable=False),
    Column('price', Integer, nullable=True),
    Column('type', PgEnum(ShopUnitType, name='shop_unit_type'), nullable=False),
    UniqueConstraint('shop_unit_id', 'date', name='uq__shop_unit_revisions__shop_unit_id_date'),
)

relations_table = Table(
    'relations', metadata,
    Column('child_revision_id', Integer,
           ForeignKey('shop_unit_revisions.id', ondelete='CASCADE', onupdate='RESTRICT'),
           nullable=False),
    Column('parent_id', String,
           ForeignKey('shop_unit_ids.id', ondelete='RESTRICT', onupdate='CASCADE'), nullable=False),
    UniqueConstraint('child_revision_id', 'parent_id'),
    PrimaryKeyConstraint('child_revision_id', name='pk__relations'),
)


import numpy as np
from termcolor import colored
import matplotlib.pyplot as plt

filename = 'scan1.txt'
file = open(filename, 'r')
lines = file.readlines()
inittime=lines[0]
endtime=lines[1]

print('# of lines',len(lines))
ADCout=[]
ADCoutstepsMean=[]
ADCoutstepsStd=[]

i=2
data=len(lines)
while i<data:
	ADCout.append(float(lines[i]))
	i+=1
xaxis=range(data-2)

plt.plot(xaxis, ADCout, marker='.', linestyle='')
plt.grid(True)
plt.title(filename)
plt.xlabel('sample')
plt.ylabel('ADC output (V)')
plt.tight_layout()
plt.savefig(filename[:-4]+'.png')
plt.show()


import csv
import sys
import getopt
import numpy as np
import pandas as pd
import nltk

def get_dataframe(filename):
    return pd.read_table(filename)

def get_hfw():
    word_file = open('./picked/pacifier.txt', 'r')
    res = list()
    for word in word_file.readlines():
        word = word.split(" ")[0]
        res.append(word)
    return res

def get_hfw_weight():
    word_file = open('./picked/pacifier.txt', 'r')
    res = list()
    for word in word_file.readlines():
        for weigth in word.split(" "):
            try:
                res.append(float(weigth))
            except ValueError:
                pass
    return res

def get_adj():
    word_file = open('./picked/pacifier_a.txt', 'r')
    res_p = list()
    res_n = list()
    for word in word_file.readlines():
        is_positive = False
        if "1" in word.split(" ") or  "1\n"  in word.split(" "):
            is_positive = True
        word = word.split(" ")[0]
        if is_positive:
            res_p.append(word)
        else:
            res_n.append(word)
    return (res_p, res_n)

def get_brands():
    table = get_dataframe("/source_file_path/Problem_C_Data/pacifier.tsv")
    product_titles = table[table['helpful_votes']!=0].product_title.tolist()
    count = {}
    for t in product_titles:
        count[t] = count.get(t, 0) + 1
    res = list()
    for title in count:
        if count[title] > 5:
            res.append(title)
    return res

def get_staratings(product_title):
    table = get_dataframe("/source_file_path/Problem_C_Data/pacifier.tsv")
    product_stars = table[table['product_title']==product_title].star_rating.tolist()
    product_votes = table[table['product_title']==product_title].helpful_votes.tolist()
    res = 0.0
    count = 0
    for i in range(len(product_stars)):
        res += product_stars[i] * product_votes[i]
        count += product_votes[i]
    return res/count

def get_sentence(product_title):
    table = get_dataframe("/source_file_path/Problem_C_Data/pacifier.tsv")
    product_reviews = table[table['product_title']==product_title].review_body.tolist()
    product_review_titles = table[table['product_title']==product_title].review_headline.tolist()
    '''
    product_reviews = table.review_body.tolist()
    product_review_titles = table.review_headline.tolist()
    '''
    product_reviews.extend(product_review_titles)
    tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
    sentences = list()
    for paragraph in product_reviews:
        try:
            sentences.extend(tokenizer.tokenize(paragraph))
        except:
            continue
        finally:
            pass
    return sentences

def get_pairs(product_title):
    # print("----------"+product_title+"----------")
    hfw = get_hfw()
    product_reviews = get_sentence(product_title)
    counts = {}
    for rw in product_reviews:
        tokens = nltk.word_tokenize(rw)
        for hf_word in hfw:
            if hf_word in tokens:
                pos_tags = nltk.pos_tag(tokens)
                last_token = ""
                for token, pos in pos_tags:
                    if pos == "JJ" or pos == "JJS" or pos == "JJR":
                        tmp_pair=(hf_word.lower(), token.lower())
                        if last_token != "not" and last_token != "barely" and last_token != "hardly":
                            counts[tmp_pair] = counts.get(tmp_pair, 0) + 1
                last_token = token
    return counts

def compute_vector(brandname):
    adjs = get_adj()
    positive_adj = adjs[0]
    negative_adj = adjs[1]
    dimension = get_hfw()
    pair_counts = get_pairs(brandname)
    items = list(pair_counts.items())
    items.sort(key=lambda x:x[1], reverse=True)
    vector = []
    # each dimension
    for d in dimension:
        val = 0
        adj_count = 0
        dimension_score = 0
        # iteration in pairs to
        for pairs_ct in items:
            pairs, count = pairs_ct
            count = int(count)
            if pairs[0] == d:
                if pairs[1] in positive_adj:
                    val += 1 * count
                elif pairs[1] in negative_adj:
                    val -= 1 * count
                adj_count += count
        if adj_count != 0:
            dimension_score = val / adj_count
        dimension_res = (d, dimension_score)
        vector.append(dimension_res)

    return vector

def compute_value(brandname):
    vector = compute_vector(brandname)
    value = 0.0
    weights = get_hfw_weight()
    total = 0.0
    for w in weights:
        total += w
    st_weight = list()
    for w in weights:
        st_weight.append(w/total)
    for i in range(len(vector)):
        value += vector[i][1] * st_weight[i]
    return value

def main():
    items = get_brands()
    score_line = ""
    star_line = ""
    for i in items:
        score = compute_value(i)
        star = get_staratings(i)
        if True: #star < (20*score+2.5) and star > (1.25*16 / 3)*(score+0.125):
            score_line += str(score) + ", "
            star_line += str(star) + ", "
    print(score_line)
    print(star_line)

# main()
# compute_vector()
# get_sentence("samsung smh1816s 1.8 cu. ft. stainless steel over-the-range pacifier")
main()


import torch
import torch.nn as nn

# Tuple is structured by (filters, kernel_size, stride)

'''
Information about architecture config:
Tuple is structured by (filters, kernel_size, stride)
Every conv is a same convolution.
List is structured by "B" indicating a residual block followed by the number of repeats
"S" is for scale prediction block and computing the yolo loss
"U" is for upsampling the feature map and concatenating with a previous layer
'''
# ['B',重复次数]

config = [
    (32, 3, 1),
    (64, 3, 2),
    ["B", 1],
    (128, 3, 2),
    ["B", 2],
    (256, 3, 2),
    ["B", 8],
    (512, 3, 2),
    ["B", 8],
    (1024, 3, 2),
    ["B", 4],  # To this point is Darknet-53
    (512, 1, 1),
    (1024, 3, 1),
    "S",
    (256, 1, 1),
    "U",
    (256, 1, 1),
    (512, 3, 1),
    "S",
    (128, 1, 1),
    "U",
    (128, 1, 1),
    (256, 3, 1),
    "S",
]

class CNNBlock(nn.Module):
  def __init__(self,in_channels,out_channels,bn_act=True,**kwargs):
    super().__init__()
    self.conv = nn.Conv2d(in_channels,out_channels,bias=not bn_act,**kwargs)
    self.bn = nn.BatchNorm2d(out_channels)

    self.leaky = nn.LeakyReLU(0.1)

    self.use_bn_act = bn_act

  def forward(self,x):
    if self.use_bn_act:
      self.leaky(self.bn(self.conv))
    else :
      return self.conv(x)

class ResidualBlock(nn.Module):
  def __init__(self,channels,use_residual=True,num_repeats = 1):
    super().__init__()
    self.layers = nn.ModuleList()
    for _ in num_repeats:
      self.layers +=[
        CNNBlock(channels,channels//2,kernel_size=1),
        CNNBlock(channels//2,channels,kernel_size=3,padding=1)
      ]
    self.use_residual = use_residual
    self.num_repeats = num_repeats

  def forward(self):
    for layers in self.layers:
      x = layers(x)+x if self.use_residual else layers(x)
    return x

class ScalePrediction(nn.Module):
  pass

class YOLOv3(nn.Module):
  pass


import warnings
from typing import List
import numpy as np
from scipy import linalg

class Tensor(np.ndarray):
    def __new__(cls, num_modes: int, modes: tuple[int], data: np.ndarray):
        obj = np.asarray(data).view(cls)
        obj.num_modes = num_modes
        obj.modes = np.asarray(modes)
        if np.any(obj.modes) <= 0: raise ValueError(
            "'modes' must contain strictly positive values; if np.any mode is 1, consider a smaller num_modes")
        return obj

    # Pour pouvoir accéder aux données via .data et mimiquer rTensor. Mais inutile, à déprécier
    @property
    def data(self):
        return self[...]

    def is_zero_tensor(self):
        if np.sum(self.data == 0) == np.prod(np.asarray(self.modes)): return True
        return False

def astensor(array: np.ndarray) -> Tensor:
    modes = array.shape
    num_modes = len(modes)
    return Tensor(num_modes=num_modes, modes=modes, data=array)

def unfold(tensor: Tensor, row_idx: List[int], col_idx: List[int], order='F') -> Tensor:
    rs = np.asarray(row_idx)
    cs = np.asarray(col_idx)
    # if not rs or not cs: raise ValueError("row and column indices must be specified")
    num_modes = tensor.num_modes  # pour démarrer à zero

    if len(rs) + len(cs) != num_modes:
        raise ValueError("Incorrect number of indices. Number of modes not reached.")
    if np.any(rs < 0) or np.any(rs > num_modes - 1) or np.any(cs < 0) or np.any(cs > num_modes - 1):
        raise ValueError(
            "Illegal indices specified. 'row_idx' and 'col_idx' must be positive and strictly less than 'num_modes'.")
    perm = np.array(list(rs) + list(cs))
    if np.any(np.sort(perm) != np.arange(num_modes)):
        raise ValueError("Missing and/or repeated indices")

    modes = tensor.modes
    mat = tensor.data
    new_modes = np.array([np.prod(modes[rs]), np.prod(modes[cs])])
    mat = np.transpose(tensor.data, perm)  # probablement soustraire -1 à perm pour les indices
    mat = mat.reshape(new_modes, order=order)  # rearrangement style fortran comme pour dim() <- dim en R:
    # https://rstudio.github.io/reticulate/reference/array_reshape.html
    return astensor(mat)

def rs_unfold(tensor: Tensor, m: int, order='F') -> Tensor:
    assert 0 <= m < tensor.num_modes, f"'m' must be a valid mode of the tensor, not {m}."
    rs = np.asarray([m])
    cs = np.asarray([i for i in range(tensor.num_modes) if i != m])
    return unfold(tensor, row_idx=rs, col_idx=cs, order=order)

# Validé par essai manuel
def superdiagonal_tensor2(num_modes, length, elements=1):
    modes = [length] * num_modes
    arr = np.zeros(modes, dtype=np.float32)

    if isinstance(elements, int):
        elements = [elements] * length

    for i in range(length):
        indices = [i] * num_modes
        arr[tuple(indices)] = elements[i]

    return astensor(arr)

# L'implémentation originale pernd une liste en argument, et les multiplie entre elles, "element-wise".
# L'opération est largement simplifiée avec un ndarray

# Vérifiée à la main
# def hadamard_list(L: np.ndarray) -> np.ndarray:
#     # TODO: Verif forme des tableaux, et de la nature de L``
#     # return np.prod(L, axis=-1)  # typiquement axis=2 dans notre cas
#
#     retmat = L[0]
#     for matrice in L[1:]:
#         retmat = np.multiply(retmat, matrice)
#     return retmat

def hadamard_list(L):
    retmat = L[0]
    for matrice in L[1:]:
        retmat *= matrice
    return retmat

def kronecker_list(L):
    result = L[0]
    for matrix in L[1:]:
        result = np.kron(result, matrix)
    return result

def superdiagonal_tensor(num_modes, length, elements=1):
    modes = np.repeat(length, num_modes)
    arr = np.zeros(modes)
    if isinstance(elements, int) == 1:
        elements = np.repeat(elements, length)
    for i in range(length):
        txt = "arr[" + ",".join([str(i)] * num_modes) + "]=" + str(elements[i])
        txt = txt.replace(" ", ", ")
        print(txt)
        exec(txt)
    return arr

def khatri_rao_list_2(L, reverse=False):
    if reverse:
        L = L[::-1]

    retmat = L[0]
    for matrice in L[1:]:
        retmat = linalg.khatri_rao(retmat, matrice)
    return retmat

def khatri_rao_list(L, reverse=False):
    assert all([isinstance(x, np.ndarray) for x in L]), "All elements in L must be matrices"
    ncols = [x.shape[1] for x in L]
    assert len(set(ncols)) == 1, "All matrices in L must have the same number of columns"
    ncols = ncols[0]
    nrows = [x.shape[0] for x in L]
    retmat = np.zeros((np.prod(nrows), ncols))
    if reverse:
        L = L[::-1]
    for j in range(ncols):
        Lj = [x[:, j] for x in L]
        retmat[:, j] = kronecker_list(Lj)
    return retmat

def khatri_rao_list_bis(L, reverse=False):
    # Vérifie que tous les éléments de L sont des matrices
    assert all(isinstance(matrix, np.ndarray) for matrix in L), "Tous les éléments de L doivent être des matrices"

    # Vérifie que toutes les matrices ont le même nombre de colonnes
    ncols = [matrix.shape[1] for matrix in L]
    assert len(set(ncols)) == 1, "Toutes les matrices doivent avoir le même nombre de colonnes"
    ncols = ncols[0]

    # Initialise la matrice résultante
    nrows = [matrix.shape[0] for matrix in L]

    retmat = np.zeros((np.prod(nrows), ncols))
    # Inverse l'ordre des matrices si reverse=True
    if reverse:
        L = L[::-1]

    # Remplit la matrice résultante en utilisant le produit de Kronecker
    for j in range(ncols):
        # Lj = [matrix[:, j] for matrix in L]
        # retmat[:, j] = kronecker_list(Lj)
        retmat = linalg.khatri_rao(a, b)
    return retmat

def ttl(tnsr, list_mat, ms=None):
    if ms is None or not isinstance(ms, (list, np.ndarray)):
        raise ValueError("m modes must be specified as a vector")

    if len(ms) != len(list_mat):
        raise ValueError("m modes length does not match list_mat length")

    num_mats = len(list_mat)
    if len(set(ms)) != num_mats:
        print("Consider pre-multiplying matrices for the same m for speed")

    mat_nrows = [mat.shape[0] for mat in list_mat]
    mat_ncols = [mat.shape[1] for mat in list_mat]

    for i in range(num_mats):
        mat = list_mat[i]
        m = ms[i]

        mat_dims = mat.shape
        modes_in = tnsr.modes

        if modes_in[m] != mat_dims[1]:
            raise ValueError(f"Modes mismatch: tnsr.modes[{m}] != mat.shape[1]")

        modes_out = modes_in.copy()
        modes_out[m] = mat_dims[0]

        tnsr_m = rs_unfold(tnsr, m=m).data
        retarr_m = np.dot(mat, tnsr_m)
        tnsr = rs_fold(retarr_m, m=m, modes=modes_out)

    return tnsr

def fold(mat: Tensor | np.ndarray, row_idx: List[int], col_idx: List[int], modes: List[int], order='F'):
    rs = row_idx
    cs = col_idx

    if not isinstance(mat, np.ndarray):
        raise ValueError("mat must be of type 'numpy.ndarray'")
    if mat.ndim != 2:
        raise ValueError("mat must be a 2D matrix")

    num_modes = len(modes)
    if num_modes != len(rs) + len(cs):
        raise ValueError("Number of modes does not match the sum of row and column space indices")

    mat_modes = mat.shape
    if mat_modes[0] != np.prod([modes[i] for i in rs]) or mat_modes[1] != np.prod([modes[i] for i in cs]):
        raise ValueError("Matrix dimensions do not match Tensor modes")

    # iperm = [modes.index(mode) + 1 for mode in rs + cs]
    modes = list(modes)
    iperm = rs + cs
    # iperm = [modes.index(x) + 1 if x in modes else None for x in rs + cs]
    # iperm = [np.where(np.array(modes) == mode)[0][0] if mode in modes else None for mode in rs + cs]
    modes = np.asarray(modes)
    mat = mat.reshape([modes[i] for i in rs] + [modes[i] for i in cs], order=order)
    # folded_tensor = np.transpose(mat, iperm)
    folded_tensor = np.moveaxis(mat, range(len(rs) + len(cs)), rs + cs)
    # mat = mat.reshape(new_modes, order='F')  # rearrangement style fortran comme pour dim() <- dim en R:
    # https://rstudio.github.io/reticulate/reference/array_reshape.html return astensor(mat)
    return astensor(folded_tensor)

def k_fold(mat: Tensor | np.ndarray, m: int, modes: List[int], order='F') -> Tensor:
    num_modes = len(modes)
    rs = [m]
    cs = [i for i in range(num_modes) if i != m]  # vérifier si on bouge m, ou l'indice lié à m
    return fold(mat, row_idx=rs, col_idx=cs, modes=modes, order=order)

def rs_fold(mat: Tensor | np.ndarray, m: int, modes: List[int], order='F') -> Tensor:
    return k_fold(mat, m, modes, order)


import re
import numpy as np
import pickle
import spacy_udpipe
import spacy
import pandas as pd
from nltk.stem.porter import PorterStemmer
from nltk.tokenize import RegexpTokenizer
from tqdm import tqdm
from bs4 import BeautifulSoup
from collections import Counter

class VectorSpaceModel():
    '''
    Vector space information retrieval system
    Baseline has:
    - terms: word forms
    - case normalization: no
    - removing stopwords: no
    - query construction: all word forms from "title"
    - term weighting: natural
    - document frequency weighting: none
    - vector normalization: cosine
    - similarity measurement: cosine
    - relevance feedback: none
    - query expansion: none

    Options include:
    stopwords, lemmas, stemming, lower-case,
    pivoted document length, tf/df weighting
    '''

    def __init__(self, args, index):
        self.run = args.run
        self.output = args.output
        self.stopwords = args.stopwords
        self.lemmas = args.lemmas
        self.stemming = args.stemming
        self.lowercase = args.lowercase
        self.pivoted = args.pivoted
        self.tf_weighting = args.tf_weighting
        self.df_weighting = args.df_weighting
        self.index = index
        self.lang = args.documents.split(".")[0][-2:]

        self.query_terms = self.get_topic_terms(args.queries)
        self.docs = self.get_docs(args.documents)

        self.save_results()

    def get_topic_terms(self, queries):
        ''' return dictionary of topic_num: [term for term in title] '''
        with open(queries, 'r') as f:
            topics = f.read()
        soup = BeautifulSoup(topics, 'html.parser')
        head = soup.contents[2]
        topics = [item for item in head.children][1::2]
        nums = [doc.num.contents[0] for doc in topics]

        if self.lang == "en":
            nlp = spacy.load("en_core_web_sm", exclude=['parser', 'ner'])
        else:
            nlp = spacy_udpipe.load("cs")
        stopword_list = nlp.Defaults.stop_words
        tokenizer = RegexpTokenizer(r'\w+')

        if self.lemmas:
            titles = [nlp(str(doc.title.contents[0])) for doc in topics]
        else:
            titles = [tokenizer.tokenize(doc.title.contents[0]) for doc in topics]

        if self.lemmas:
            titles = [[k.lemma_.lower() for k in doc] for doc in titles]
        elif self.lowercase:
            titles = [[k.lower() for k in doc] for doc in titles]
        else:
            titles = [[k for k in doc] for doc in titles]
        if self.stopwords:
            titles = [[k for k in doc if not k in stopword_list and k.isalpha()]
                    for doc in titles]
        # only for English - Czech is pre-stemmed
        if self.stemming:
            stemmer = PorterStemmer()
            titles = [[stemmer.stem(str(k)) for k in doc] for doc in titles]

        query_terms = {num: title for num, title in zip(nums, titles)}

        return query_terms

    def get_tf_weight(self, tf, d, weighting='natural'):
        '''
        weighting options are as below
        natural (default): tf_{t,d}
        logarithm: 1 + log(tf_{t,d})
        augmented: 0.5 + (0.5*tf_{t,d})/max_t(tf_{t,d})
        '''
        if self.tf_weighting:
            weighting = self.tf_weighting
        if weighting == 'natural': tf_weight = tf
        elif weighting == 'logarithm': tf_weight = 1 + np.log2(tf)
        elif weighting == 'augmented':
            tf_weight = 0.5 + ((0.5 * tf)/ max(Counter(d).values()))
        return tf_weight

    def get_df_weight(self, df, tf, weighting='no'):
        '''
        weighting options are as below
        no (default): 1
        idf: log(N/df_{t})
        prob_idf: max(0, log((N-df)/df))
        '''
        if self.df_weighting:
            weighting = self.df_weighting
        if weighting == 'no': df_weight = 1
        elif weighting == 'idf': df_weight = np.log2(len(self.docs)/df)
        elif weighting == 'prob_idf':
            df_weight = max(0, np.log2((len(self.docs) - df)/df))
        return df_weight

    def get_docs(self, docs_file):
        ''' returns list of tuples of (doc_id, [terms]) '''
        docs_folder = docs_file.split(".")[0]+self.run+"/"
        with open(docs_file, "r") as f:
            filenames = [line.split(".")[0] for line in f.readlines()]
        docs = []
        for fn in filenames:
            with open(docs_folder+fn+"_docs.bin", 'rb') as f:
                collection = pickle.load(f)
            for doc in collection:
                docs.append((doc[0], doc[1]))
        return docs

    def similarity(self, query, length, k=1000):
        '''
        fast cosine score (IIR fig 7.1)
        returns top k docs for query
        '''
        docs = self.docs
        doc_dict = {doc[0]: doc[1] for doc in docs}

        scores = pd.DataFrame(np.zeros((1,len(docs))), columns=[doc[0] for doc in docs])
        for t in query:
            try:
                postings_list = self.index[t]
                for d, tf in postings_list.items():
                    # just storing natural term frequency
                    scores[d] += self.get_tf_weight(tf, doc_dict[d]) \
                            * self.get_df_weight(len(postings_list), tf)
            except KeyError:
                pass

        query_length = np.linalg.norm(list(Counter(query).values()))

        scores = scores/(query_length*length)
        scores = scores.to_numpy().reshape((len(docs),))

        inds = np.argpartition(scores, -k)[-k:]

        sorted_inds = inds[np.argsort(scores[inds])]
        doc_nos = [docs[docid][0] for docid in sorted_inds]

        return scores[sorted_inds][::-1], doc_nos[::-1]

    def save_results(self):
        '''
        save results in TREC format, as described in section 5.3
        (qid, iter, docno, rank, sim, run_id)
        '''
        iteration = "0"
        run_id = self.run

        print("Processing queries")
        doc_dict = {doc[0]: list(Counter(doc[1]).values()) for doc in self.docs}
        # cosine normalization
        length = np.array([np.linalg.norm(counts) for counts in doc_dict.values()])
        if self.pivoted: # value of a
            if self.lang == "cs":
                # values are computed as described in report
                piv = 24.6788
            else:
                piv = 40.7795
            length = self.pivoted*length + (1-self.pivoted)*piv
        for (qid, query) in tqdm(self.query_terms.items()):
            sim_scores, doc_nos = self.similarity(query, length)
            results = [qid+"\t"+iteration+"\t"+doc_no+"\t"+str(i)+"\t"+str(sim)
                    +"\t"+run_id+"\n"
                    for i, (doc_no, sim) in enumerate(zip(doc_nos, sim_scores))]

            with open(self.output, "a+") as f:
                f.writelines(results)


import pymdicator.timeseries as ts
from pymdicator.indicators import Momentum, MACD, RSI
import numpy as np
import datetime
import pytest
import os
from pandas import read_csv

@pytest.fixture(params=[False, True])
def test_data(request, datadir):
    if request.param:
        pd = read_csv(datadir.join('stock_data.txt'))
        dts = pd['Date'].tolist()
        vals = pd["Close"].tolist()
    else:
        dts = [datetime.date(2018, 1, 1)]
        for ii in range(1, 20):
            dts.append(dts[0] + datetime.timedelta(ii))
        vals = [100.0, 102.0, 99.0, 101.0, 103.0, 101.5, 103.0, 104.0, 103.5, 105,
                106.0, 105.5, 108.0, 109.0, 111.0, 109.5, 112.0, 114.0, 113.5, 115]
        pd = None
    test_ts = ts.Timeseries(dts, vals, ts.TimeseriesType.PRICE, ts.TimeseriesSubType.ABSOLUTE, 1)
    return {
        'dts': dts,
        'vals': vals,
        'test_ts': test_ts,
        'is_csv': request.param,
        'pd' : pd}

@pytest.fixture
def dts(test_data):
    return test_data['dts']

@pytest.fixture
def vals(test_data):
    return test_data['vals']

@pytest.fixture
def test_ts(test_data):
    return test_data['test_ts']

@pytest.fixture
def is_csv(test_data):
    return test_data['is_csv']

@pytest.fixture
def pd(test_data):
    return test_data['pd']

def test_latest_momentum(test_ts, vals, dts, is_csv, pd):
    momIndicator = Momentum(12)
    mom = momIndicator.calculate_current_ts(test_ts)

    if not is_csv:
        assert np.isclose(mom, 100.0 * 115.0 / 104.0)
    else:
        assert np.isclose(mom, 100.0*vals[-1] / vals[-13])
        mom = momIndicator.calculate_current_df(pd)
        assert np.isclose(mom, 100.0 * vals[-1] / vals[-13])

def test_latest_momentum_overlong(test_ts, vals):
    momIndicator = Momentum(len(test_ts))
    mom = momIndicator.calculate_current_ts(test_ts)
    assert np.isnan(mom)

    momIndicator = Momentum(len(test_ts) - 1)
    mom = momIndicator.calculate_current_ts(test_ts)
    assert np.isclose(mom, 100.0 * vals[-1] / vals[0])

def test_momentum_timeseries(test_ts, vals, dts, is_csv, pd):
    momIndicator = Momentum(10)
    mom_ts = momIndicator.calculate_timeseries_ts(test_ts)
    if not is_csv:
        assert np.isclose(mom_ts.values[0], 106.0)
        assert np.isclose(mom_ts.values[1], 105.5/1.02)
        assert np.isclose(mom_ts.values[2], 108.0/0.99)
        assert np.isclose(mom_ts.values[3], 109.0/1.01)
    else:
        n_checks = min(20, len(vals)-10)
        mom_ts_pd = momIndicator.calculate_timeseries_df(pd)
        for ii in range(n_checks):
            assert np.isclose(mom_ts.values[ii],
                              100.0 * vals[ii + 10] / vals[ii])
            assert np.isclose(mom_ts_pd.values[ii],
                              100.0 * vals[ii + 10] / vals[ii])

def test_latest_momentum_outer(test_ts, vals, dts, is_csv, pd):
    momIndicator = Momentum(12)
    mom = momIndicator.calculate_current(test_ts)

    if not is_csv:
        assert np.isclose(mom, 100.0 * 115.0 / 104.0)
    else:
        assert np.isclose(mom, 100.0*vals[-1] / vals[-13])
        mom_pd = momIndicator.calculate_current(pd)
        assert np.isclose(mom_pd, 100.0*vals[-1] / vals[-13])
        mom_dict = momIndicator.calculate_current({"a": pd})
        assert np.isclose(mom_dict["a"], 100.0*vals[-1] / vals[-13])

def test_momentum_timeseries_outer(test_ts, vals, dts, is_csv, pd):
    momIndicator = Momentum(10)
    mom_ts = momIndicator.calculate_timeseries(test_ts)
    if not is_csv:
        assert np.isclose(mom_ts.values[0], 106.0)
        assert np.isclose(mom_ts.values[1], 105.5/1.02)
        assert np.isclose(mom_ts.values[2], 108.0/0.99)
        assert np.isclose(mom_ts.values[3], 109.0/1.01)
    else:
        n_checks = min(20, len(vals)-10)
        mom_pd = momIndicator.calculate_timeseries(pd)
        mom_dict = momIndicator.calculate_timeseries({"a": pd})

        for ii in range(n_checks):
            assert np.isclose(mom_ts.values[ii],
                              100.0 * vals[ii + 10] / vals[ii])
            assert np.isclose(mom_pd.values[ii],
                              100.0 * vals[ii + 10] / vals[ii])
            assert np.isclose(mom_dict["a"].values[ii],
                              100.0 * vals[ii + 10] / vals[ii])

def test_latest_macd(test_ts, vals, is_csv, pd):
    macd_calc = MACD()
    (macd, signal) = macd_calc.calculate_current_ts(test_ts)
    if not is_csv:
        assert np.isnan(macd) and np.isnan(signal)
    else:
        # I can't be bothered to do full calculation,
        # so make sure the values are sensible
        slow_average = sum(vals[-26:]) / 26.0
        fast_average = sum(vals[-12:]) / 12.0
        assert abs(macd) <= abs(2*(fast_average - slow_average))
        assert abs(signal) <= abs(2*(fast_average - slow_average))
        (macd_df, signal_df) = macd_calc.calculate_current_df(pd)
        assert np.isclose(macd_df, macd)
        assert np.isclose(signal_df, signal)

def test_latest_macd_outer(test_ts, vals, is_csv, pd):
    macd_calc = MACD()
    (macd, signal) = macd_calc.calculate_current(test_ts)
    if not is_csv:
        assert np.isnan(macd) and np.isnan(signal)
    else:
        # I can't be bothered to do full calculation,
        # so make sure the values are sensible
        slow_average = sum(vals[-26:]) / 26.0
        fast_average = sum(vals[-12:]) / 12.0
        assert abs(macd) <= abs(2*(fast_average - slow_average))
        assert abs(signal) <= abs(2*(fast_average - slow_average))
        (macd_df, signal_df) = macd_calc.calculate_current(pd)
        assert np.isclose(macd_df, macd)
        assert np.isclose(signal_df, signal)
        (macd_dict, signal_dict) = macd_calc.calculate_current({"a":pd})["a"]
        assert np.isclose(macd_dict, macd)
        assert np.isclose(signal_dict, signal)

def test_latest_rsi(test_ts, vals, is_csv, pd):
    rsi_calc = RSI(10)
    rsi = rsi_calc.calculate_current_ts(test_ts)
    if not is_csv:
        assert np.isclose(100.0 - 100.0 / (1 + 12.5/2.5), rsi)
    else:
        rsi_df = rsi_calc.calculate_current_df(pd)
        assert np.isclose(rsi, rsi_df)

def test_timeseries_rsi(test_ts, vals, is_csv, pd):
    rsi_calc = RSI(10)
    rsi = rsi_calc.calculate_current_ts(test_ts)
    rsi_ts = rsi_calc.calculate_timeseries_ts(test_ts)
    if not is_csv:
        assert np.isclose(100.0 - 100.0 / (1 + 12.5/2.5), rsi_ts.values[-1])
        assert np.isclose(100.0 - 100.0 / (1 + 12.5/2.5), rsi_ts.values[-2])
        assert np.isclose(100.0 - 100.0 / (1 + 12.5/2.5), rsi_ts.values[-3])
        assert np.isclose(100.0 - 100.0 / (1 + 11.5/2.5), rsi_ts.values[-4])
        assert np.isclose(100.0 - 100.0 / (1 + 10.5/2.5), rsi_ts.values[-5])
        assert np.isclose(100.0 - 100.0 / (1 + 10.5/2.5), rsi_ts.values[-6])
    else:
        assert np.isclose(rsi_ts.values[-1], rsi)


#AREA
from database.config import Conexion
from helper import helper

#TABLA AREA
class Area:
    def __init__(self, tipoArea=None):
        self.tipoArea = tipoArea

    def add_Area(self, area, app):
        try:
            conn = Conexion()
            query = f'''
                INSERT INTO area(tipoArea)
                VALUES('{area.tipoArea}')
            '''
            conn.ejecutar_sentencia(query)
            conn.commit()
            message = f'''Se agrego el area: {area.tipoA}'''
            return helper.handler_response(app, 201, message)
        except Exception as e:
            raise
            print(e)
        finally:
            conn.cerrar_conexion()

    def listar_Area(self, app):
        listado_area = []
        diccionario={}
        try:
            conn = Conexion()
            query = f'''
                SELECT * FROM area
            '''
            cursor = conn.ejecutar_sentencia(query)
            filas = cursor.fetchall()
            for fila in filas:
                listado_area.append({'id ':str(fila[0]), 'Cargo ': fila[1]})
            diccionario['Area'] = listado_area
            print(diccionario)
            return helper.handler_response(app, 201, diccionario)
        except Exception as e:
            raise
            print(e)
        finally:
            conn.cerrar_conexion()

    def obtener_Area(self, app, id_area):
        listado_area = []
        diccionario={}
        try:
            conn = Conexion()
            query = f'''
                SELECT * FROM area WHERE id={id_area}
            '''
            cursor = conn.ejecutar_sentencia(query)
            fila = cursor.fetchone()
            area = Area(fila[1])
            listado_area.append({'id ':str(fila[0]), 'Cargo ': area.tipoArea})
            diccionario['Area'] = listado_area
            return helper.handler_response(app, 201, diccionario)
        except Exception as e:
            raise
            print(e)
        finally:
            conn.cerrar_conexion()

    def actualizar_Area(self, app, id_area, area):
        try:
            conn = Conexion()
            query = f'''
                UPDATE area
                SET tipoArea = '{id_area.tipoArea}'
                WHERE id = {id_area}
            '''
            conn.ejecutar_sentencia(query)
            conn.commit()
            proces = 'Procesado'
            return helper.handler_response(app, 201, proces)
        except Exception as e:
            raise
            print(e)
        finally:
            conn.cerrar_conexion()

    def eliminar_Area(self, app, id_area):
        try:
            conn = Conexion()
            query = f'''
                DELETE FROM area WHERE id={id_area}
            '''
            cursor = conn.ejecutar_sentencia(query)
            conn.commit()
            eliminado = 'Eliminado...'
            return helper.handler_response(app, 201, eliminado)
        except Exception as e:
            raise
            print(e)
        finally:
            conn.cerrar_conexion()


from lib.get_endpoint import call_endpoint, endpoints
from lib.utils import format_response, trace

endpoint_inputs = {
    "headers": {
        "Content-Type": "application/json"
    }
}

@trace(text="Delete company tasks")
def delete_tasks(command_args: dict):
    """
    Function compiles a list of tasks associated with a companyid that is supplied to the the deleteCompanyTasks endpoint
    in order to delete all tasks associated with a client
    :return: endpoint call response object
    """
    # Check required argument
    assert command_args.get('companyid'), "Required argument 'companyid' is missing"

    # Find count
    search_args = {"companyid": command_args.get('companyid')}
    endpoint_inputs["args"] = search_args
    endpoint_inputs['json'] = search_args
    count_response = call_endpoint(endpoint_config=endpoints.company_tasks_svc.countCompanyTasks,
                                   command_args=command_args,
                                   **endpoint_inputs)
    actual_count = count_response.data.get('content')
    if actual_count == 0:
        print("Client has no tasks.")
        return
    # Search task Ids
    search_args["pageRequest"] = {"size": actual_count}
    search_response = call_endpoint(endpoint_config=endpoints.company_tasks_svc.getCompanyTasks,
                                    command_args=command_args,
                                    **endpoint_inputs)
    if search_response.status == 404:
        print(search_response.data['errors'][0]['description'])
        return
    # Delete all task Ids
    ids = [company_task['id'] for company_task in search_response.data['content']]
    if ids:
        endpoint_inputs['json'] = ids
        delete_response = call_endpoint(endpoint_config=endpoints.company_tasks_svc.deleteCompanyTasks,
                                        command_args=command_args,
                                        **endpoint_inputs)
        assert search_response.status == 200, f"Delete operation failed! Error: {format_response(delete_response)}"
    print(f"{actual_count} Company tasks deleted successfully! Now, Client has no tasks.")


import pyaudio
import wave
import pydub
import numpy as np
import os
import threading
import random
import time
import sys
freq = 60 #60秒おきに集中力を計算
excert_range = 5 #その５倍の時間の姿勢データを計算に使う
global position
position = [4] * freq*excert_range  #####集中力を計算するために姿勢を格納する配列(最初は非集中なので姿勢4を入れてる)

def get_position_seq():
    global position
    n = len(position)
    i = 0
    while True:
        position[i] = 1 ##############ここに姿勢を入れる####################
        print("姿勢は",position[i])
        i += 1
        if(i == n):
            i = 0
        time.sleep(1) ##1秒ディレイを入れてる(多分いらない)

def concentration_rate(sequence): ###集中力を計算する(関数は適当)
    counts = [0, 0, 0, 0]
    for num in sequence:
        if num == 1:
            counts[0] += 1
        elif num == 2:
            counts[1] += 1
        elif num == 3:
            counts[2] += 1
        elif num == 4:
            counts[3] += 1
    concentrate_raw = (counts[0]+counts[1]*0.2)/(len(sequence))
    if concentrate_raw >= 0.7:  ##集中力はせいぜい0.7が最大と仮定
        concentrate = 1
    else:
        concentrate = concentrate_raw/0.7
    print("集中力は",concentrate)
    return concentrate

def choose_music(concentration,threshold):  ##集中力に応じて音楽を選ぶ
    folder_path = os.path.dirname(os.path.abspath(sys.argv[0]))
    #上がる方
    if concentration < threshold:
        mp3_folder_path = os.path.join(folder_path, "no_concentrate_music")
        mp3_files = [file for file in os.listdir(mp3_folder_path) if file.endswith(".mp3")]
        random_file = random.choice(mp3_files)
        file_path = os.path.join(mp3_folder_path, random_file)
        print("上がる音楽",file_path,"を再生します")
    #集中できる方
    else:
        mp3_folder_path = os.path.join(folder_path, "concentrate_music")
        mp3_files = [file for file in os.listdir(mp3_folder_path) if file.endswith(".mp3")]
        random_file = random.choice(mp3_files)
        file_path = os.path.join(mp3_folder_path, random_file)
        print("集中できる音楽",file_path,"を再生します")
    return file_path

def volume(raw_volume):     ##dBに基づいて適切な音量に変える
    min_volume = 0.1
    return (10**(raw_volume*-0.5)-10**-0.5+min_volume)/(1-10**-0.5+min_volume)

def play_audio(freq):   ##音楽を再生する、音量は1秒おきに少しずつ滑らかに変わるようになってる(中断ボタンに合わせて再生を終了するとかは未実装)
    global position
    global event
    decay = int(freq/2)
    threshold_0 = 0.1 ##これを下回ったら非集中と仮定
    threshold_1 = 0.5 ##これを上回ったら集中と仮定
    n = 0
    concentration_1 = 0
    while True:
        if event == "end":
            break
        file_path = choose_music(concentration_1,threshold_0)
        # WAV形式に変換
        wav_file = file_path[:-4] + ".wav"
        sound = pydub.AudioSegment.from_mp3(file_path)
        sound.export(wav_file, format="wav")

        # WAVファイルを再生
        wf = wave.open(wav_file, 'rb')
        chunk = wf.getframerate()

        # PyAudioの初期化
        p = pyaudio.PyAudio()
        stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                        channels=wf.getnchannels(),
                        rate = chunk,
                        output=True)

        # 音声のストリームを再生
        data = wf.readframes(chunk)
        concentration_origin = concentration_1
        print("最初の集中力は",concentration_origin)
        while data:

            # 入力値に基づいて音量を調整
            concentration_0 = concentration_1
            concentration_1 = concentration_rate(position)
            n += freq

            if concentration_origin < threshold_0 and concentration_1 > threshold_1:
                break

            elif concentration_origin > threshold_1 and concentration_1 < threshold_0:
                break

            concentration_step = (concentration_1 - concentration_0)/decay
            raw_volume = concentration_0
            raw_volume += concentration_step
            for i in range(decay):
                # バイナリデータをnumpy配列に変換
                audio_array = np.frombuffer(data, dtype=np.int16)
                volume_factor = volume(raw_volume)
                print("音量は",volume_factor)
                adjusted_array = (audio_array * volume_factor).astype(np.int16)

                # 音声データをバイナリに戻す
                adjusted_data = adjusted_array.tobytes()

                # 調整済みの音声を再生

                stream.write(adjusted_data)

                # 次のデータを読み込む
                data = wf.readframes(chunk)

                raw_volume += concentration_step

                #########ここに中断ボタンを押されたらループを抜けるコード??
                if event == "end":
                    break
            if event == "end":
                break
            volume_factor = volume(raw_volume)

            for i in range(freq - decay):
                # バイナリデータをnumpy配列に変換
                audio_array = np.frombuffer(data, dtype=np.int16)
                print("音量は",volume_factor)
                adjusted_array = (audio_array * volume_factor).astype(np.int16)

                # 音声データをバイナリに戻す
                adjusted_data = adjusted_array.tobytes()

                # 調整済みの音声を再生

                stream.write(adjusted_data)

                # 次のデータを読み込む
                data = wf.readframes(chunk)

                #########ここに中断ボタンを押されたらループを抜けるコード??
                if event == "end":
                    break
            if event == "end":
                break

        # ストリームを閉じる
        stream.stop_stream()
        stream.close()

        # PyAudioを終了する
        p.terminate()

        # 一時的に作成したWAVファイルを削除
        os.remove(wav_file)

        #########ここに中断ボタンを押されたらループを抜けるコード??
        if event == "end":
            break

# メインの処理
if __name__ == "__main__":
    # ロックオブジェクトを作成
    lock = threading.Lock()

    # スレッドを作成
    t1 = threading.Thread(target=get_position_seq)
    t2 = threading.Thread(target=play_audio, args=(freq,))

    # スレッドを開始
    t1.start()
    t2.start()


from django.forms import ModelForm, TextInput
from django import forms
from .models import List

class ListForm(ModelForm):
    class Meta:
        model = List
        fields = ['list']
        widgets = {'task': TextInput(attrs={
                'class': 'form-control',
                'name': 'list',
                'id': 'list',
                'placeholder': 'List'
            }),
            }


import sys

from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon
from qtasync import AsyncTask, coroutine
from PyQt5.QtCore import QCoreApplication, Qt,QThread
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from core import fmaker
import random
from planmaker import make_plan
import numpy as np
import asyncio
class App(QWidget):
    fmaker_ =0
    def __init__(self):
        super().__init__()
        self.left = 400
        self.top = 400
        self.title = 'PyQt5 matplotlib example - pythonspot.com'
        self.width = 800
        self.height = 600
        self.fmaker_ = fmaker()
        self.plan=[[],[]]
        self.initUI()

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.center()
        hbox = QHBoxLayout(self)

        topleft = QSplitter(Qt.Vertical)
        topleft.setFrameShape(QFrame.StyledPanel)

        splitbutton = QSplitter(Qt.Horizontal)
        splitbutton.setFrameShape(QFrame.StyledPanel)

        splitter1 = QSplitter(Qt.Horizontal)
        splitter1.addWidget(topleft)
        topleft.addWidget(splitbutton)

        parts= []
        for i in range(3):
            parts.append(QSplitter(Qt.Horizontal))
            parts[i].setFrameShape(QFrame.StyledPanel)
            topleft.addWidget(parts[i])

        hbox.addWidget(splitter1)

        self.setLayout(hbox)
        self.setWindowTitle('Синтез непрерывных D-планов для нечетких моделей с тремя подобластями')
        self.m = PlotCanvas(splitter1, width=5, height=4)
        self.m.move(0,0)
        self.radiobutton = []

        dic = ["в первом","во втором", "в третьем"]
        for i in range(3):
            grid = QGridLayout()
            group_box = QGroupBox("Модель "+dic[i]+" нечетком множестве")
            group_box.setLayout(grid)

            self.radiobutton.append(QRadioButton("Квадратичная"))
            self.radiobutton[i * 2].setChecked(True)
            self.radiobutton[i * 2].type = "quad"
            self.radiobutton[i * 2].toggled.connect(self.on_radio_button_toggled1)

            self.radiobutton.append(QRadioButton("Линейная"))
            self.radiobutton[i * 2 + 1].type = "lin"
            self.radiobutton[i * 2 + 1].toggled.connect(self.on_radio_button_toggled1)
            parts[i].addWidget(group_box)
            grid.addWidget(self.radiobutton[i * 2],1,1)
            grid.addWidget(self.radiobutton[i * 2 + 1],2,1)

        button = QPushButton('Сформировать план')
        button.clicked.connect(self.start_calculations)
        splitbutton.addWidget(button)
        self.show()

    def on_radio_button_toggled1(self):
        radiobutton = self.sender()

        if radiobutton.isChecked():
            self.fmaker_.change_model((self.radiobutton.index(radiobutton)+1)//3, radiobutton.type)

    @coroutine
    def start_calculations(self,arg):
        button = self.sender()
        button.setText('Производятся вычисления')
        button.setEnabled(False)
        for rb in self.radiobutton:
            rb.setEnabled(False)
        self.plan  = yield AsyncTask(make_plan,self.fmaker_,button)
        self.m.plot(self.plan)
        file = open('plan.txt','w')
        for i in range(len(self.plan[0])):
            file.write(str(self.plan[0][i]) + '\t' + str(self.plan[1][i]) + '\n')
        file.close()
        button.setText('Сформировать план')

        button.setEnabled(True)
        for rb in self.radiobutton:
            rb.setEnabled(True)

class PlotCanvas(FigureCanvas):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                QSizePolicy.Expanding,
                QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

    def plot(self, plan):
        data = [random.random() for i in range(25)]
        self.axes.cla()
        self.axes.scatter( x = plan[0], y = [0 for _ in plan[0]],
                          s = 5e3 * np.array(plan[1]), c = np.random.rand(len(plan[0])),
                          alpha = 0.5,
                          label = 'Веса точек в плане')
        self.axes.scatter( x = [0], y = [0],
                          s = 0,
                          alpha = 0.0,
                          label = '|M| = ' + str(plan[2]))
        plt.ylim(-1,1)
        self.axes.legend()
        for i, num in enumerate(plan[1]):
            self.axes.annotate(round(num,3), (plan[0][i]-0.05,plan[1][i]/40))
        self.axes.set_title('План эксперимента')
        self.axes.grid()
        self.draw()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())