# https://orange3.readthedocs.io/projects/orange-development/en/latest/tutorial-settings.html
import os
import sys

import Orange.data
from Orange.data import ContinuousVariable, Domain
from Orange.data.table import Table
from Orange.widgets import widget
from Orange.widgets.utils.signals import Input, Output


if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
    from Orange.widgets.orangecontrib.AAIT.optimiser import optuna_multi
    from Orange.widgets.orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file
else:
    from orangecontrib.AAIT.optimiser import optuna_multi
    from orangecontrib.AAIT.utils.initialize_from_ini import apply_modification_from_python_file


@apply_modification_from_python_file(filepath_original_widget=__file__)
class Optimisation(widget.OWWidget):
    name = "Optimization"
    description = "Optimization with optuna"
    icon = "icons/owoptimisation.svg"
    category = "AAIT - ALGORITHM"
    if "site-packages/Orange/widgets" in os.path.dirname(os.path.abspath(__file__)).replace("\\", "/"):
        icon = "icons_dev/owoptimisation.svg"



    priority = 1020
    dossier_du_script = os.path.dirname(os.path.abspath(__file__))
    want_control_area = False
    partie_1 = ""
    partie_2 = ""
    CaptionDuLabelPourGoto = ""
    AddAcondition = 0
    liste_a_afficher_comboBox_selection_label = []

    class Inputs:
        data_search_space = Input("Search Space Limits", Orange.data.Table)
        data_number_iterations = Input("Number of iterations", Orange.data.Table)
        data_previous_study = Input("Previous Study Data", Orange.data.Table)

    class Outputs:
        data_out = Output("Data", Orange.data.Table)
        best_trial_out = Output("Best trial", Orange.data.Table)
        current_proposition_out = Output("Current proposition (preview)", Orange.data.Table)
        studies_out = Output("Last Studies ", Orange.data.Table, auto_summary=False)
        out_pointer = Output("begin of the loop", str, auto_summary=False)  # sended as the widget is created
        out_pointer1 = Output("Send study for the loop", str, auto_summary=False)  # sended as the widget is created

    @Inputs.data_number_iterations
    def set_data_number_iterations(self, dataset):
        if dataset is not None:
            self.current_data_number_iterations = dataset[0][0]
            self.compteur_iteration = 1
            # pour relancer une etude
            self.itere(score=None)

    @Inputs.data_search_space
    def set_data_search_space(self, dataset):
        if dataset is not None:
            self.current_data_search_space = dataset
            self.len_file_current_data_search_space = len(dataset)

    @Inputs.data_previous_study
    def set_data_previous_study(self, dataset):
        self.current_data_previous_study = dataset


    # on lance l'étude et définition des data table en sortie
    def launch_study(self, score):
        ligne_best_etude, data, domain, current_proposition_out = optuna_multi.launch_study(score, self.len_score, self.current_data_search_space, self.current_data_previous_study, self.stop)

        if ligne_best_etude != []:
            table_best_etude = Table.from_list(Domain([ContinuousVariable(h) for h in domain]), ligne_best_etude)
            self.Outputs.best_trial_out.send(table_best_etude)

        if current_proposition_out != []:
            self.table = Table.from_list(Domain([ContinuousVariable(h) for h in domain]), current_proposition_out)
            self.Outputs.current_proposition_out.send(self.table)

        self.current_data_previous_study = Table.from_list(Domain([ContinuousVariable(h) for h in domain]), data[3:])
        self.Outputs.studies_out.send(self.current_data_previous_study)

        if self.stop == True:
            self.stop = False
            return

    def change_last_ligne(self, data=[]):
        if data == []:
            return

        if self.current_data_previous_study is not None:
            new_ligne = []
            for i in range(len(data.domain.attributes)):
                if data[0][i] == '?':
                    new_ligne.append("?")
                else:
                    # si le pas est défini dans le fichier d'entrée on gère le pas pour éviter toute cassure avec optuna
                    if len(self.current_data_search_space) == 3:
                        new_value = round(data[0][i].value / self.current_data_search_space[2][i].value) * self.current_data_search_space[2][i].value
                        data[0][i] = new_value
                    new_ligne.append(data[0][i].value)

            replace = False
            for i in range(len(data.domain.attributes)):
                if self.current_data_previous_study[-1][i] == '?':
                    replace = True
            #modification de la dernière ligne
            if replace == True:
                self.current_data_previous_study[-1] = new_ligne

            #ajout d'une nouvelle étude
            else:
                data = []
                for i in range(len(self.current_data_previous_study)):
                    d = []
                    for j in range(len(self.current_data_previous_study.domain)):
                        d.append(self.current_data_previous_study[i][j].value)

                    data.append(d)
                data.append(new_ligne)
                self.current_data_previous_study = Table.from_list(self.current_data_previous_study.domain,
                                                                    data)

            self.Outputs.studies_out.send(self.current_data_previous_study)

    # appelé depuis un focntion tierce
    def itere(self, score=[]):
        if self.current_data_search_space is None:
            print('Erreur il n y a pas de paramètres de configuration en entree')
            return

        if self.current_data_number_iterations is None:
            if self.compteur_iteration > 10:
                self.stop = True
        else:
            if self.compteur_iteration > self.current_data_number_iterations:
                self.stop = True

        self.compteur_iteration = self.compteur_iteration + 1

        # dans le cas du chargement d'une ancienne étude
        if self.current_data_previous_study is not None:
            self.len_score = len(self.current_data_previous_study.domain) - len(self.current_data_search_space.domain)

        if score is not None:
            new_score = []
            for i in range(len(score[0])):
                if score[0][i] != '?':
                   new_score.append(score[0][i].value)
            # ajouter car le feature constructor peut garder les anciens scores
            if self.len_score is None:
                self.len_score = len(new_score)

            #if len(new_score) != self.len_score:
                #print('Erreur les nombres de scores entre les études sont différents')
                #return
            self.launch_study(new_score)

        else:
            self.launch_study(score)



    def __init__(self):

        self.current_data_standard_input = None
        self.current_data_search_space = None
        self.current_data_previous_study = None
        self.current_data_number_iterations = None
        self.etude = None
        self.stop = False
        self.len_score = None
        self.table = None
        # compteur_iteration
        self.compteur_iteration = 1
        self.len_file_current_data_search_space = 0

        # on envoie l identifiant pour pouvoir boucler
        self.Outputs.out_pointer.send(str(id(self)))

        # on envoie l identifiant pour pouvoir boucler
        self.Outputs.out_pointer1.send(str(id(self)))

        super().__init__()  # je pense que c'est pour garder les config entre deux executions


        self.setFixedWidth(480)
        self.setFixedHeight(354)
        self.setAutoFillBackground(True)


if __name__ == "__main__":
    from AnyQt.QtWidgets import QApplication
    app = QApplication(sys.argv)
    mon_objet = Optimisation()
    mon_objet.show()
    if hasattr(app, "exec"):
        app.exec()
    else:
        app.exec_()



