from agentta import Agent_TA
from agentev import Agent_EV
from matrice import Matrice
from parametres import Parametres
import numpy as np
import random
import os
    
    
class Marche_travail :

    def __init__(self,parametres) :
        self.parametres = parametres

    def creer_matrice_TE(self,liste_agents_EV,liste_agents_TA) :
        #Initialisation de la matrice :
        m = len(liste_agents_TA)
        n = len(liste_agents_EV)
        matrice_TE = Matrice(m,n) 
        #Remplissage de la matrice :
        for i in range (matrice_TE.m) :
            for j in range (matrice_TE.n) :
                if self.parametres.proba_matrice_TE == 0.50 :
                    matrice_TE.data[i][j] = random.randint(0,1)
                else :
                    r = random.random()
                    matrice_TE.data[i][j] = int(r + float(self.parametres.proba_matrice_TE))
        return matrice_TE
            
    def creer_liste_salaires_indicatifs(self,liste_agents_EV,liste_salaires_effectifs_precedente) :
        liste_salaires_indicatifs = []
        for j in range (len(liste_agents_EV)) :
            liste_salaires_indicatifs.append(liste_salaires_effectifs_precedente[j]) #Le salaire indicatif de l'iteration n correspond au salaire effectif de l'iteration n-1
        return liste_salaires_indicatifs    
         
    #Obtenir couples salaire indic - entreprise dans l'ordre decroissant :
    #Les salaires indic None (cas ou total_heures de l'iteration precedente = 0) sont classes en fin de liste
    #Methode utilisee dans la methode couper_lien_travailleur_entreprise 
    def obtenir_couples_salaire_entreprise(self,liste_salaires_indicatifs) :
        J = len(liste_salaires_indicatifs)
        #Liste des paires de salaire - indice entreprise :
        liste_sal_indice = zip(liste_salaires_indicatifs,range(J))
        #Le premier element de la paire x est compare a celui de la paire y (salaires) :
        couples_salaire_entreprise = sorted(liste_sal_indice,cmp = lambda x,y : cmp(x[0],y[0]),reverse = True) 
        return couples_salaire_entreprise
    
    def couper_lien_travailleur_entreprise(self,matrice_TE,liste_salaires_indicatifs) :
        couples_salaire_entreprise = self.obtenir_couples_salaire_entreprise(liste_salaires_indicatifs)
        L = len(couples_salaire_entreprise)
        #Coupure si le salaire indic de l'entreprise est None ou nul :
        couples_a_supprimer = []
        for i in range (matrice_TE.m) :
            for j in range (L) :
                if couples_salaire_entreprise[j][0] == None or couples_salaire_entreprise[j][0] == 0  :
                    matrice_TE.data[i][couples_salaire_entreprise[j][1]] = 0 
                    #On stocke les couples a supprimer des le 1er i (la suppression se fait apres avoir parcouru tous les i) :
                    if i == 0 :
                        couples_a_supprimer.append(couples_salaire_entreprise[j]) 
        #Suppression des couples salaire - entreprise lorsque le salaire indic est None ou nul :
        for c in range (len(couples_a_supprimer)) :       
            couples_salaire_entreprise.remove(couples_a_supprimer[c]) 
            #print "Salaire None ou nul donc coupure"
        L = len(couples_salaire_entreprise)
        #Coupure avec l'entreprise qui propose le plus bas salaire non None si ce dernier est plus de 2x inferieur au salaire indic le plus eleve :        
        for i in range (matrice_TE.m) :
            #On cree la liste des couples salaire - entreprise connectee pour chaque employe :
            couples_salaire_entreprise_connectee = []
            for j in range (L) :
                if matrice_TE.data[i][j] == 1 :
                    couples_salaire_entreprise_connectee.append(couples_salaire_entreprise[j])
            #On verifie que l'employe est connecte a plus d'une entreprise :
            l = len(couples_salaire_entreprise_connectee)
            if l > 1 :
                if couples_salaire_entreprise_connectee[0][0] > (couples_salaire_entreprise_connectee[l-1][0] * self.parametres.param_coupure) :
                    matrice_TE.data[i][couples_salaire_entreprise[l-1][1]] = 0
                    #print "Une coupure a eu lieu entre le travailleur " + str(i) + " et l'entreprise " + str(j)
        return matrice_TE
    
    #Methode pour creer une liste qui contient pour chaque employe la somme des salaires indicatifs qui lui sont proposes :
    def creer_liste_somme_salaires_indic_employes(self,matrice_TE,liste_salaires_indicatifs) :
        liste_somme_salaires_indic_employes = []
        #Pour chaque employe :
        for i in range (matrice_TE.m) :
            somme_salaires = 0
            for j in range (matrice_TE.n) :
                if liste_salaires_indicatifs[j] != None and liste_salaires_indicatifs[j] != 0 :
                    somme_salaires += liste_salaires_indicatifs[j]*matrice_TE.data[i][j]
            liste_somme_salaires_indic_employes.append(somme_salaires)
        return liste_somme_salaires_indic_employes
   
    #Obtenir matrice de repartition des heures des travailleurs dans les entreprises :
    def repartir_heures(self,matrice_TE,liste_agents_TA,liste_salaires_indicatifs,liste_somme_salaires_indic_employes) :
        repartition_heures_travailleurs = []
        #Pour chaque employe :
        for i in range (matrice_TE.m) :  
            liste_repartition_heures = []
            for j in range (matrice_TE.n) : 
                if liste_salaires_indicatifs[j] != 0 and liste_salaires_indicatifs[j] != None and liste_somme_salaires_indic_employes[i] != 0  :
                    heures_travaillees = ((liste_salaires_indicatifs[j]*matrice_TE.data[i][j])/liste_somme_salaires_indic_employes[i])*liste_agents_TA[i].heures
                else :
                    heures_travaillees = 0
                liste_repartition_heures.append(heures_travaillees)
            repartition_heures_travailleurs.append(liste_repartition_heures)
        return repartition_heures_travailleurs
    
    #Methode qui permet d'obtenir la liste du total des heures travaillees dans chaque entreprise :
    def obtenir_liste_total_heures(self,repartition_heures_travailleurs,liste_agents_EV,liste_agents_TA) :
        liste_total_heures = []
        #Pour chaque entreprise :
        for j in range (len(liste_agents_EV)) :
            total_heures = 0
            for i in range (len(liste_agents_TA)) :
                total_heures += repartition_heures_travailleurs[i][j] 
            liste_total_heures.append(total_heures)
        return liste_total_heures
        
    #Methode qui permet d'obtenir la liste de la production des entreprises :
    def creer_liste_production_entreprises(self,liste_agents_EV,liste_total_heures) :
        liste_production_entreprises = []
        #Pour chaque entreprise :
        for j in range (len(liste_agents_EV)) :
            production = liste_agents_EV[j].convertir_heures_biens(self.parametres,liste_total_heures[j])
            liste_production_entreprises.append(production)
        return liste_production_entreprises
    
    #Methode qui permet de creer la liste des salaires horaires effectifs des entreprises :
    def creer_liste_salaires_effectifs(self,liste_agents_EV,liste_total_heures,liste_salaires_effectifs_precedente,parametres) :
        liste_salaires_effectifs = []
        for j in range (len(liste_agents_EV)) :
            if liste_total_heures[j] != 0 :
                sal = (liste_agents_EV[j].cash*self.parametres.prct_invest_emploi)/liste_total_heures[j] #Attention : ici le cash de l'entreprise et le total des heures sont ceux de l'iteration n (iteration en cours)
                salaire_effectif = liste_salaires_effectifs_precedente[j] + (sal - liste_salaires_effectifs_precedente[j]) * parametres.gamma
                liste_salaires_effectifs.append(salaire_effectif)
            else :
                salaire_effectif = None 
                liste_salaires_effectifs.append(salaire_effectif)
                #print "Salaire effectif donne par l'entreprise " + str(j) + " = None car aucun employe n'a travaille pour l'entreprise."
        return liste_salaires_effectifs 
        
    #Paiement des employes en fonction des heures passees a travailler dans chaque entreprise et des salaires effectifs :
    def payer_employes(self,liste_agents_EV,liste_agents_TA,repartition_heures_travailleurs,liste_salaires_effectifs) :
        liste_payes_totales_employes = []
        somme_payes_totales_employes = 0
        #Pour chaque employe :
        for i in range (len(liste_agents_TA)) :
            paye_totale = 0
            #Pour chaque entreprise :
            for j in range (len(liste_salaires_effectifs)) :
                if liste_salaires_effectifs[j] != None :
                    #Paiement des employes :
                    paye = repartition_heures_travailleurs[i][j]*liste_salaires_effectifs[j]
                    paye_totale += paye
                    liste_agents_TA[i].cash += paye
                    liste_agents_EV[j].cash -= paye
            somme_payes_totales_employes += paye_totale
            liste_payes_totales_employes.append(paye_totale)
        return liste_payes_totales_employes,somme_payes_totales_employes
    
    
    
        
    
    ###METHODES GLOBALES POUR FAIRE TOURNER LE MARCHE DU TRAVAIL :
        
    #Methode a lancer a l'iteration 0 :
    def initialiser_marche_travail(self,liste_agents_EV,liste_agents_TA,matrice_TE,liste_salaires_effectifs_precedente,parametres) :
        #Initialisation de la liste des salaires indicatifs :
        J = len(liste_agents_EV)
        liste_salaires_indicatifs = [self.parametres.salaire_initial] * J
        #Les employes repartissent leurs heures dans les differentes entreprises avec lesquelles ils sont connectes :
        liste_somme_salaires_indic_employes = self.creer_liste_somme_salaires_indic_employes(matrice_TE,liste_salaires_indicatifs)
        repartition_heures_travailleurs = self.repartir_heures(matrice_TE,liste_agents_TA,liste_salaires_indicatifs,liste_somme_salaires_indic_employes)
        #Conversion des heures travaillees au sein de chaque entreprise en biens :
        liste_total_heures = self.obtenir_liste_total_heures(repartition_heures_travailleurs,liste_agents_EV,liste_agents_TA) #On MAJ liste_total_heures avec les heures travaillees dans les entreprises au cours de l'iteration n (iteration en cours)
        liste_production_entreprises = self.creer_liste_production_entreprises(liste_agents_EV,liste_total_heures)
        #Payer les employes :
        liste_salaires_effectifs  = self.creer_liste_salaires_effectifs(liste_agents_EV,liste_total_heures,liste_salaires_effectifs_precedente,parametres)
        liste_payes_totales_employes,somme_payes_totales_employes = self.payer_employes(liste_agents_EV,liste_agents_TA,repartition_heures_travailleurs,liste_salaires_effectifs) 
        return matrice_TE,liste_salaires_indicatifs,repartition_heures_travailleurs,liste_total_heures,liste_production_entreprises,liste_salaires_effectifs,liste_payes_totales_employes 
        
    def travailler(self,matrice_TE,liste_agents_EV,liste_agents_TA,liste_salaires_effectifs_precedente,parametres) :
        #Chaque entreprise propose un salaire horaire indicatif :
        liste_salaires_indicatifs = self.creer_liste_salaires_indicatifs(liste_agents_EV,liste_salaires_effectifs_precedente) 
        #Coupures eventuelles avec MAJ de la matrice TE :
        matrice_TE = self.couper_lien_travailleur_entreprise(matrice_TE,liste_salaires_indicatifs)
        #Les employes repartissent leurs heures dans les differentes entreprises avec lesquelles ils sont connectes :
        liste_somme_salaires_indic_employes = self.creer_liste_somme_salaires_indic_employes(matrice_TE,liste_salaires_indicatifs)
        repartition_heures_travailleurs = self.repartir_heures(matrice_TE,liste_agents_TA,liste_salaires_indicatifs,liste_somme_salaires_indic_employes)
        #Conversion des heures travaillees au sein de chaque entreprise en biens :
        liste_total_heures = self.obtenir_liste_total_heures(repartition_heures_travailleurs,liste_agents_EV,liste_agents_TA) #On MAJ liste_total_heures avec les heures travaillees dans les entreprises au cours de l'iteration n (iteration en cours)
        liste_production_entreprises = self.creer_liste_production_entreprises(liste_agents_EV,liste_total_heures)
        #Payer les employes :
        liste_salaires_effectifs = self.creer_liste_salaires_effectifs(liste_agents_EV,liste_total_heures,liste_salaires_effectifs_precedente,parametres)
        liste_payes_totales_employes,somme_payes_totales_employes = self.payer_employes(liste_agents_EV,liste_agents_TA,repartition_heures_travailleurs,liste_salaires_effectifs)
        return matrice_TE,liste_salaires_indicatifs,repartition_heures_travailleurs,liste_total_heures,liste_production_entreprises,liste_salaires_effectifs,liste_payes_totales_employes
    
                
    
   

        
         
