import Chemins
from Utils import UTILS_Adaptations
from Utils.UTILS_Traduction import _
import wx
from Ctrl import CTRL_Bouton_image
import GestionDB

from Ctrl import CTRL_Saisie_date
from Ctrl import CTRL_Saisie_euros
from Dlg.DLG_Saisie_lot_conso import CTRL_Jours
from Ol import OL_Aides_montants

class CTRL_Activite(wx.Choice):
    def __init__(self, parent, IDfamille=None):
        wx.Choice.__init__(self, parent, -1)
        self.parent = parent
        self.IDfamille = IDfamille
        self.MAJ()

    def MAJ(self):
        listeItems = self.GetListeDonnees()
        if len(listeItems) == 0 :
            self.Enable(False)
        self.SetItems(listeItems)

    def GetListeDonnees(self):
        db = GestionDB.DB()
        if self.IDfamille == None :
            # Pour les modèles
            req = """SELECT IDactivite, nom
            FROM activites
            ORDER BY activites.nom;"""
        else:
            # Pour les aides aux familles
            req = """SELECT IDactivite, activites.nom
            FROM activites
            ORDER BY activites.date_fin DESC;"""
        db.ExecuterReq(req)
        listeDonnees = db.ResultatReq()
        db.Close()
        listeItems = []
        self.dictDonnees = {}
        index = 0
        for IDactivite, nom in listeDonnees :
            if nom == None: nom = ""
            self.dictDonnees[index] = {"ID": IDactivite, "nom ": nom}
            listeItems.append(nom)
            index += 1
        return listeItems

    def SetID(self, ID=0):
        for index, values in self.dictDonnees.items():
            if values["ID"] == ID :
                 self.SetSelection(index)

    def GetID(self):
        index = self.GetSelection()
        if index == -1 : return None
        return self.dictDonnees[index]["ID"]

# -----------------------------------------------------------------------------------------------------------------------

class CTRL_Caisse(wx.Choice):
    def __init__(self, parent, IDfamille=None):
        wx.Choice.__init__(self, parent, -1)
        self.parent = parent
        self.IDfamille = IDfamille
        self.MAJ()

    def MAJ(self):
        listeItems = self.GetListeDonnees()
        if len(listeItems) == 0 :
            self.Enable(False)
        self.SetItems(listeItems)

    def GetListeDonnees(self):
        listeItems = []
        self.dictDonnees = {}
        self.dictDonnees[0] = { "ID" : None, "nom " : _(u"- Aucune caisse -") }
        listeItems.append(_(u"- Aucune caisse -"))
        db = GestionDB.DB()
        req = """SELECT IDcaisse, nom
        FROM caisses
        ORDER BY nom;"""
        db.ExecuterReq(req)
        listeDonnees = db.ResultatReq()
        db.Close()
        index = 1
        for IDcaisse, nom in listeDonnees :
            self.dictDonnees[index] = { "ID" : IDcaisse, "nom " : nom}
            listeItems.append(nom)
            index += 1
        return listeItems

    def SetID(self, ID=0):
        for index, values in self.dictDonnees.items():
            if values["ID"] == ID :
                 self.SetSelection(index)

    def GetID(self):
        index = self.GetSelection()
        if index == -1 : return None
        return self.dictDonnees[index]["ID"]

# -----------------------------------------------------------------------------------------------------------------------

class CTRL_Beneficiaires(wx.CheckListBox):
    def __init__(self, parent, IDfamille=None, IDactivite=None):
        wx.CheckListBox.__init__(self, parent, -1, size=(-1, 60))
        self.parent = parent
        self.IDfamille = IDfamille
        self.IDactivite = IDactivite
        self.data = []
        if self.IDfamille == None :
            self.Enable(False)
        else:
            self.MAJ()

    def MAJ(self):
        if self.IDactivite == None :
            IDactivite = 0
        else:
            IDactivite = self.IDactivite
        db = GestionDB.DB()
        # req = """SELECT rattachements.IDindividu, individus.nom, individus.prenom
        # FROM rattachements
        # LEFT JOIN individus ON individus.IDindividu = rattachements.IDindividu
        # LEFT JOIN inscriptions ON inscriptions.IDindividu = rattachements.IDindividu
        # WHERE rattachements.IDfamille=%d AND IDcategorie IN (1, 2)
        # AND inscriptions.IDactivite=%d
        # ORDER BY individus.nom, individus.prenom;""" % (self.IDfamille, IDactivite)
        req = """SELECT rattachements.IDindividu, individus.nom, individus.prenom
        FROM rattachements
        LEFT JOIN individus ON individus.IDindividu = rattachements.IDindividu
        WHERE rattachements.IDfamille=%d AND IDcategorie IN (1, 2)
        ORDER BY individus.nom, individus.prenom;""" % self.IDfamille

        db.ExecuterReq(req)
        listeDonnees = db.ResultatReq()
        db.Close()
        listeValeurs = []
        for IDindividu, nom, prenom in listeDonnees :
            if prenom == None : prenom = u""
            listeValeurs.append((IDindividu, u"%s %s" % (nom, prenom), False))
        self.SetData(listeValeurs)

    def SetIDactivite(self, IDactivite=None):
        self.IDactivite = IDactivite
        self.MAJ()

    def SetData(self, listeValeurs=[]):
        """ items = (ID, label, checked) """
        self.data = []
        index = 0
        self.Clear()
        for ID, label, checked in listeValeurs:
            self.data.append((ID, label))
            self.Append(label)
            if checked == True :
                self.Check(index)
            index += 1

    def GetIDcoches(self):
        listeIDcoches = []
        NbreItems = len(self.data)
        for index in range(0, NbreItems):
            if self.IsChecked(index):
                listeIDcoches.append(self.data[index][0])
        return listeIDcoches

    def SetIDcoches(self, listeIDcoches=[]):
        index = 0
        for index in range(0, len(self.data)):
            ID = self.data[index][0]
            if ID in listeIDcoches :
                self.Check(index)
            index += 1

# -----------------------------------------------------------------------------------------------------------------

class Dialog(wx.Dialog):
    def __init__(self, parent, IDaide=None, IDfamille=None):
        wx.Dialog.__init__(self, parent, -1, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX)
        self.parent = parent
        self.IDaide = IDaide
        self.IDfamille = IDfamille

        self.listeInitialeBeneficiaires = []
        self.listeInitialeMontants = []
        self.listeInitialeCombi = []
        self.listeInitialeUnites = []

        # Nom
        self.label_nom = wx.StaticText(self, -1, _(u"Nom de l'aide :"))
        self.ctrl_nom = wx.TextCtrl(self, -1, u"")

        # Généralités
        self.staticbox_generalites_staticbox = wx.StaticBox(self, -1, _(u"Caractéristiques"))

        # Activité
        self.label_activite = wx.StaticText(self, -1, _(u"Activité associée :"))
        self.ctrl_activite = CTRL_Activite(self, IDfamille=self.IDfamille)

        # Caisse
        self.label_caisse = wx.StaticText(self, -1, _(u"Caisse associée :"))
        self.ctrl_caisse = CTRL_Caisse(self, IDfamille=self.IDfamille)

        # Période
        self.label_periode = wx.StaticText(self, -1, _(u"Période de validité :"))
        self.ctrl_date_debut = CTRL_Saisie_date.Date2(self)
        self.label_date_fin = wx.StaticText(self, -1, _(u"au"))
        self.ctrl_date_fin = CTRL_Saisie_date.Date2(self)

        # Jours
        self.label_scolaires = wx.StaticText(self, -1, _(u"Jours scolaires :"))
        self.ctrl_scolaires = CTRL_Jours(self, "scolaires")
        self.label_vacances = wx.StaticText(self, -1, _(u"Jours de vacances :"))
        self.ctrl_vacances = CTRL_Jours(self, "vacances")
        self.ctrl_scolaires.SetJoursStr("0;1;2;3;4;5;6")
        self.ctrl_vacances.SetJoursStr("0;1;2;3;4;5;6")

        # Plafonds
        self.label_plafonds = wx.StaticText(self, -1, _(u"Plafonds :"))
        self.checkbox_plafond_montant = wx.CheckBox(self, -1, _(u"Montant :"))
        self.ctrl_plafond_montant = CTRL_Saisie_euros.CTRL(self, size=(65, -1))
        self.checkbox_plafond_quantite = wx.CheckBox(self, -1, _(u"Quantité :"))
        self.ctrl_plafond_quantite = wx.SpinCtrl(self, -1, u"", min=0, max=1000, size=(60, -1))

        # Bénéficiaires
        self.staticbox_beneficiaires_staticbox = wx.StaticBox(self, -1, _(u"Bénéficiaires"))
        self.ctrl_beneficiaires = CTRL_Beneficiaires(self, IDfamille=self.IDfamille, IDactivite=None)
        self.ctrl_beneficiaires.SetMinSize((50, 80))

        # Montants
        self.staticbox_montants_staticbox = wx.StaticBox(self, -1, _(u"Montants"))
        self.ctrl_montants = OL_Aides_montants.ListView(self, id=-1, name="OL_montants", style=wx.LC_REPORT|wx.SUNKEN_BORDER|wx.LC_SINGLE_SEL|wx.LC_HRULES|wx.LC_VRULES)
        self.ctrl_montants.SetMinSize((50, 100))
        self.bouton_ajouter = wx.BitmapButton(self, -1, wx.Bitmap(Chemins.GetStaticPath(u"Images/16x16/Ajouter.png"), wx.BITMAP_TYPE_ANY))
        self.bouton_modifier = wx.BitmapButton(self, -1, wx.Bitmap(Chemins.GetStaticPath(u"Images/16x16/Modifier.png"), wx.BITMAP_TYPE_ANY))
        self.bouton_supprimer = wx.BitmapButton(self, -1, wx.Bitmap(Chemins.GetStaticPath(u"Images/16x16/Supprimer.png"), wx.BITMAP_TYPE_ANY))

        # Boutons
        self.bouton_aide = CTRL_Bouton_image.CTRL(self, texte=_(u"Aide"), cheminImage="Images/32x32/Aide.png")
        self.bouton_importer = CTRL_Bouton_image.CTRL(self, texte=_(u"Importer un modèle"), cheminImage="Images/32x32/Fleche_bas.png")
        self.bouton_ok = CTRL_Bouton_image.CTRL(self, texte=_(u"Ok"), cheminImage="Images/32x32/Valider.png")
        self.bouton_annuler = CTRL_Bouton_image.CTRL(self, id=wx.ID_CANCEL, texte=_(u"Annuler"), cheminImage="Images/32x32/Annuler.png")

        self.__set_properties()
        self.__do_layout()

        self.Bind(wx.EVT_CHECKBOX, self.OnCheckbox_plafond_montant, self.checkbox_plafond_montant)
        self.Bind(wx.EVT_CHECKBOX, self.OnCheckbox_plafond_quantite, self.checkbox_plafond_quantite)
        self.Bind(wx.EVT_BUTTON, self.OnBoutonAjouter, self.bouton_ajouter)
        self.Bind(wx.EVT_BUTTON, self.OnBoutonModifier, self.bouton_modifier)
        self.Bind(wx.EVT_BUTTON, self.OnBoutonSupprimer, self.bouton_supprimer)
        self.Bind(wx.EVT_BUTTON, self.OnBoutonAide, self.bouton_aide)
        self.Bind(wx.EVT_BUTTON, self.OnBoutonImporter, self.bouton_importer)
        self.Bind(wx.EVT_BUTTON, self.OnBoutonOk, self.bouton_ok)
        self.Bind(wx.EVT_CHOICE, self.OnChoixActivite, self.ctrl_activite)

        # Importation
        if self.IDaide != None :
            if self.IDfamille == None :
                self.SetTitle(_(u"Modification d'un modèle d'aide"))
            else:
                self.SetTitle(_(u"Modification d'une aide"))
            self.Importation()
        else:
            if self.IDfamille == None :
                self.SetTitle(_(u"Saisie d'un modèle d'aide"))
            else:
                self.SetTitle(_(u"Saisie d'une aide"))
            self.ctrl_montants.MAJ()

        # Init contrôles
        self.OnCheckbox_plafond_montant(None)
        self.OnCheckbox_plafond_quantite(None)

        if self.IDfamille == None :
            self.staticbox_beneficiaires_staticbox.Show(False)
            self.ctrl_beneficiaires.Show(False)
            self.bouton_importer.Show(False)

    def __set_properties(self):
        self.ctrl_nom.SetToolTip(wx.ToolTip(_(u"Saisissez ici le nom de l'aide (Exemple : 'Bons vacances CAF 2017')")))
        self.ctrl_activite.SetToolTip(wx.ToolTip(_(u"Sélectionnez ici l'activité")))
        self.ctrl_caisse.SetToolTip(wx.ToolTip(_(u"Sélectionnez ici une caisse")))
        self.ctrl_date_debut.SetToolTip(wx.ToolTip(_(u"Saisissez ici la date de début de validité")))
        self.ctrl_date_fin.SetToolTip(wx.ToolTip(_(u"Saisissez ici la date de fin de validité")))
        self.ctrl_beneficiaires.SetToolTip(wx.ToolTip(_(u"Cochez ici les bénéficiaires de l'aide")))
        self.checkbox_plafond_montant.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour appliquer un montant maximal")))
        self.ctrl_plafond_montant.SetToolTip(wx.ToolTip(_(u"Saisissez ici le montant maximal")))
        self.checkbox_plafond_quantite.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour appliquer un nombre de dates maximal")))
        self.ctrl_plafond_quantite.SetToolTip(wx.ToolTip(_(u"Cliquez ici le nombre maximal de dates")))
        self.bouton_ajouter.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour ajouter un montant")))
        self.bouton_modifier.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour modifier le montant sélectionné dans la liste")))
        self.bouton_supprimer.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour supprimer le montant sélectionné dans la liste")))
        self.bouton_aide.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour obtenir de l'aide")))
        self.bouton_importer.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour importer un modèle d'aide prédéfini")))
        self.bouton_ok.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour valider")))
        self.bouton_annuler.SetToolTip(wx.ToolTip(_(u"Cliquez ici pour annuler et fermer")))

    def __do_layout(self):
        grid_sizer_base = wx.FlexGridSizer(rows=5, cols=1, vgap=10, hgap=10)

        # Généralites
        staticbox_generalites = wx.StaticBoxSizer(self.staticbox_generalites_staticbox, wx.VERTICAL)
        grid_sizer_generalites = wx.FlexGridSizer(rows=7, cols=2, vgap=10, hgap=10)

        # Nom de l'aide
        grid_sizer_generalites.Add(self.label_nom, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_generalites.Add(self.ctrl_nom, 1, wx.EXPAND, 0)

        # Activité
        grid_sizer_generalites.Add(self.label_activite, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_generalites.Add(self.ctrl_activite, 1, wx.EXPAND, 0)

        # Caisse
        grid_sizer_generalites.Add(self.label_caisse, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_generalites.Add(self.ctrl_caisse, 1, wx.EXPAND, 0)

        # Période
        grid_sizer_generalites.Add(self.label_periode, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_periode = wx.FlexGridSizer(rows=1, cols=4, vgap=5, hgap=5)
        grid_sizer_periode.Add(self.ctrl_date_debut, 0, 0, 0)
        grid_sizer_periode.Add(self.label_date_fin, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_periode.Add(self.ctrl_date_fin, 0, 0, 0)
        grid_sizer_generalites.Add(grid_sizer_periode, 1, wx.ALL|wx.EXPAND, 0)

        # Jours
        grid_sizer_generalites.Add(self.label_scolaires, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_generalites.Add(self.ctrl_scolaires, 0, 0, 0)
        grid_sizer_generalites.Add(self.label_vacances, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_generalites.Add(self.ctrl_vacances, 0, 0, 0)

        # Plafonds
        grid_sizer_generalites.Add(self.label_plafonds, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_plafonds = wx.FlexGridSizer(rows=1, cols=5, vgap=0, hgap=0)
        grid_sizer_plafonds.Add(self.checkbox_plafond_montant, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_plafonds.Add(self.ctrl_plafond_montant, 0, 0, 0)
        grid_sizer_plafonds.Add((20, 20), 0, 0, 0)
        grid_sizer_plafonds.Add(self.checkbox_plafond_quantite, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        grid_sizer_plafonds.Add(self.ctrl_plafond_quantite, 0, 0, 0)
        grid_sizer_generalites.Add(grid_sizer_plafonds, 0, 0, 0)

        grid_sizer_generalites.AddGrowableCol(1)
        staticbox_generalites.Add(grid_sizer_generalites, 1, wx.ALL|wx.EXPAND, 5)
        grid_sizer_base.Add(staticbox_generalites, 1, wx.LEFT|wx.RIGHT|wx.TOP|wx.EXPAND, 10)

        # Bénéficiaires
        staticbox_beneficiaires = wx.StaticBoxSizer(self.staticbox_beneficiaires_staticbox, wx.VERTICAL)
        staticbox_beneficiaires.Add(self.ctrl_beneficiaires, 0, wx.ALL|wx.EXPAND, 5)
        grid_sizer_base.Add(staticbox_beneficiaires, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, 10)

        # Montants
        staticbox_montants = wx.StaticBoxSizer(self.staticbox_montants_staticbox, wx.VERTICAL)
        grid_sizer_montants = wx.FlexGridSizer(rows=1, cols=2, vgap=5, hgap=5)
        grid_sizer_boutons_montants = wx.FlexGridSizer(rows=3, cols=1, vgap=5, hgap=5)
        grid_sizer_montants.Add(self.ctrl_montants, 1, wx.EXPAND, 0)
        grid_sizer_boutons_montants.Add(self.bouton_ajouter, 0, 0, 0)
        grid_sizer_boutons_montants.Add(self.bouton_modifier, 0, 0, 0)
        grid_sizer_boutons_montants.Add(self.bouton_supprimer, 0, 0, 0)
        grid_sizer_montants.Add(grid_sizer_boutons_montants, 1, wx.EXPAND, 0)
        grid_sizer_montants.AddGrowableRow(0)
        grid_sizer_montants.AddGrowableCol(0)
        staticbox_montants.Add(grid_sizer_montants, 1, wx.ALL|wx.EXPAND, 5)
        grid_sizer_base.Add(staticbox_montants, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, 10)

        # Boutons
        grid_sizer_boutons = wx.FlexGridSizer(rows=1, cols=5, vgap=10, hgap=10)
        grid_sizer_boutons.Add(self.bouton_aide, 0, 0, 0)
        grid_sizer_boutons.Add(self.bouton_importer, 0, 0, 0)
        grid_sizer_boutons.Add((20, 20), 0, wx.EXPAND, 0)
        grid_sizer_boutons.Add(self.bouton_ok, 0, 0, 0)
        grid_sizer_boutons.Add(self.bouton_annuler, 0, 0, 0)
        grid_sizer_boutons.AddGrowableCol(2)
        grid_sizer_base.Add(grid_sizer_boutons, 1, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND, 10)

        self.SetSizer(grid_sizer_base)
        grid_sizer_base.Fit(self)
        grid_sizer_base.AddGrowableRow(2)
        grid_sizer_base.AddGrowableCol(0)
        self.Layout()
        self.SetMinSize(self.GetSize())
        self.CenterOnScreen()

    def OnChoixActivite(self, event):
        IDactivite = self.ctrl_activite.GetID()
        if self.IDfamille != None :
            self.ctrl_beneficiaires.SetIDactivite(IDactivite)
        self.ctrl_montants.SetIDactivite(IDactivite)

    def OnCheckbox_plafond_montant(self, event):
        if self.checkbox_plafond_montant.GetValue() == True :
            self.ctrl_plafond_montant.Enable(True)
        else:
            self.ctrl_plafond_montant.Enable(False)

    def OnCheckbox_plafond_quantite(self, event):
        if self.checkbox_plafond_quantite.GetValue() == True :
            self.ctrl_plafond_quantite.Enable(True)
        else:
            self.ctrl_plafond_quantite.Enable(False)

    def OnBoutonAjouter(self, event):
        self.ctrl_montants.Ajouter(None)

    def OnBoutonModifier(self, event):
        self.ctrl_montants.Modifier(None)

    def OnBoutonSupprimer(self, event):
        self.ctrl_montants.Supprimer(None)

    def OnBoutonAide(self, event):
        from Utils import UTILS_Aide
        UTILS_Aide.Aide("Caisse")

    def OnBoutonImporter(self, event):
        """ Importer un modèle d'aide """
        from Dlg import DLG_Choix_modele_aide
        dlg = DLG_Choix_modele_aide.Dialog(self)
        if dlg.ShowModal() == wx.ID_OK:
            self.IDaide = dlg.GetIDaide()
            self.Importation(modele=True)
            self.IDaide = None
        dlg.Destroy()

    def Importation(self, modele=False):
        # Importation des données sur l'aide
        DB = GestionDB.DB()
        req = """SELECT IDaide, IDfamille, IDactivite, nom, date_debut, date_fin, IDcaisse, montant_max, nbre_dates_max, jours_scolaires, jours_vacances
        FROM aides
        WHERE IDaide=%d
        ;""" % self.IDaide
        DB.ExecuterReq(req)
        listeDonnees = DB.ResultatReq()
        if len(listeDonnees) == 0 :
            DB.Close()
            return None
        IDaide, IDfamille, IDactivite, nom, date_debut, date_fin, IDcaisse, plafond_montant, nbre_plafond_quantite, jours_scolaires, jours_vacances = listeDonnees[0]

        # Activité
        self.ctrl_activite.SetID(IDactivite)
        if self.IDfamille != None :
            self.ctrl_beneficiaires.SetIDactivite(IDactivite)
        self.ctrl_montants.SetIDactivite(IDactivite)

        # Caisse
        self.ctrl_caisse.SetID(IDcaisse)

        # Nom
        self.ctrl_nom.SetValue(nom)

        # Dates de validité
        self.ctrl_date_debut.SetDate(date_debut)
        self.ctrl_date_fin.SetDate(date_fin)

        # Jours
        self.ctrl_scolaires.SetJoursStr(jours_scolaires)
        self.ctrl_vacances.SetJoursStr(jours_vacances)

        # Plafonds
        if plafond_montant != None :
            self.ctrl_plafond_montant.SetMontant(plafond_montant)
            self.checkbox_plafond_montant.SetValue(True)
        if nbre_plafond_quantite != None :
            self.ctrl_plafond_quantite.SetValue(nbre_plafond_quantite)
            self.checkbox_plafond_quantite.SetValue(True)

        # Bénéficiaires
        listeIDindividus = []
        if self.IDfamille != None :
            req = """SELECT IDaide_beneficiaire, IDindividu
            FROM aides_beneficiaires
            WHERE IDaide=%d;""" % self.IDaide
            DB.ExecuterReq(req)
            listeBeneficiaires = DB.ResultatReq()
            for IDaide_beneficiaire, IDindividu in listeBeneficiaires :
                listeIDindividus.append(IDindividu)
            self.ctrl_beneficiaires.SetIDcoches(listeIDindividus)
        self.listeInitialeBeneficiaires = list(listeIDindividus)

        # Combinaisons
        req = """SELECT
        aides_combi_unites.IDaide_combi_unite, aides_combi_unites.IDaide_combi, aides_combi_unites.IDunite,
        aides_combinaisons.IDaide_montant
        FROM aides_combi_unites
        LEFT JOIN aides_combinaisons ON aides_combinaisons.IDaide_combi = aides_combi_unites.IDaide_combi
        LEFT JOIN aides_montants ON aides_montants.IDaide_montant = aides_combinaisons.IDaide_montant
        WHERE aides_montants.IDaide=%d;""" % self.IDaide
        DB.ExecuterReq(req)
        listeUnites = DB.ResultatReq()
        dictCombinaisons = {}
        for IDaide_combi_unite, IDaide_combi, IDunite, IDaide_montant in listeUnites :
            dictUnite = {"IDaide_combi_unite" : IDaide_combi_unite, "IDunite" : IDunite}
            if (IDaide_montant in dictCombinaisons) == False :
                dictCombinaisons[IDaide_montant] = {}
            if (IDaide_combi in dictCombinaisons[IDaide_montant]) == False :
                dictCombinaisons[IDaide_montant][IDaide_combi] = { "IDaide_combi" : IDaide_combi, "listeUnites" : [] }
            if dictUnite not in dictCombinaisons[IDaide_montant][IDaide_combi]["listeUnites"] :
                dictCombinaisons[IDaide_montant][IDaide_combi]["listeUnites"].append(dictUnite)

            if IDaide_combi not in self.listeInitialeCombi : self.listeInitialeCombi.append(IDaide_combi)
            if IDaide_combi_unite not in self.listeInitialeUnites : self.listeInitialeUnites.append(IDaide_combi_unite)

        # Montants
        req = """SELECT IDaide_montant, montant
        FROM aides_montants
        WHERE IDaide=%d;""" % self.IDaide
        DB.ExecuterReq(req)
        listeDonnees = DB.ResultatReq()
        listeMontants = []
        for IDaide_montant, montant in listeDonnees :
            listeCombinaisons = []
            if IDaide_montant in dictCombinaisons :
                for IDaide_combi, dictCombi in dictCombinaisons[IDaide_montant].items() :
                    listeCombinaisons.append(dictCombi)
            dictMontant = { "IDaide_montant" : IDaide_montant, "montant" : montant , "combinaisons" : listeCombinaisons }
            listeMontants.append(dictMontant)
        self.listeInitialeMontants = list(listeMontants)

        # Si on vient d'importer un modèle, on supprime les ID de chaque champ
        if modele == True :

            self.listeInitialeMontants = []
            self.listeInitialeCombi = []
            self.listeInitialeUnites = []
            for dictMontant in listeMontants :
                dictMontant["IDaide_montant"] = None
                for dictCombi in dictMontant["combinaisons"] :
                    dictCombi["IDaide_combi"] = None
                    for dictUnite in dictCombi["listeUnites"] :
                        dictUnite["IDaide_combi_unite"] = None

        # Envoie les montants au listCtrl
        self.ctrl_montants.SetListeMontants(listeMontants)

        DB.Close()

    def GetIDaide(self):
        return self.IDaide

    def OnBoutonOk(self, event):
        # Récupération des données

        # Nom
        nom = self.ctrl_nom.GetValue()
        if nom == u"" :
            dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement saisir un nom !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            self.ctrl_nom.SetFocus()
            return

        # Activité
        IDactivite = self.ctrl_activite.GetID()
        if IDactivite == None :
            dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement sélectionner une activité !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            self.ctrl_activite.SetFocus()
            return

        # Caisse
        IDcaisse = self.ctrl_caisse.GetID()
##        if IDcaisse == None :
##            dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement saisir une caisse !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
##            dlg.ShowModal()
##            dlg.Destroy()
##            self.ctrl_caisse.SetFocus()
##            return

        # Dates de validité
        date_debut = self.ctrl_date_debut.GetDate()
        date_fin = self.ctrl_date_fin.GetDate()
        if date_debut == None :
            dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement saisir une date de début de validité !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            self.ctrl_date_debut.SetFocus()
            return
        if date_fin == None :
            dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement saisir une date de fin de validité !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            self.ctrl_date_fin.SetFocus()
            return
        if date_fin < date_debut :
            dlg = wx.MessageDialog(self, _(u"Vous avez saisi une date de début supérieure à la date de fin !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            return

        # Jours
        jours_scolaires = self.ctrl_scolaires.GetJoursStr()
        jours_vacances = self.ctrl_vacances.GetJoursStr()

        # Plafonds
        if self.checkbox_plafond_montant.GetValue() == True :
            plafond_montant = self.ctrl_plafond_montant.GetMontant()
            if plafond_montant == None or plafond_montant == 0.0 :
                dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement saisir un montant plafond !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
                dlg.ShowModal()
                dlg.Destroy()
                return
        else:
            plafond_montant = None
        if self.checkbox_plafond_quantite.GetValue() == True :
            nbre_plafond_quantite = int(self.ctrl_plafond_quantite.GetValue())
            if nbre_plafond_quantite == 0 :
                dlg = wx.MessageDialog(self, _(u"Vous devez obligatoirement saisir un de nombre de dates maximal !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
                dlg.ShowModal()
                dlg.Destroy()
                return
        else:
            nbre_plafond_quantite = None

##        if nbre_plafond_quantite != None :
##            self.ctrl_plafond_quantite.SetValue(str(nbre_plafond_quantite))
##            self.checkbox_plafond_quantite.SetValue(True)

        # Bénéficiaires
        listeBeneficiaires = self.ctrl_beneficiaires.GetIDcoches()
        if self.IDfamille != None :
            if len(listeBeneficiaires) == 0 :
                dlg = wx.MessageDialog(self, _(u"Vous sélectionner au moins un bénéficiaire dans la liste !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
                dlg.ShowModal()
                dlg.Destroy()
                return

        # Montants
        listeMontants = self.ctrl_montants.GetListeMontants()
        if len(listeMontants) == 0 :
            dlg = wx.MessageDialog(self, _(u"Vous n'avez saisi aucun montant !"), _(u"Erreur de saisie"), wx.OK | wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            dlg.Destroy()
            return

        # Sauvegarde de l'aide
        DB = GestionDB.DB()
        listeDonnees = [
            ("IDfamille", self.IDfamille ),
            ("IDactivite", IDactivite ),
            ("nom", nom ),
            ("date_debut", date_debut),
            ("date_fin", date_fin),
            ("IDcaisse", IDcaisse),
            ("montant_max", plafond_montant),
            ("nbre_dates_max", nbre_plafond_quantite),
            ("jours_scolaires", jours_scolaires),
            ("jours_vacances", jours_vacances),
        ]

        if self.IDaide == None :
            self.IDaide = DB.ReqInsert("aides", listeDonnees)
        else:
            DB.ReqMAJ("aides", listeDonnees, "IDaide", self.IDaide)

        # Sauvegarde des utilisateurs
        for IDindividu in listeBeneficiaires :
            if IDindividu not in self.listeInitialeBeneficiaires :
                listeDonnees = [("IDaide", self.IDaide ), ("IDindividu", IDindividu ),]
                DB.ReqInsert("aides_beneficiaires", listeDonnees)
        for IDindividu in self.listeInitialeBeneficiaires :
            if IDindividu not in listeBeneficiaires :
                req = """DELETE FROM aides_beneficiaires
                WHERE IDaide=%d AND IDindividu=%d;""" % (self.IDaide, IDindividu)
                DB.ExecuterReq(req)
                DB.Commit()

        # Sauvegarde des montants

##    DONNEES_TEST = {
##    "IDaide_montant" : None,
##    "montant" : 20.0,
##    "combinaisons" : [
##            { "IDaide_combi" : None, "listeUnites" :
##                [
##                {"IDaide_combi_unite" : None, "IDunite" : 35}, # Après-midi
##                {"IDaide_combi_unite" : None, "IDunite" : 33}, # Repas
##                ],
##            },
##            { "IDaide_combi" : None, "listeUnites" :
##                [
##                {"IDaide_combi_unite" : None, "IDunite" : 34}, # Matinée
##                {"IDaide_combi_unite" : None, "IDunite" : 33}, # Repas
##                ],
##            },
##        ],
##    }

        listeIDmontant = []
        listeIDcombi = []
        listeIDunites = []

        for dictMontant in listeMontants :
            IDaide_montant = dictMontant["IDaide_montant"]
            montant = dictMontant["montant"]
            listeCombinaisons = dictMontant["combinaisons"]

            # Sauvegarde des nouveau montants
            if IDaide_montant == None :
                listeDonnees = [ ("IDaide", self.IDaide), ("montant", montant), ]
                IDaide_montant = DB.ReqInsert("aides_montants", listeDonnees)
            else:
                # Enregistrement d'un montant modifié
                for dictMontantInitial in self.listeInitialeMontants :
                    if dictMontantInitial["IDaide_montant"] == IDaide_montant :
                        if dictMontantInitial["montant"] != montant :
                            DB.ReqMAJ("aides_montants", [("montant", montant),], "IDaide_montant", IDaide_montant)
                listeIDmontant.append(IDaide_montant)

            # Sauvegarde des unités de combi
            for dictCombi in listeCombinaisons :
                IDaide_combi = dictCombi["IDaide_combi"]
                listeUnites = dictCombi["listeUnites"]

                # Nouvelles combinaisons
                if IDaide_combi == None :
                    listeDonnees = [ ("IDaide_montant", IDaide_montant), ("IDaide", self.IDaide), ]
                    IDaide_combi = DB.ReqInsert("aides_combinaisons", listeDonnees)
                else:
                    listeIDcombi.append(IDaide_combi)

                # Nouvelles unités
                for dictUnite in listeUnites :
                    IDaide_combi_unite = dictUnite["IDaide_combi_unite"]
                    IDunite = dictUnite["IDunite"]

                    # Nouvelles combinaisons
                    if IDaide_combi_unite == None :
                        listeDonnees = [ ("IDunite", IDunite), ("IDaide_combi", IDaide_combi), ("IDaide", self.IDaide), ]
                        IDaide_combi_unite = DB.ReqInsert("aides_combi_unites", listeDonnees)
                    else:
                        listeIDunites.append(IDaide_combi_unite)

        # Suppression des montants supprimés
        for dictMontantInitial in self.listeInitialeMontants :
            if dictMontantInitial["IDaide_montant"] not in listeIDmontant and dictMontantInitial["IDaide_montant"] != None :
                DB.ReqDEL("aides_montants", "IDaide_montant", dictMontantInitial["IDaide_montant"])

        # Suppression des combinaisons supprimées :
        for IDaide_combi in self.listeInitialeCombi :
            if IDaide_combi not in listeIDcombi and IDaide_combi != None :
                DB.ReqDEL("aides_combinaisons", "IDaide_combi", IDaide_combi)

        # Suppression des unités de combi supprimées
        for IDaide_combi_unite in self.listeInitialeUnites :
            if IDaide_combi_unite not in listeIDunites and IDaide_combi_unite != None :
                DB.ReqDEL("aides_combi_unites", "IDaide_combi_unite", IDaide_combi_unite)

        DB.Close()

        # Fermeture de la fenêtre
        self.EndModal(wx.ID_OK)

if __name__ == u"__main__":
    app = wx.App(0)
    #wx.InitAllImageHandlers()
    dialog_1 = Dialog(None, IDaide=1, IDfamille=205)
    app.SetTopWindow(dialog_1)
    dialog_1.ShowModal()
    app.MainLoop()

{'UTILS_Aide': 'Utils.UTILS_Aide', 'DLG_Choix_modele_aide': 'Dlg.DLG_Choix_modele_aide'}


from typing import Optional, List

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
        if not root:
            return []

        stack = [root]
        res = []

        while stack:
            lvl = []
            for _ in range(len(stack)):
                n = stack.pop(0)
                lvl.append(n.val)
                if n.left:
                    stack.append(n.left)
                if n.right:
                    stack.append(n.right)
            res.append(lvl)

        return res


import grpc
import time
import multiprocessing
from .stubs import daemon_pb2
from .stubs import daemon_pb2_grpc
from concurrent import futures
from distutils.util import strtobool
from ..common.log import get_logger
from ..management.engine import dryrun, engine_server
from ..management.notebook import notebook, lab
from ..management.test import test, tox, tdd

logger = get_logger('daemon_base.command_server')

command_list = ['DRYRUN', 'TEST', 'TDD',
                'TOX', 'NOTEBOOK', 'LAB', 'GRPC']

def call_dryrun(config, parameters):
    profiling = strtobool(parameters['profiling'])

    dryrun(config, parameters['action'], bool(profiling))

def call_grpc(config, parameters):
    max_workers = int(parameters['max_workers']) if parameters['max_workers'] else multiprocessing.cpu_count()
    max_rpc_workers = int(parameters['max_rpc_workers']) if parameters['max_rpc_workers'] else multiprocessing.cpu_count()

    return engine_server(config, parameters['action'], max_workers,
                        max_rpc_workers)

def call_notebook(config, parameters):

    notebook(config, parameters['port'])

def call_lab(config, parameters):

    lab(config, parameters['port'])

def call_test(config, parameters):
    cov = strtobool(parameters['cov'])
    no_capture = strtobool(parameters['no_capture'])
    pdb = strtobool(parameters['pdb'])

    test(config, bool(cov), bool(no_capture), bool(pdb), parameters['args'])

def call_tdd(config, parameters):
    cov = strtobool(parameters['cov'])
    no_capture = strtobool(parameters['no_capture'])
    pdb = strtobool(parameters['pdb'])
    partial = strtobool(parameters['partial'])

    tdd(config, bool(cov), bool(no_capture), bool(
        pdb), bool(partial), parameters['args'])

def call_tox(config, parameters):
    tox(config, parameters['args'])

CALLS = {
    'DRYRUN': call_dryrun,
    'TEST': call_test,
    'TDD': call_tdd,
    'TOX': call_tox,
    'NOTEBOOK': call_notebook,
    'LAB': call_lab,
    'GRPC': call_grpc
}

class CommandServicer(daemon_pb2_grpc.CommandCall):

    def __init__(self, config):
        self.config = config
        self.command_running = None
        self.command_processes = None

    def callCommand(self, request, context):
        response = daemon_pb2.Status()
        self.command_running = command_list[request.command]
        command_call = CALLS[self.command_running]

        try:
            logger.info("Command {0} called!".format(self.command_running))
            self.command_processes = command_call(
                self.config, request.parameters)
            logger.info("Command {0} successful!".format(self.command_running))
            print(self.command_processes)
            if not self.command_processes:
                self.command_running = None
            response.status = daemon_pb2.Status.StatusType.OK
        except:
            logger.exception(
                "Command {0} failed!".format(self.command_running))
            response.status = daemon_pb2.Status.StatusType.NOK

        return response

    def stopCommand(self, request, context):
        response = daemon_pb2.Status()

        try:
            n_servers = 1
            for server in self.command_processes:
                logger.info("{0} servers terminated.".format(n_servers))
                server.stop(0)
                n_servers += 1
            logger.info("Command {0} terminated.".format(self.command_running))
            self.command_running = None
            self.command_processes = None
            response.status = daemon_pb2.Status.StatusType.OK
        except:
            logger.exception(
                "Unable to stop command: {0}.".format(self.command_running))
            response.status = daemon_pb2.Status.StatusType.NOK

        return response

    def getState(self, request, response):
        response = daemon_pb2.State()

        response.engine_name = self.config['marvin_package']
        response.command = 'None' if not self.command_running else self.command_running

        return response

def init_server(config):
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=multiprocessing.cpu_count()))

    daemon_pb2_grpc.add_CommandCallServicer_to_server(
        CommandServicer(config), server)

    logger.info('Starting server. Listening on port 50057.')
    server.add_insecure_port('[::]:50057')
    server.start()

    try:
        while True:
            time.sleep(10)
    except KeyboardInterrupt:
        server.stop(0)


#!/usr/bin/python3
import glob
import xlwt
import os
from xlwt import Workbook
import datetime
from repo import repo_lib, jrt_repo

HEADER_STRING = 	"#TEST_DESCR_START\n\
#NAME_single_ln()\n\
#VERSION_single_ln()\n\
#MODULE_NAME_single_ln()\n\
#PLATFORM_single_ln()\n\
#SUMMARY_single_ln()\n\
#DESCRIPTION_multi_ln()\n\
#PASS-CRITERIA_single_ln(Pass: )\n\
#TEST_DESCR_END"

# WORKSPACE = '/mnt/c/code/jenkins-regression-tests/regression-suites/'
# WORKBOOKPATH = '/mnt/c/code/jrt-testplan/'
TESTPLAN_FILENAME = 'Testplan.xls'

jobStr = ['NAME', 'VERSION', 'MODULE_NAME', 'PLATFORM', 'SUMMARY', 'DESCRIPTION', 'PASS-CRITERIA', 'wner']
excelColumn = ['S.No', 'Module Name', 'Test Name',  'Test Summary', 'Owner', 'Description', 'Platform', 'Version', 'Pass-Criteria']

colNameStr = []
colSummStr = []
colCritStr = []
colVerStr = []
colSubDir = []

class jenkinsJobs():
	def __init__(self):
		self.enable_print = False

		self.name_str = ""
		self.ver_str = ""
		self.mod_str = ""
		self.plat_str = ""
		self.summ_str = ""
		self.desc_str = ""
		self.pf_str = ""
		self.own_str = ""

		self.workspace_path = ""
		self.workbook_path = ""
		self.repo_path = ""

	def clearProperties(self):
		self.name_str = ""
		self.ver_str = ""
		self.mod_str = ""
		self.plat_str = ""
		self.summ_str = ""
		self.desc_str = ""
		self.pf_str = ""
		self.own_str = ""

	def setWorkspacePath(self, path):
		self.workspace_path = path

	def getWorkspacePath(self):
		return self.workspace_path

	def setRepoPath(self, path):
		self.repo_path = path

	def getRepoPath(self):
		return self.repo_path

	def setWorkbookPath(self, path):
		self.workbook_path = path

	def getWorkbookPath(self):
		return self.workbook_path

	def enableprint(self):
		self.enable_print = True

	def getJobFiles(self, path):
		return glob.glob(path + "**/*.job", recursive=True)

	def getJobFileNames(self, path):
		jobfiles = []
		for eachval in os.listdir(path):
			dir1 = os.path.join(path,eachval)
			#dir1 = eachval
			if os.path.isdir(dir1) == False:
				#Level1 job files added
				dir1.replace(self.workspace_path, '')
				if self.enable_print:
					print("Dir...path...",dir1)
				jobfiles.append(dir1)
				#jobfiles.append(eachval)
			else:
				if self.enable_print:
					print('subdir ', eachval)
				for subDirFiles in (os.listdir(dir1)):
					dir2 = os.path.join(dir1,subDirFiles)
					if os.path.isdir(dir2) == False:
						#Level2 job files added
						dir2.replace(self.workspace_path, '')
						if self.enable_print:
							print("Dir2...", dir2)
						jobfiles.append(dir2)
						#jobfiles.append(eachval + '/' + subDirFiles)
					else:
						if self.enable_print:
							print('subdir2 ', subDirFiles)
						for subDir2Files in (os.listdir(dir2)):
							dir3 = os.path.join(dir2,subDir2Files)
							#Level3 job files added
							dir3.replace(self.workspace_path, '')
							if self.enable_print:
								print("Dir3...", dir3)
							jobfiles.append(dir3)
							#jobfiles.append(eachval + '/' + subDirFiles+ '/' + subDir2Files)
		return jobfiles

	def extractValue(self, strval):
		return strval[strval.find("(")+1:strval.find(")")]

	def getIDExcelColumn(self, columnName):
		foundVal = 0
		for i, eachColumn in enumerate(excelColumn):
			if eachColumn == columnName:
				foundVal = 1
				return i

		if foundVal == 0:
			print("!!!ERROR!!! Invalid Excel Column name ", columnName)
			return 0

	def parseEachJobFile(self, jobfile):
			fp = open(jobfile, 'r')
			#print(jobfile)
			for eachline in fp:
				for i, eachID in enumerate(jobStr):
					if eachline.find(eachID) == True:
						extractField = self.extractValue(eachline)
						if eachID == jobStr[0]:
							self.name_str = extractField
						elif eachID == jobStr[1]:
							self.ver_str = extractField
						elif eachID == jobStr[3]:
							self.plat_str = extractField
						elif eachID == jobStr[4]:
							self.summ_str = extractField
						elif eachID == jobStr[6]:
							self.pf_str = extractField
						elif eachID == jobStr[7]:
							self.own_str = extractField
	#This function will check the job file for valid header
	def checkJobFile(self, jobfile):
		try:
			fp = open(jobfile, 'r')
			validCount = 0
			for eachline in fp:
				for i, eachID in enumerate(jobStr):
					if eachline.find(eachID) == True:
						if eachID == jobStr[0]:
							validCount = validCount + 1
						elif eachID == jobStr[1]:
							validCount = validCount + 1
						elif eachID == jobStr[2]:
							validCount = validCount + 1
						elif eachID == jobStr[3]:
							validCount = validCount + 1
						elif eachID == jobStr[4]:
							validCount = validCount + 1
						elif eachID == jobStr[5]:
							validCount = validCount + 1
						elif eachID == jobStr[6]:
							validCount = validCount + 1
			return validCount
		except:
			print("Unable to open the file - ", jobfile)
			return -1

	def createTestPlanSheet(self, folderName, workbook):
		sheetName = folderName
		#excel can accept sheet name upto 30 characters
		if len(sheetName) > 30:
			sheetName = sheetName[:29]

		excelSheet = workbook.add_sheet(sheetName)
		jobFiles = self.getJobFileNames(self.workspace_path + folderName)

		if len(jobFiles) == 0:
			print("No job files in dir ", folderName)

		headStyle = xlwt.easyxf('font: bold 1')
		for i, eachColumn in enumerate(excelColumn):
			excelSheet.write(0, i, eachColumn, headStyle)

		for r, eachjob in enumerate(jobFiles):
			rowIndex = r+1
			#get the properties from job files ,
			self.clearProperties()
			self.parseEachJobFile(eachjob)
			## Write excel sheet
			excelSheet.write(rowIndex, self.getIDExcelColumn('S.No'), rowIndex)
			excelSheet.write(rowIndex, self.getIDExcelColumn('Module Name'), eachjob.replace((self.workspace_path + folderName + '/'), ''))
			excelSheet.write(rowIndex, self.getIDExcelColumn('Test Name'), self.name_str)
			excelSheet.write(rowIndex, self.getIDExcelColumn('Test Summary'), self.summ_str)
			excelSheet.write(rowIndex, self.getIDExcelColumn('Pass-Criteria'), self.pf_str)
			excelSheet.write(rowIndex, self.getIDExcelColumn('Version'), self.ver_str)
			excelSheet.write(rowIndex, self.getIDExcelColumn('Platform'), self.plat_str)
			excelSheet.write(rowIndex, self.getIDExcelColumn('Owner'), self.own_str)

	def createTestPlanWorkbook(self, filename):
		#create and populate test plan
		print("Folder to process ", self.workspace_path)

		workb = Workbook()
		#parse job folder
		for eachdir in (os.listdir(self.workspace_path)):
			if os.path.isdir(os.path.join(self.workspace_path,eachdir)) == True:
				if self.enable_print:
					print("Dir...", eachdir)

				self.createTestPlanSheet(eachdir, workb)

		try:
			workb.save(self.workbook_path + filename)
			print("File saved as ", self.workbook_path + filename)
		except:
			print("Unable to save the excel file ", self.workbook_path + filename)
			fname,fext = os.path.splitext(filename)
			renameFile = fname+str(datetime.datetime.now())+fext
			workb.save(self.workbook_path + renameFile)
			print("File saved as ", self.workbook_path + renameFile)
			filename = renameFile

		return filename

	def send_email(self, changeset, name, emailID, report):

		if len(report) > 0 :
			print("---- Email ----")
			print('Email ID : ', emailID)
			print('Name : ', name)
			print('File list : ')
			for eachItem in report:
				print(eachItem)
		else:
			print(changeset, " is fine")

	def parse_job_files(self, regression_files):

		file_notOk_report = []
		file_ok_report = []
		file_err_report = []
		for eachfile in regression_files:
			# print(self.repo_path+eachfile)
			validity = self.checkJobFile(self.repo_path+eachfile)
			if validity == 7 :
				# print(self.repo_path + eachfile + " - File Valid ")
				file_ok_report.append(self.repo_path + eachfile + " - File Valid ")
			elif validity == -1:
				# print(self.repo_path + eachfile + " - File not found/error ")
				file_err_report.append(self.repo_path + eachfile + " - File not found/error ")
			else:
				# print(self.repo_path + eachfile + " - File Invalid ")
				file_notOk_report.append(self.repo_path + eachfile + " - File Invalid ")

		return file_notOk_report

	def parse_repository(self, changeset):

		files_changed, committer, emailID, build_num = repo_lib.get_repo_log(self.repo_path, changeset)
		# for eachfile in files_changed:
		# 	print(eachfile)
		# print(committer, ' ', emailID)
		reg_files = jrt_repo.get_regression_suite_files(files_changed)
		# for eachfile in reg_files:
		# 	print(eachfile)
		return committer, emailID, reg_files, build_num

	def parse_repo_change_log(self, baseChangeset, recentChangeset):

		id_list = repo_lib.get_changeset_list(self.repo_path, baseChangeset, recentChangeset)
		newid_list = []
		print(id_list)
		#last element is always null
		#ignore first element, which is baseline
		for eachid in range(1, len(id_list)-1):
			newid_list.append(id_list[eachid])
		print(newid_list)

		# for eachID in id_list:
		# 	if len(eachID) > 0 :
		# 		print(eachID)
		# 		files_changed, committer, emailID = repo_lib.get_repo_log(self.repo_path, eachID)
		# 		print(committer, ' ', emailID)
		# 		reg_files = jrt_repo.get_regression_suite_files(files_changed)
		# 		print(reg_files)

		# print(committer, ' ', emailID)
		# reg_files = jrt_repo.get_regression_suite_files(files_changed)
		# return committer, emailID, reg_files
		return newid_list

class utils_jrt():
	def getAllFileNames(self, path):
		listfilename = []
		for dirpaths, dirnames, filenames in os.walk(path):
			for filename in filenames:
			 	listfilename.append(filename)
		return listfilename

	def logAllJobFileNames(self, path, logfilename):
		listfilename = []
		if os.path.exists(logfilename):
			os.remove(logfilename)
		logfile = open(logfilename, 'a')

		for dirpaths, dirnames, filenames in os.walk(path):
			for filename in filenames:
				# print(filename)
				fname,fext = os.path.splitext(filename)
				if fext == '.job':
					listfilename.append(filename)
					logfile.write(filename + '\n')
				else:
					print('Unknown job file type', filename)

		logfile.close()
		return listfilename

	def logAllFileNamesAndPath(self, path, logfilename):
		listFileNamePath = []
		if os.path.exists(logfilename):
			os.remove(logfilename)
		logfile = open(logfilename, 'a')

		for dirpaths, dirnames, filenames in os.walk(path):
				for filename in filenames:
					fname,fext = os.path.splitext(filename)
					if fext == '.job':
						strfileAndpath = os.path.join(dirpaths,filename)
						logfile.write(strfileAndpath + '\n')
						#print(strfileAndpath)
						listFileNamePath.append(strfileAndpath)
					elif filename == '.empty':
						strfileAndpath = os.path.join(dirpaths,filename)
						logfile.write(strfileAndpath + '\n')
						# print('Unknown job file ', filename)
					else:
						print('Unknown file type', filename)

		logfile.close()

		return listFileNamePath


# Scraping tools
from selenium import webdriver
import urllib.request
import requests

# Data management tools
import pandas as pd
import numpy as np

# Basic tools
from time import sleep
import datetime as dt
import os
import copy
import sys

# Firebase
import firebase_admin
from firebase_admin import credentials
from firebase_admin import storage

class Set:
    """
    Data reader from SET website
    """

    def __init__(self, chrome_driver_dir, download_dir, firebase_credential_path="../../credential/dbsweb-secret.json",
                 bucket="dbsweb-f2346.appspot.com"):
        self.chrome_driver_dir = chrome_driver_dir
        self.download_dir = download_dir

        # INITIALIZING CHROME
        option = webdriver.ChromeOptions()
        option.add_argument(" — incognito")
        option.add_argument('--headless')
        option.add_argument('--no-sandbox')
        option.add_argument('--disable-dev-shm-usage')
        prefs = {'download.default_directory': self.download_dir}
        option.add_experimental_option('prefs', prefs)
        self.browser = webdriver.Chrome(self.chrome_driver_dir, chrome_options=option)

        self.browser.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')
        params = {'cmd': 'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': "/path/to/download/dir"}}
        command_result = self.browser.execute("send_command", params)

        # profile = webdriver.FirefoxProfile()
        # profile.set_preference("browser.download.folderList", 2)
        # profile.set_preference("browser.download.manager.showWhenStarting", False)
        # profile.set_preference("browser.download.dir", '')
        # profile.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/x-gzip")

        # self.browser = webdriver.Firefox(chrome_driver_dir, firefox_profile=profile)

        if (not len(firebase_admin._apps)):
            cred = credentials.Certificate(firebase_credential_path)
            firebase_admin.initialize_app(cred, {
                "storageBucket": bucket
            })

    def _upload_file(self, local_file_name, file_name, data_type, firebase_dir="data/raw/set_website/"):
        """
        Uploading files to Firebase
        """
        bucket = storage.bucket()
        today_str = dt.date.today().strftime(format="%Y%m%d")
        output_dir = firebase_dir + data_type + "/" + today_str + "/"
        blob = bucket.blob(output_dir + file_name)
        blob.upload_from_filename(local_file_name)

    def _read_gcs(self, file_name, data_type, file_type, firebase_dir="data/raw/yahoo/"):

        # Reading files in the firebase storage
        bucket = storage.bucket()
        today_str = dt.date.today().strftime(format="%Y%m%d")
        output_dir = firebase_dir + data_type + "/" + today_str + "/"
        blob = bucket.blob(output_dir + file_name)
        with open(file_name, 'wb') as file_obj:
            blob.download_to_file(file_obj)

        # Read with pandas DataFrame
        if file_type == "html":
            df = pd.read_html(file_name)
            self._check_and_delete_old_file(file_name)
            return df

        if file_type == "csv":
            df = pd.read_csv(file_name, sep="|")
            self._check_and_delete_old_file(file_name)
            return df

    def get_thai_ticker_list(self):
        """
        Getting ticker data from metadata in SET website
        """
        df = self._read_gcs("metadata.csv", "metadata", "csv", firebase_dir="data/process/set_website/")
        return np.array(df["symbol"].unique())

    def _check_and_delete_old_file(self, local_file_name):
        """
        Checking and deleting file in the local path
        """
        if os.path.isfile(self.download_dir + local_file_name):
            os.remove(self.download_dir + local_file_name)

    def get_metadata(self):
        """
        Get company metadata including symbol, company name, location, telephone number, etc.
        """
        self._check_and_delete_old_file(self.download_dir + "listedCompanies_en_US.xls")
#         self.browser.get("https://www.set.or.th/en/company/companylist.html")
#         sleep(1)
#         self.browser.find_element_by_xpath(
# '//a[@href="/dat/eod/listedcompany/static/listedCompanies_en_US.xls"]').click()
#         sleep(1)
        urllib.request.urlretrieve("https://www.set.or.th/dat/eod/listedcompany/static/listedCompanies_en_US.xls", self.download_dir + "listedCompanies_en_US.xls")
        self._upload_file(self.download_dir + "listedCompanies_en_US.xls", "metadata.xls", "metadata",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "listedCompanies_en_US.xls")

    def get_delisting(self):
        """
        Getting delisting company list
        """
        self._check_and_delete_old_file(self.download_dir + "delistedSecurities_en_US.xls")
        # self.browser.get("https://www.set.or.th/en/company/companylist.html")
        # sleep(1)
        # self.browser.find_element_by_xpath(
        #     '//a[@href="/dat/eod/listedcompany/static/delistedSecurities_en_US.xls"]').click()
        # sleep(1)
        urllib.request.urlretrieve("https://www.set.or.th/dat/eod/listedcompany/static/delistedSecurities_en_US.xls", self.download_dir + "delistedSecurities_en_US.xls")
        self._upload_file(self.download_dir + "delistedSecurities_en_US.xls", "delisted.xls", "delisted",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "delistedSecurities_en_US.xls")

    # def get_possible_delisting(self):
    #     self.browser.get("https://www.set.or.th/en/company/companylist.html")
    #     sleep(1)
    #     self.browser.find_element_by_xpath('//a[@onclick="ga(\'send\', \'event\', \'PDF\', \'Companies\', \'PossibleDelistingCompanies - EN\');"]').click()
    #     sleep(1)
    #     _upload_file(self.download_dir+"delistedSecurities_en_US.xls", "delisted.xls", "delisted", firebase_dir="data/raw/set_website/")
    #     sleep(1)

    def get_current_set100_stocks(self):
        """
        Getting today price performance of stocks in SET100
        """
        self._check_and_delete_old_file(self.download_dir + "set100_stocks.csv")
        self.browser.get("https://marketdata.set.or.th/mkt/sectorquotation.do?sector=SET100&language=en&country=US")
        sleep(1)
        pd.read_html(self.browser.page_source)[2].to_csv(self.download_dir + "set100_stocks.csv", sep="|", index=False)
        sleep(1)
        self._upload_file(self.download_dir + "set100_stocks.csv", "set100_stocks.csv", "set100_stocks",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "set100_stocks.csv")

    def get_current_set50_stocks(self):
        """
        Getting today price performance of stocks in SET50
        """
        self._check_and_delete_old_file(self.download_dir + "set50_stocks.csv")
        self.browser.get("https://marketdata.set.or.th/mkt/sectorquotation.do?sector=SET50&language=en&country=US")
        sleep(1)
        pd.read_html(self.browser.page_source)[2].to_csv(self.download_dir + "set50_stocks.csv", sep="|", index=False)
        sleep(1)
        self._upload_file(self.download_dir + "set50_stocks.csv", "set50_stocks.csv", "set50_stocks",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "set50_stocks.csv")

    def get_current_sethd_stocks(self):
        """
        Getting today price performance of stocks in SETHD
        """
        self._check_and_delete_old_file(self.download_dir + "sethd_stocks.csv")
        self.browser.get("https://marketdata.set.or.th/mkt/sectorquotation.do?sector=SETHD&language=en&country=US")
        sleep(1)
        pd.read_html(self.browser.page_source)[2].to_csv(self.download_dir + "sethd_stocks.csv", sep="|", index=False)
        sleep(1)
        self._upload_file(self.download_dir + "sethd_stocks.csv", "sethd_stocks.csv", "sethd_stocks",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "sethd_stocks.csv")

    def get_current_setclmv_stocks(self):
        """
        Getting today price performance of stocks in SETCLMV
        """
        self._check_and_delete_old_file(self.download_dir + "setclmv_stocks.csv")
        self.browser.get("https://marketdata.set.or.th/mkt/sectorquotation.do?sector=SETCLMV&language=en&country=US")
        sleep(1)
        pd.read_html(self.browser.page_source)[2].to_csv(self.download_dir + "setclmv_stocks.csv", sep="|", index=False)
        sleep(1)
        self._upload_file(self.download_dir + "setclmv_stocks.csv", "setclmv_stocks.csv", "setclmv_stocks",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "setclmv_stocks.csv")

    def get_current_sset_stocks(self):
        """
        Getting today price performance of stocks in sSET
        """
        self._check_and_delete_old_file(self.download_dir + "sset_stocks.csv")
        self.browser.get("https://marketdata.set.or.th/mkt/sectorquotation.do?sector=sSET&language=en&country=US")
        sleep(1)
        pd.read_html(self.browser.page_source)[2].to_csv(self.download_dir + "sset_stocks.csv", sep="|", index=False)
        sleep(1)
        self._upload_file(self.download_dir + "sset_stocks.csv", "sset_stocks.csv", "sset_stocks",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "sset_stocks.csv")

    def get_current_setthsi_stocks(self):
        """
        Getting today price performance of stocks in SETTHSI
        """
        self._check_and_delete_old_file(self.download_dir + "setthsi_stocks.csv")
        self.browser.get("https://marketdata.set.or.th/mkt/sectorquotation.do?sector=SETTHSI&language=en&country=US")
        sleep(1)
        pd.read_html(self.browser.page_source)[2].to_csv(self.download_dir + "setthsi_stocks.csv", sep="|", index=False)
        sleep(1)
        self._upload_file(self.download_dir + "setthsi_stocks.csv", "setthsi_stocks.csv", "setthsi_stocks",
                          firebase_dir="data/raw/set_website/")
        sleep(1)
        os.remove(self.download_dir + "setthsi_stocks.csv")

    def _factsheet_get_page(self, symbol, user_agent=None, proxy=None):
        """Getting company data through factsheet page"""

        # Case when user specify user_agent and proxy
        if (user_agent is not None) & (proxy is not None):
            headers = {
                  'accept-encoding': 'gzip, deflate, br',
                  'accept-language': 'en-US,en;q=0.9',
                  'user-agent': user_agent,
                  'accept': '*/*',
                }
            data = requests.get("https://www.set.or.th/set/factsheet.do?symbol={0}&ssoPageId=3&language=en&country=US".format(symbol.upper().replace("&", "%26")),
                                headers=headers,
                                proxies={"http": proxy, "https": proxy}).text

        elif (user_agent is not None) & (proxy is None):
            headers = {
                  'accept-encoding': 'gzip, deflate, br',
                  'accept-language': 'en-US,en;q=0.9',
                  'user-agent': user_agent,
                  'accept': '*/*',
                }

            data = requests.get("https://www.set.or.th/set/factsheet.do?symbol={0}&ssoPageId=3&language=en&country=US".format(symbol.upper().replace("&", "%26")),
                                headers=headers).text
        elif (user_agent is None) & (proxy is not None):
            data = requests.get("https://www.set.or.th/set/factsheet.do?symbol={0}&ssoPageId=3&language=en&country=US".format(symbol.upper().replace("&", "%26")),
                                proxies={"http": proxy, "https": proxy}).text
        else:
            data = requests.get("https://www.set.or.th/set/factsheet.do?symbol={0}&ssoPageId=3&language=en&country=US".format(symbol.upper().replace("&", "%26"))).text

        return data

    def get_factsheet_data(self):
        symbol_list = self.get_thai_ticker_list()
        progress_n = 0
        for symbol in symbol_list:
            data = self._factsheet_get_page(symbol.replace("&", "%26"))
            progress_n += 1
            sys.stdout.write("\rDownloading {0}/{1}".format(str(progress_n), str(len(symbol_list))))
            sys.stdout.flush()
            file = open(symbol+".txt","w")
            file.write(data)
            file.close()
            self._upload_file(self.download_dir + symbol + ".txt", symbol + ".txt", "factsheet",
                          firebase_dir="data/raw/set_website/")
            os.remove(self.download_dir + symbol + ".txt")

def run(chrome_driver_dir="../../tools/chromedriver", download_dir="",
        firebase_credential_path="../../credential/dbsweb-secret.json", bucket="dbsweb-f2346.appspot.com"):
    scraper = Set(chrome_driver_dir, download_dir, firebase_credential_path=firebase_credential_path, bucket=bucket)
    scraper.get_metadata()
    scraper.get_delisting()
    # scraper.get_possible_delisting()
    scraper.get_current_set100_stocks()
    scraper.get_current_set50_stocks()
    scraper.get_current_sethd_stocks()
    scraper.get_current_setclmv_stocks()
    scraper.get_current_sset_stocks()
    scraper.get_current_setthsi_stocks()

def run_factsheet(chrome_driver_dir="../../tools/chromedriver", download_dir="",
        firebase_credential_path="../../credential/dbsweb-secret.json", bucket="dbsweb-f2346.appspot.com"):
    scraper = Set(chrome_driver_dir, download_dir, firebase_credential_path=firebase_credential_path, bucket=bucket)
    scraper.get_factsheet_data()

if __name__ == "__main__":
    run_factsheet()


import numpy as np
import pybullet as p
import itertools
# import math
# from controller import controller

class Robot():
    """
    The class is the interface to a single robot
    """
    def __init__(self, init_pos, robot_id, dt):
        self.id = robot_id
        self.dt = dt
        self.pybullet_id = p.loadSDF("../models/robot.sdf")[0]
        self.joint_ids = list(range(p.getNumJoints(self.pybullet_id)))
        self.initial_position = init_pos
        self.reset()
        self.square_done = False
        self.move_out = False
        self.circle_done = False
        self.v_done = False
        self.v_side = False
        self.v_up = False
        self.circle_form = False
        self.purple_place = False
        self.v_back = False
        self.v_down = False
        self.v_right = False
        self.v_inverse = False
        self.v_inverse_down = False
        self.form_circle = False
        self.circle_up = False
        self.circle_left = False
        self.red_place = False
        self.v_transform = False
        self.v_final_down = False
        self.v_final_right = False
        self.back_in = False
        self.form_rhombus = False

        # No friction between bbody and surface.
        p.changeDynamics(self.pybullet_id, -1, lateralFriction=5., rollingFriction=0.)
        self.prev_position = [0,0,0]
        # Friction between joint links and surface.
        for i in range(p.getNumJoints(self.pybullet_id)):
            p.changeDynamics(self.pybullet_id, i, lateralFriction=5., rollingFriction=0.)
        self.static = False
        self.messages_received = []
        self.messages_to_send = []
        self.neighbors = []
        self.obstacles = []
        self.desired_positions_square= 1*np.array([1.,1.0,1.,-1.0,0.,1.,0.,-1.,-1.,1.0,-1.,-1.0])
        self.desired_positions_circle = 0.5*np.array([np.cos(np.pi/3),np.sin(np.pi/3),1.,0.,-np.cos(np.pi/3),np.sin(np.pi/3),np.cos(np.pi/3),-np.sin(np.pi/3),-1.,0,-np.cos(np.pi/3),-np.sin(np.pi/3)])
        # self.desired_positions_line = 1*np.array([4.,0.,4.,1.,4.,2.,4.,3.,4.,4.,4.,5.])
        self.desired_positions_v = 0.4*np.array([0.,0.,1/np.sqrt(2),-1/np.sqrt(2),-1.0,0.,np.sqrt(2),-np.sqrt(2),-1-1/np.sqrt(2),-1/np.sqrt(2),-1-np.sqrt(2),-np.sqrt(2)])
        self.desired_positions_v_inv = 0.4*np.array([1+np.sqrt(2),np.sqrt(2),1+1/np.sqrt(2),1/np.sqrt(2),-np.sqrt(2),np.sqrt(2),1,0,-1/np.sqrt(2),1/np.sqrt(2),0.,0.])
        self.desired_positions_rhombus = 1*np.array([1.,1.0,1.5,-np.cos(np.pi/6),0.,1.,0.5,-np.cos(np.pi/6),-1.,1.0,-.5,-np.cos(np.pi/6)])
        self.count = 0

        for i in np.arange(-2,2,0.1):
            self.obstacles.append([0,i])
            self.obstacles.append([3,i])

        for i in np.arange(0,2,0.1):
            self.obstacles.append([i,2])

        for i in np.arange(1,3,0.1):
            self.obstacles.append([i,-2])

        # for i in np.arange(1.8,2.2):
        #     for j in np.arange(3.8,4.2):
        #         self.obstacles.append([i,j])

        self.obstacles = np.asarray(self.obstacles)

    def reset(self):
        """
        Moves the robot back to its initial position
        """
        p.resetBasePositionAndOrientation(self.pybullet_id, self.initial_position, (0., 0., 0., 1.))

    def set_wheel_velocity(self, vel):
        """
        Sets the wheel velocity,expects an array containing two numbers (left and right wheel vel)
        """
        assert len(vel) == 2, "Expect velocity to be array of size two"
        p.setJointMotorControlArray(self.pybullet_id, self.joint_ids, p.VELOCITY_CONTROL,
            targetVelocities=vel)

    def get_pos_and_orientation(self):
        """
        Returns the position and orientation (as Yaw angle) of the robot.
        """
        pos, rot = p.getBasePositionAndOrientation(self.pybullet_id)
        euler = p.getEulerFromQuaternion(rot)
        return np.array(pos), euler[2]

    def get_messages(self):
        """
        returns a list of received messages, each element of the list is a tuple (a,b)
        where a= id of the sending robot and b= message (can be any object, list, etc chosen by user)
        Note that the message will only be received if the robot is a neighbor (i.e. is close enough)
        """
        return self.messages_received

    def send_message(self, robot_id, message):
        """
        sends a message to robot with id number robot_id, the message can be any object, list, etc
        """
        self.messages_to_send.append([robot_id, message])

    def get_neighbors(self):
        """
        returns a list of neighbors (i.e. robots within 2m distance) to which messages can be sent
        """
        return self.neighbors

    def is_static(self, position):
        if(np.linalg.norm(self.prev_position - position)<10e-5):
            self.static = True

        else:
            self.static = False

    def compute_controller(self):
        """
        function that will be called each control cycle which implements the control law
        TO BE MODIFIED

        we expect this function to read sensors (built-in functions from the class)
        and at the end to call set_wheel_velocity to set the appropriate velocity of the robots
        """
        # desired_graph = np.array([1, .5**2, .5**2, 1, .5**2, .5**2, 2, 2, 1])
        # edges = np.array([[0,1],[1,3],[3,5],[4,5],[0,2],[2,4],[0,3],[1,4],[2,5]])

        # desired_positions = np.array([0,0,0,0,0,0,0,0,0,0])
        # desired_positions_line = 0.5*np.array([0.1,1,0.2,2,0.3,3,0.4,4,0.5,5,0.6,6])
        # desired_graph = np.zeros(9)
        # here we implement an example for a consensus algorithm
        neig = self.get_neighbors()
        messages = self.get_messages()
        pos, rot = self.get_pos_and_orientation()
        gain = 5
        potential_feild = [4,5.5,0.3]
        potential_feild1 = [4,3,0.3]
        potential_feild2 = [2,3,0.3]
        potential_feild3 = [2,4,0.3]
        potential_feild4 = [2.5,5.5,0.3]
        potential_feild5 = [4,3.5,0.3]
        potential_feild6 = [4,2,0.3]
        potential_feild7 = [0.5,3,0.3]
        potential_feild8 = [0.5,5.5,0.3]
        potential_feild9 = [2.5,4.5,0.3]
        potential_feild10 = [2.5,0,0.3]
        potential_feild11 = [1.5,0,0.3]
        feild_distance1 = 6
        feild_distance2 = 2
        min_distance = 0.4
        kr = 30
        ko = 10
        ks = 3
        kc = 5
        kf = 5
        kv = 7
        #send message of positions to all neighbors indicating our position
        for n in neig:
            self.send_message(n, pos)

        # check if we received the position of our neighbors and compute desired change in position
        # as a function of the neighbors (message is composed of [neighbors id, position])
        if(not self.square_done):
            dx = 0
            dy = 0

        elif(not self.move_out):
            dx = gain*(potential_feild[0] - pos[0])
            dy = gain*(potential_feild[1] - pos[1])

        elif(not self.circle_done):
            dx = 0
            dy = 0

        elif(not self.v_done):
            dx = kv*(potential_feild1[0] - pos[0])
            dy = kv*(potential_feild1[1] - pos[1])

        elif(not self.v_side):
            dx = kv*(potential_feild2[0] - pos[0])
            dy = kv*(potential_feild2[1] - pos[1])

        elif(not self.v_up):
            dx = kv*(potential_feild3[0] - pos[0])
            dy = kv*(potential_feild3[1] - pos[1])

        elif(not self.circle_form):
            dx = kv*(potential_feild3[0] - pos[0])
            dy = kv*(potential_feild3[1] - pos[1])

        elif(not self.purple_place):
            dx = kv*(potential_feild4[0] - pos[0])
            dy = kv*(potential_feild4[1] - pos[1])

        elif(not self.v_back):
            dx = kv*(potential_feild4[0] - pos[0])
            dy = kv*(potential_feild4[1] - pos[1])

        elif(not self.v_down):
            dx = kv*(potential_feild3[0] - pos[0])
            dy = kv*(potential_feild3[1] - pos[1])

        elif(not self.v_right):
            dx = kv*(potential_feild5[0] - pos[0])
            dy = kv*(potential_feild5[1] - pos[1])

        elif(not self.v_inverse):
            dx = kv*(potential_feild5[0] - pos[0])
            dy = kv*(potential_feild5[1] - pos[1])

        elif(not self.v_inverse_down):
            dx = kv*(potential_feild6[0] - pos[0])
            dy = kv*(potential_feild6[1] - pos[1])

        elif(not self.form_circle):
            dx = kv*(potential_feild6[0] - pos[0])
            dy = kv*(potential_feild6[1] - pos[1])

        elif(not self.circle_up):
            dx = kv*(potential_feild5[0] - pos[0])
            dy = kv*(potential_feild5[1] - pos[1])

        elif(not self.circle_left):
            dx = kv*(potential_feild7[0] - pos[0])
            dy = kv*(potential_feild7[1] - pos[1])

        elif(not self.red_place):
            dx = kv*(potential_feild8[0] - pos[0])
            dy = kv*(potential_feild8[1] - pos[1])

        elif(not self.v_transform):
            dx = kv*(potential_feild8[0] - pos[0])
            dy = kv*(potential_feild8[1] - pos[1])

        elif(not self.v_final_down):
            dx = kv*(potential_feild7[0] - pos[0])
            dy = kv*(potential_feild7[1] - pos[1])

        elif(not self.v_final_right):
            dx = kv*(potential_feild9[0] - pos[0])
            dy = kv*(potential_feild9[1] - pos[1])

        elif(not self.back_in):
            dx = kv*(potential_feild10[0] - pos[0])
            dy = kv*(potential_feild10[1] - pos[1])

        else:
            dx = kv*(potential_feild11[0] - pos[0])
            dy = kv*(potential_feild11[1] - pos[1])

        # positions = np.zeros(12)
        # print("robot:",self.id)
        # positions[self.id*2] = pos[0]
        # positions[self.id*2+1] = pos[1]
        if messages:
            for m in messages:
                # positions[2*m[0]] = m[1][0]
                # positions[m[0]*2+1] = m[1][1]
                # print(m[0])
                """ formation control square"""
                # print(self.square_done, self.move_out, self.circle_done)
                if(not self.square_done):
                    dx += ks*((m[1][0] - pos[0]) - (self.desired_positions_square[2*self.id] - self.desired_positions_square[2*m[0]]))
                    dy += ks*((m[1][1] - pos[1]) - (self.desired_positions_square[2*self.id+1] - self.desired_positions_square[2*m[0]+1]))

                # """formation control circle"""
                elif(not self.move_out):
                    if(np.linalg.norm(m[1]-pos)<0.5):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))

                # """potential field control"""
                # if(np.linalg.norm((pos-potential_feild))<feild_distance2):

                elif(not self.circle_done):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))
                    """potential field control"""

                elif(not self.v_done):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_side):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_up):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.circle_form):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))

                elif(not self.purple_place):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))

                elif(not self.v_back):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_down):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_right):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_inverse):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v_inv[2*self.id] - self.desired_positions_v_inv[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v_inv[2*self.id+1] - self.desired_positions_v_inv[2*m[0]+1]))

                elif(not self.v_inverse_down):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v_inv[2*self.id] - self.desired_positions_v_inv[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v_inv[2*self.id+1] - self.desired_positions_v_inv[2*m[0]+1]))

                elif(not self.form_circle):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))

                elif(not self.circle_up):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))

                elif(not self.circle_left):
                    if(np.linalg.norm(m[1]-pos)<0.5):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))

                elif(not self.red_place):
                    if(np.linalg.norm(m[1]-pos)<0.5):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kc*((m[1][0] - pos[0]) - (self.desired_positions_circle[2*self.id] - self.desired_positions_circle[2*m[0]]))
                    dy += kc*((m[1][1] - pos[1]) - (self.desired_positions_circle[2*self.id+1] - self.desired_positions_circle[2*m[0]+1]))

                elif(not self.v_transform):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_final_down):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.v_final_right):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    # dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_v[2*self.id] - self.desired_positions_v[2*m[0]]))
                    # dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_v[2*self.id+1] - self.desired_positions_v[2*m[0]+1]))

                elif(not self.back_in):
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))

                else:
                    if(np.linalg.norm(m[1]-pos)<0.4):
                        dx += np.sign(pos[0]-m[1][0])*kr*np.exp(-abs(pos[0]-m[1][0]))
                        dy += np.sign(pos[1]-m[1][1])*kr*np.exp(-abs(pos[1]-m[1][1]))
                    dx += kv*((m[1][0] - pos[0]) - (self.desired_positions_rhombus[2*self.id] - self.desired_positions_rhombus[2*m[0]]))
                    dy += kv*((m[1][1] - pos[1]) - (self.desired_positions_rhombus[2*self.id+1] - self.desired_positions_rhombus[2*m[0]+1]))

            for obs in self.obstacles:
                if(np.linalg.norm(pos[:-1]-obs) < min_distance):
                    dx += np.sign(pos[0]-obs[0])*ko*np.exp(-abs(pos[0]-obs[0]))
                    dy += np.sign(pos[1]-obs[1])*ko*np.exp(-abs(pos[1]-obs[1]))

            if(self.count == 2500):
                if(not self.square_done):
                    self.square_done = True

                elif(not self.move_out):
                    self.move_out = True

                elif(not self.circle_done):
                    self.circle_done = True

                elif(not self.v_done):
                    self.v_done = True

                elif(not self.v_side):
                    self.v_side = True

                elif(not self.v_up):
                    self.v_up = True

                elif(not self.circle_form):
                    self.circle_form = True

                elif(not self.purple_place):
                    self.purple_place = True

                elif(not self.v_back):
                    self.v_back = True

                elif(not self.v_down):
                    self.v_down = True

                elif(not self.v_right):
                    self.v_right = True

                elif(not self.v_inverse):
                    self.v_inverse = True

                elif(not self.v_inverse_down):
                    self.v_inverse_down = True

                elif(not self.form_circle):
                    self.form_circle = True

                elif(not self.circle_up):
                    self.circle_up = True

                elif(not self.circle_left):
                    self.circle_left = True

                elif(not self.red_place):
                    self.red_place = True

                elif(not self.v_transform):
                    self.v_transform = True

                elif(not self.v_final_down):
                    self.v_final_down = True

                elif(not self.v_final_right):
                    self.v_final_right = True

                elif(not self.back_in):
                    self.back_in = True

                else:
                    self.form_rhombus = True

                self.count = 0

            # if(np.linalg.norm(pos == self.prev_position) < 0.006):
            #     self.static = True
            #
            # else:
            #     self.static = False
            # self.is_static(pos)
            # print(self.static, self.square_done, self.move_out, self.circle_done)
            # self.prev_position = pos
            self.count +=1
            # if(self.circle_done):
            #     potential_feild[0]+=.1
            #     potential_feild[1]+=.1
            # if(self.static):
            #     if()
            #
            #     else:
            #         dx+=0
            #         dy+=0

                # else:
                #     dx = gain*(np.log(feild_distance2) + feild_distance1/feild_distance2)
                #     dy = gain*(np.log(feild_distance2) + feild_distance1/feild_distance2)

            # integrate
            # des_pos_x = pos[0] + self.dt * dx
            # des_pos_y = pos[1] + self.dt * dy
            # desired_graph = self.get_graph(desired_pos)

            # des_pos = self.formation_consensus(edges, desired_positions, positions, gain, self.dt)
            # print(des_pos.shape)
            # des_pos_x = np.asarray([des_pos[i] for i in range(0,12,2)])
            # des_pos_y = np.asarray([des_pos[i] for i in range(1,12,2)])
            # dx = des_pos_x[self.id]
            # dy = des_pos_y[self.id]
            # print(dy)
            #compute velocity change for the wheels
            vel_norm = np.linalg.norm([dx, dy]) #norm of desired velocity
            if vel_norm < 0.01:
                vel_norm = 0.01
            des_theta = np.arctan2(dy/vel_norm, dx/vel_norm)
            right_wheel = np.sin(des_theta-rot)*vel_norm + np.cos(des_theta-rot)*vel_norm
            left_wheel = -np.sin(des_theta-rot)*vel_norm + np.cos(des_theta-rot)*vel_norm
            self.set_wheel_velocity([left_wheel, right_wheel])

    # def get_laplacian(self, incidence_matrix):
    #     laplacian = incidence_matrix.dot(incidence_matrix.T)
    #     return laplacian
    #
    # def get_incidence_matrix(self, edges, num_vertices):
    #
    #     incidence_matrix = np.zeros((2*num_vertices, 2*len(edges)))
    #     for i in range(len(edges)):
    #
    #         incidence_matrix[2*edges[i][0],2*i] =-1
    #         incidence_matrix[2*edges[i][1],2*i] = 1
    #         incidence_matrix[2*edges[i][0]+1,2*i+1] =-1
    #         incidence_matrix[2*edges[i][1]+1,2*i+1] = 1
    #
    #     return incidence_matrix
    #
    # def get_rigidity_matrix(self, positions):
    #     return np.asarray([[2*positions[0] - 2*positions[2], 2*positions[1] - 2*positions[3], -2*positions[0] + 2*positions[2], -2*positions[1] + 2*positions[3], 0, 0, 0, 0, 0, 0, 0, 0],
    #     [0, 0, 2*positions[2] - 2*positions[6], 2*positions[3] - 2*positions[7], 0, 0, -2*positions[2] + 2*positions[6], -2*positions[3] + 2*positions[7], 0, 0, 0, 0],
    #     [0, 0, 0, 0, 0, 0, 2*positions[6] - 2*positions[10], 2*positions[7] - 2*positions[11], 0, 0, -2*positions[6] + 2*positions[10], -2*positions[7] + 2*positions[11]],
    #     [0, 0, 0, 0, 0, 0, 0, 0, 2*positions[8] - 2*positions[10], 2*positions[9] - 2*positions[11], -2*positions[8] + 2*positions[10], -2*positions[9] + 2*positions[11]],
    #     [0, 0, 0, 0, 2*positions[4] - 2*positions[8], 2*positions[5] - 2*positions[9], 0, 0, -2*positions[4] + 2*positions[8], -2*positions[5] + 2*positions[9], 0, 0],
    #     [2*positions[0] - 2*positions[4], 2*positions[1] - 2*positions[5], 0, 0, -2*positions[0] + 2*positions[4], -2*positions[1] + 2*positions[5], 0, 0, 0, 0, 0, 0],
    #     [2*positions[0] - 2*positions[10], 2*positions[1] - 2*positions[11], 0, 0, 0, 0, 0, 0, 0, 0, -2*positions[0] + 2*positions[10], -2*positions[1] + 2*positions[11]],
    #     [0, 0, 2*positions[2] - 2*positions[8], 2*positions[3] - 2*positions[9], 0, 0, 0, 0, -2*positions[2] + 2*positions[8], -2*positions[3] + 2*positions[9], 0, 0],
    #     [0, 0, 0, 0, 2*positions[4] - 2*positions[6], 2*positions[5] - 2*positions[7], -2*positions[4] + 2*positions[6], -2*positions[5] + 2*positions[7], 0, 0, 0, 0]])
    #
    # def get_graph(self, positions):
    #     return np.asarray([[(positions[0]-positions[2])**2+(positions[1]-positions[3])**2],
    #     [(positions[2]-positions[6])**2+(positions[3]-positions[7])**2],
    #     [(positions[6]-positions[10])**2+(positions[7]-positions[11])**2],
    #     [(positions[8]-positions[10])**2+(positions[9]-positions[11])**2],
    #     [(positions[4]-positions[8])**2+(positions[5]-positions[9])**2],
    #     [(positions[0]-positions[4])**2+(positions[1]-positions[5])**2],
    #     [(positions[0]-positions[10])**2+(positions[1]-positions[11])**2],
    #     [(positions[2]-positions[8])**2+(positions[3]-positions[9])**2],
    #     [(positions[4]-positions[6])**2+(positions[5]-positions[7])**2],])
    #
    #
    # def formation_consensus(self, edges, desired_positions, positions, k, dt):
    #     incidence_matrix = self.get_incidence_matrix(edges, 6)
    #     laplacian = self.get_laplacian(incidence_matrix)
    #     return (-k*laplacian.dot(positions)+k*incidence_matrix.dot(incidence_matrix.T.dot(desired_positions)))*dt