#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <strings.h> // strcasecmp : insensitive case
#include "trois.h"
#include "../IV/quatre.c"

void calculerNoteGlobale(ListeCandidats liste, int nbCandidats) {
    int i;
    float noteGlobale;
    for(i=0; i<nbCandidats; i++) {
        noteGlobale = ((liste[i]->moyenneMath)*5 
                    + (liste[i]->moyenneFrancais)*10
                    + (liste[i]->moyenneAnglais)*5
                    + (liste[i]->moyenneSpecialite)*16)/36;

        liste[i]->noteGlobale = noteGlobale;
    }
}

void afficherCandidaturesByDept(ListeCandidats liste, int nbCandidats, char* searchIUT, char* searchDept) {
    int i, j;
    char decision[LEN_MAX], validation[LEN_MAX];
    ListeCandidatures candidatures;
    Candidature* candidature;

    ListeCandidats listeTriee = (ListeCandidats) malloc(nbCandidats*sizeof(Candidat*));

    if(listeTriee == NULL) {
		perror("malloc");
		exit(errno);
	}

    for(i=0; i<nbCandidats; i++) {
        memcpy(&listeTriee[i], &liste[i], sizeof(Candidat*));
    }
    
    qsort(listeTriee, nbCandidats, sizeof(Candidat*), compareCandidats);

    for(i=0; i<nbCandidats; i++) {
        candidatures = listeTriee[i]->listeCandidatures;

        for(j=0; j<listeTriee[i]->nbCandidatures; j++) {
            candidature = candidatures[j];

            if(strcasecmp(candidature->ville, searchIUT) == 0) {
                if(strcasecmp(candidature->departement, searchDept) == 0) {
                    switch (candidature->decision) {
                        case 0:
                            strcpy(decision, "en cours de traitement");
                            break;
                        case 1:
                            strcpy(decision, "admis");
                            break;
                        case -1:
                            strcpy(decision, "refusé");
                            break;
                        case 2:
                            strcpy(decision, "sur liste d'attente");
                            break;
                        default:
                            strcpy(decision, "inconnu");
                            break;
                    }

                    switch (candidature->validation) {
                        case 0:
                            strcpy(validation, "n'a pas encore décidé");
                            break;
                        case 1:
                            strcpy(validation, "refuse la proposition");
                            break;
                        case -1:
                            strcpy(validation, "accepte");
                            break;
                        default:
                            strcpy(validation, "inconnu");
                            break;
                    }

                    printf("\n\e[4;37mCandidature de '%s %s' pour le département '%s' à l'IUT '%s' :\n\e[0m"
                            "  - Décision du département : %s,\n  - Décision du candidat : %s,\n  - Note globale : %.2f\n\n",
                            listeTriee[i]->nom, listeTriee[i]->prenom, candidature->departement, candidature->ville, decision, validation, listeTriee[i]->noteGlobale);
                }
            }
        }
    }

    free(listeTriee);
}

void merge(ListeCandidats liste, int start, int middle, int end) {
    int i, j, k=start;
    int n1 = middle - start + 1;
    int n2 = end - middle;
    Candidat* left[n1], *right[n2];

    for (i = 0; i < n1; i++)
        left[i] = liste[start + i];
    for (j = 0; j < n2; j++)
        right[j] = liste[middle + 1 + j];
    
    i = 0;
    j = 0;
    while (i < n1 && j < n2) {
        if (left[i]->noteGlobale >= right[j]->noteGlobale)
            liste[k++] = left[i++];
        else
            liste[k++] = right[j++];
    }

    while (i < n1)
        liste[k++] = left[i++];
    while (j < n2)
        liste[k++] = right[j++];
}

void triDichotomiqueFusion(ListeCandidats liste, int start, int end) {
    if (start < end) {
        int middle = (start + end) / 2;
        triDichotomiqueFusion(liste, start, middle);
        triDichotomiqueFusion(liste, middle + 1, end);
        merge(liste, start, middle, end);
    }
}

void afficherCandidatTraite(Candidat candidat) {
     printf("\tCandidat n°%d, '%s %s' :"
            "\n\t   - Note globale : %.2f\n\n",
            candidat.id, candidat.prenom, candidat.nom,
            candidat.noteGlobale);
}

void traiterCandidatures(ListeCandidats liste, int nbCandidats, int nbCandidatsAccept, float noteMini, int checkQueue) {
    int i, j, k, nbCandidatsMatch = 0, nbAdmis=0, nbAttente=0, nbRefuse=0;
    char dept[LEN_MAX], ville[LEN_MAX], fNameAdmis[100], fNameAttente[100];
    FILE* fAdmis, *fAttente;

    FileAttente* file;
    CandidatTraite* candidat = (CandidatTraite*) malloc(sizeof(CandidatTraite));

    Candidature* candidature;
    ListeCandidatures candidatures;
    ListeCandidats listeCandidatsMatch;

    Candidat listeAdmis[nbCandidatsAccept], listeAttente[nbCandidatsAccept], listeRefuses[nbCandidatsAccept];

	strcpy(dept, "Informatique");
	strcpy(ville, "Clermont-Ferrand");

    if(checkQueue == 1) {
        file = lireCandidatsAttente(dept, ville);

        if(file->nbAttente > 0) {
            printf("\n\n\e[4;37mCandidats acceptés :\e[0m\n\n");

            for(i=0; i<nbCandidatsAccept; i++) {
                *candidat = defiler(file);
                ajouterCandidatAdmis(dept, ville, candidat);
                nbAdmis++;

                printf("\tCandidat '%s %s' :"
                "\n\t   - Note globale : %.2f\n\n",
                candidat->prenom, candidat->nom,
                candidat->noteGlobale);
                printf("\n");

                if(strcmp(candidat->nom, "") != 0 && strcmp(candidat->prenom, "") != 0) {
                    for(j=0; j<nbCandidats; j++) {
                        if(strcmp(liste[j]->nom, candidat->nom) == 0 && strcmp(liste[j]->prenom, candidat->prenom)) {
                            candidatures = liste[j]->listeCandidatures;
                            for(k=0; k<liste[j]->nbCandidatures; k++)
                                if(candidatures[k]->ville == ville 
                                    && candidatures[k]->departement == dept) {
                                        candidatures[k]->decision = 1;
                                        break;
                                    }
                        }
                    }
                }
            }

            printf("\e[1;32m%d candidats ont été admis depuis la file d'attente.\n\n\e[0m",
                nbAdmis);
            ecrireCandidatsAttente(dept, ville, file);
        } else
            printf("\n\e[1;32mAucun candidat n'a été admis puisque la file d'attente est vide.\n\n\e[0m");        
    } else {
        listeCandidatsMatch = (ListeCandidats) malloc(nbCandidats*sizeof(Candidat*));

        for(i=0; i<nbCandidats; i++) {
            candidatures = liste[i]->listeCandidatures;

            for(j=0; j<liste[i]->nbCandidatures; j++) {
                candidature = candidatures[j];

                if(strcasecmp(candidature->ville, ville) == 0)
                    if(strcasecmp(candidature->departement, dept) == 0)
                        if(candidature->decision == 0)
                            listeCandidatsMatch[nbCandidatsMatch++] = liste[i];
            }
        }

        calculerNoteGlobale(listeCandidatsMatch, nbCandidatsMatch); // Calcul des notes de chaque candidat
        triDichotomiqueFusion(listeCandidatsMatch, 0, nbCandidatsMatch-1); // Trie les candidats selon leur noteGlobale

        for(i=0; i<nbCandidatsMatch; i++) {
            if(listeCandidatsMatch[i]->noteGlobale >= noteMini) {
                if(nbAdmis < nbCandidatsAccept) {
                    for(j=0; j<listeCandidatsMatch[i]->nbCandidatures; j++)
                        if(strcasecmp(listeCandidatsMatch[i]->listeCandidatures[j]->ville, ville) == 0)
                            if(strcasecmp(listeCandidatsMatch[i]->listeCandidatures[j]->departement, dept) == 0)
                                listeCandidatsMatch[i]->listeCandidatures[j]->decision = 1;
                    
                    listeAdmis[nbAdmis++] = *listeCandidatsMatch[i];
                } else {
                    for(j=0; j<listeCandidatsMatch[i]->nbCandidatures; j++)
                        if(strcasecmp(listeCandidatsMatch[i]->listeCandidatures[j]->ville, ville) == 0)
                            if(strcasecmp(listeCandidatsMatch[i]->listeCandidatures[j]->departement, dept) == 0)
                                listeCandidatsMatch[i]->listeCandidatures[j]->decision = 2;

                    listeAttente[nbAttente++] = *listeCandidatsMatch[i];
                }
            } else {
                for(j=0; j<listeCandidatsMatch[i]->nbCandidatures; j++)
                    if(strcasecmp(listeCandidatsMatch[i]->listeCandidatures[j]->ville, ville) == 0)
                        if(strcasecmp(listeCandidatsMatch[i]->listeCandidatures[j]->departement, dept) == 0)
                            listeCandidatsMatch[i]->listeCandidatures[j]->decision = -1;
                
                listeRefuses[nbRefuse++] = *listeCandidatsMatch[i];
            }
        }

        strcpy(fNameAdmis, "donnees/");
        strcat(fNameAdmis, ville);
        strcat(fNameAdmis, "_");
        strcat(fNameAdmis, dept);
        strcat(fNameAdmis, "_Admis.don");

        fAdmis = fopen(fNameAdmis, "w");

        if(fAdmis == NULL) {
            perror("fopen");
            exit(errno);
        }

        if(nbAdmis > 0)
            fprintf(fAdmis, "%d\n", nbAdmis);

        printf("\n\n\e[4;37mCandidats acceptés :\e[0m\n\n");
        for(i=0; i<nbAdmis; i++) {
            afficherCandidatTraite(listeAdmis[i]);
            printf("\n");

            fprintf(fAdmis, "%s\n%s\n%.2f %.2f %.2f %.2f %.2f\n",
                            listeAdmis[i].nom, listeAdmis[i].prenom, 
                            listeAdmis[i].moyenneMath, listeAdmis[i].moyenneFrancais,
                            listeAdmis[i].moyenneAnglais, listeAdmis[i].moyenneSpecialite,
                            listeAdmis[i].noteGlobale);
        }

        fclose(fAdmis);

        if(nbAdmis == 0)
            printf("\tAucun candidat accepté.\n\n");

        strcpy(fNameAttente, "donnees/");
        strcat(fNameAttente, ville);
        strcat(fNameAttente, "_");
        strcat(fNameAttente, dept);
        strcat(fNameAttente, "_Attente.don");

        fAttente = fopen(fNameAttente, "w");

        if(fAttente == NULL) {
            perror("fopen");
            exit(errno);
        }

        if(nbAttente > 0)
            fprintf(fAttente, "%d\n", nbAttente);

        printf("\e[4;37mCandidats en liste d'attente :\e[0m\n\n");
        for(i=0; i<nbAttente; i++) {
            afficherCandidatTraite(listeAttente[i]);
            printf("\n\n");

            fprintf(fAttente, "%s\n%s\n%.2f %.2f %.2f %.2f %.2f\n",
                            listeAttente[i].nom, listeAttente[i].prenom, 
                            listeAttente[i].moyenneMath, listeAttente[i].moyenneFrancais,
                            listeAttente[i].moyenneAnglais, listeAttente[i].moyenneSpecialite,
                            listeAttente[i].noteGlobale);
        }

        fclose(fAttente);

        if(nbAttente == 0)
            printf("\tAucun candidat en liste d'attente.\n\n");

        printf("\e[4;37mCandidats refusés :\e[0m\n\n");
        for(i=0; i<nbRefuse; i++) {
            afficherCandidatTraite(listeRefuses[i]);
            printf("\n\n");
        }

        if(nbRefuse == 0)
            printf("\tAucun candidat refusé.\n\n");

        printf("\e[1;32m%d candidats ont été admis, %d mis en file d'attente et %d refusés.\n\n\e[0m",
                nbAdmis, nbAttente, nbRefuse);

        free(listeCandidatsMatch);
    }
}