#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void uniform(int , int **, double *);
void equalsplit(int , int **, double *);
void concede(int , int **, double *);
void puntuacio(int, double **, double *);

int main(void){

    int N, **A,  total=0, i, j, compt=0, poss=0;
    int resultatbo=0;
    double k, l;
    double *c, *x, *m, *u, *es, *cd, totalc=0.;
    double **Mer, *pt, totalpt=0.;
    double *xreal, *mreal, *resreal;
    double pes_u=1, pes_es=0, pes_cd=0, suma=1;
    double maxim=0, minim=100000;
    double **C,  mmq=0;
    double minmmq=1000000;
    FILE *fin, *fin2, *finmer, *fout, *fout2;

    /*
    Matriu mèrits
    Files corresponen als equips
    Columna 1: gols
    Columna 2: passades
    Columna 3: salvades
    */

    fin=fopen("real_aud.txt", "r");
    if (fin==NULL){
        printf("error en obrir fixer d'entrada\n");
        exit(1);
    }
     fin2=fopen("real_ing.txt", "r");
    if (fin2==NULL){
        printf("error en obrir fixer guany\n");
        exit(1);
    }
    finmer=fopen("real_mer.txt", "r");
    if (finmer==NULL){
        printf("error en obrir fixer merits\n");
        exit(1);
    }
    fout=fopen("allocation.txt", "w");
    if (fout==NULL){
        printf("error en obrir fixer allocation\n");
        exit(1);
    }
    fout2=fopen("matriuMerits.txt", "w");
    if (fout==NULL){
        printf("error en obrir fixer allocation\n");
        exit(1);
    }



    fscanf(fin, "%d", &N);



    //Memoria dinamica matriu A (audiències)
    A=(int**)malloc(N*sizeof(int*));
    if (A==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    for (i=0; i<N; i++){
        A[i]=(int*)malloc(N*sizeof(int));
        if (A[i]==NULL){
            printf("\nerror de memoria");
            exit(1);
        }
    }

    //Memoria dinamica matriu Mer (merits)
    Mer=(double**)malloc(N*sizeof(double*));
    if (A==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    for (i=0; i<N; i++){
        Mer[i]=(double*)malloc(4*sizeof(double));
        if (Mer[i]==NULL){
            printf("\nerror de memoria");
            exit(1);
        }
    }

    //Memòria dinamica matriu C (possibilitats)
    C=(double**)malloc(1000*sizeof(double*));
    if (C==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    for (i=0; i<1000; i++){
        C[i]=(double*)malloc(7*sizeof(double));
        if (C[i]==NULL){
            printf("\nerror de memoria");
            exit(1);
        }
        for(j=0; j<5; j++){
            C[i][j]=0;
        }
    }

    //Memòria dinàmica vectors
    //Vector demanda
    c=(double*)malloc(N*sizeof(double));
    if (c==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    //Allocations
    x=(double*)malloc(N*sizeof(double));
    if (x==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    m=(double*)malloc(N*sizeof(double));
    if (m==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    //Vector que retorna la puntuació dels equips
    pt=(double *)malloc(N*sizeof(double));
    if(pt==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    //Normes
    u=(double*)malloc(N*sizeof(double));
    if (u==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    es=(double *)malloc(N*sizeof(double));
    if(es==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    cd=(double *)malloc(N*sizeof(double));
    if(cd==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    //Vector resultant
    xreal=(double *)malloc(N*sizeof(double));
    if(xreal==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    //Ingressos per mèrits
    mreal=(double *)malloc(N*sizeof(double));
    if(mreal==NULL){
        printf("\nerror de memoria");
        exit(1);
    }
    //Vector ponderacions del resultat
    resreal=(double *)malloc(N*sizeof(double));
    if(resreal==NULL){
        printf("\nerror de memoria");
        exit(1);
    }


    //Llegim matriu Audiencies
    printf("Matriu Audiencies\n");
    for(i=0; i<N; i++){
            A[i][i]=0;
        for(j=0; j<N; j++){
            fscanf(fin, "%d", &A[i][j]);
            if(i==j) A[i][i]=0;
            total+=A[i][j]; //Calcul ||A||
            printf("%4d ", A[i][j]);
        }
        printf("\n");
    }
    printf("Total matriu=%d\n", total);

    //Llegim matriu Mèrits
    printf("\nMatriu Merits\n");
    for(i=0; i<N; i++){
        for(j=0; j<4; j++){
            fscanf(finmer, "%lf", &Mer[i][j]);
            printf("%6.2lf ", Mer[i][j]);
        }
        printf("\n");
    }

    //Llegim vector guanys
    printf("\nVector demandes (claims)\n");
    for(i=0; i<N; i++){
        c[i]=0.;
        fscanf(fin2, "%lf", &c[i]);
        totalc+=c[i];
        printf("%6.2lf ", c[i]);
    }
    printf("\nTotal recursos a repartir=%6.2lf\n", totalc);
    printf("\n");

    for(i=0; i<N; i++){
        u[i]=0.;
        es[i]=0.;
        cd[i]=0.;
        x[i]=0.;
        m[i]=0;
        pt[i]=0.;
        xreal[i]=0;
        mreal[i]=0;
        resreal[i]=0;
    }

    //Calculem puntuació
    puntuacio(N,Mer,pt);

    for(i=0; i<N; i++){
        printf("%6.2lf ", pt[i]);
        totalpt+=pt[i];
    }
    printf("\nTotal puntuacio=%6.2lf\n", totalpt);

    //Calculem normes
    printf("\n\n");
    uniform(N, A, u);
    equalsplit(N, A, es);
    concede(N, A, cd);


    //Provem per totes les combinacions amb precisió 0.1 de ponderar F i els mèrits
    // k pondera F, 1-k pondera els mèrits
    printf("prova\n");
    for(k=0.1; k<1; k=k+0.1){
        l=1.-k;
        printf("k=%6.2lf l=%6.2lf \n", k ,l);


        for(pes_u=0; pes_u<1; pes_u+=0.1){
        for(pes_es=0; pes_es<1; pes_es+=0.1){
            for(pes_cd=0; pes_cd<1; pes_cd+=0.1){
                    if((pes_u+pes_cd+pes_es + 0.05) > 1 && (pes_u+pes_cd+pes_es - 0.05) < 1){


                        printf("Ponderacions\n");
                        printf("%2.1lf * F + %2.1lf * Merits\n", k, l);
                        printf(" pes_u  pes_es  pes_cd\n");
                        printf("%6.2lf %6.2lf %6.2lf\n", pes_u, pes_es, pes_cd);
                        printf("Resultat\t pt\t x\t u\t es\t  cd\n");
                        for(i=0; i<N; i++){
                            x[i]=(pes_u*u[i])+(pes_es*es[i])+(pes_cd*cd[i]);
                            printf("Jugador %d= %8.2lf  %8.2lf %8.2lf %8.2lf %8.2lf \n", i+1, pt[i], x[i], u[i], es[i] ,cd[i]);
                        }
                        printf("\n");


                        printf("Resultat Real resreal xreal    mreal  %2.1lf*xreal %2.1f*mreal\n", k, l);
                        double resrealtot=0;
                        for(i=0; i<N; i++){
                            xreal[i]=(x[i]*totalc)/total;
                            mreal[i]=(pt[i]*totalc)/totalpt;
                            resreal[i]=k*xreal[i]+l*mreal[i];
                            resrealtot+=resreal[i];
                            printf("Jugador %d= %8.2lf  %8.2lf %8.2lf %8.2lf %8.2lf \n", i+1, resreal[i], xreal[i], mreal[i], k*xreal[i] ,l*mreal[i]);
                        }
                        printf("resrealtot=%6.2lf\n", resrealtot);


                        maxim=resreal[0];
                        minim=resreal[0];
                        for(i=1; i<N; i++){
                            if(resreal[i]<minim) minim=resreal[i];
                            if(resreal[i]>maxim) maxim=resreal[i];
                        }


                        /*
                        MATRIU **C
                        -Columna 1: Casos
                        -Columna 2: pes_u
                        -Columna 3: pes_es
                        -Columna 4: pes_cd
                        -Columna 5: Diferencia respecte el total (%)
                        -Columna 6: ponderacio F
                        -Columna 7: ponderacio mèrits
                        */

                        if(maxim< 0.075*totalc && minim > 0.025*totalc){
                                C[compt][0]=compt+1.;
                                C[compt][1]=pes_u;
                                C[compt][2]=pes_es;
                                C[compt][3]=pes_cd;
                                C[compt][5]=k;
                                C[compt][6]=1-k;

                                compt++;

                                //Mètode dels mínims quadrats
                                mmq=0;
                                for(i=0; i<N; i++){
                                  mmq = mmq + (resreal[i]-c[i])*(resreal[i]-c[i]);
                                }
                                C[compt-1][4]=mmq;
                                if(mmq<minmmq){
                                    minmmq=mmq;
                                    resultatbo=(int) compt-1;
                                }
                                printf("prova if o impressio\n");
                                fprintf(fout, "\nCas %d \n", compt);
                                fprintf(fout, "%2.1lf * F + %2.1lf * Merits\n", k, l);
                                fprintf(fout, "pes_u  pes_es  pes_cd\n");
                                fprintf(fout, "%5.2lf %6.2lf %6.2lf\n", pes_u, pes_es, pes_cd);
                                fprintf(fout, "Resultat bo      x        u        es      cd      xreal\n");
                                for(i=0; i<N; i++){
                                    fprintf(fout, "Jugador %d= %8.2lf %8.2lf %8.2lf %8.2lf %8.2lf\n", i+1, x[i], u[i], es[i] ,cd[i], xreal[i]);
                                }
                                fprintf(fout, "Resultat     Ingres   Part F  Part mèrits  Pond F  Pond mèrits\n");
                                for(i=0; i<N; i++){
                                    fprintf(fout, "Jugador %d= %8.2lf  %8.2lf %8.2lf %8.2lf %8.2lf \n", i+1, resreal[i], xreal[i], mreal[i], k*xreal[i] ,(1-k)*mreal[i]);
                                }
                                fprintf(fout, "max=%6.2lf\nmin=%6.2lf\n", maxim, minim);
                                fprintf(fout, "mmq=%6.2lf\n", mmq);
                                fprintf(fout, "TAud=%6.2lf\nTGuany=%6.2lf\n", (double) total, totalc);
                                fprintf(fout, "Repartiment de guanys:\n");
                                for(i=0; i<N; i++){
                                    fprintf(fout, "Jugador %d= %8.2lf \n", i+1, resreal[i]);
                                }
                                fprintf(fout, "\n\n");


                            }


                        poss++;


                        }
                    }
                }
            }
    }

                        //Impressió dels resultats
                        fprintf(fout2, "METODE DE MINIMS QUADRATS\n\n");
                        fprintf(fout2, "Ingressos demandats\n");
                        for(i=0; i<N; i++){
                        fprintf(fout2, "Jugador %d: %8.2lf\n", i+1, c[i]);
                        }
                        fprintf(fout2, "\n");
                        fprintf(fout2, "Resultat bo      x        u        es      cd     xreal\n");
                        for(i=0; i<N; i++){

                        x[i]=(C[resultatbo][1]*u[i])+(C[resultatbo][2]*es[i])+(C[resultatbo][3]*cd[i]);
                        xreal[i]=(x[i]*totalc)/total;
                            mreal[i]=(pt[i]*totalc)/totalpt;
                            resreal[i]=C[i][5]*xreal[i]+C[i][6]*mreal[i];
                        fprintf(fout2, "Jugador %d= %8.2lf %8.2lf %8.2lf %8.2lf %8.2lf\n", i+1, x[i], u[i], es[i] ,cd[i], xreal[i]);
                        }

                        fprintf(fout2, "Resultat     Ingres   Part F  Part mèrits  Pond F  Pond mèrits\n");
                                for(i=0; i<N; i++){
                                    fprintf(fout2, "Jugador %d= %8.2lf  %8.2lf %8.2lf %8.2lf %8.2lf \n", i+1, resreal[i], xreal[i], mreal[i], C[resultatbo][5]*xreal[i] ,C[resultatbo][6]*mreal[i]);
                                }

                        fprintf(fout2, "\nPes Norma Unifome = %13.2lf\n", C[resultatbo][1]);
                        fprintf(fout2, "Pes Norma EqualSplit = %10.2lf\n", C[resultatbo][2]);
                        fprintf(fout2, "Pes Norma Concede-Divide = %6.2lf\n", C[resultatbo][3]);
                        fprintf(fout2, "mmq=%6.2lf\n\n", minmmq);
                        fprintf(fout2, "Ponderacio F=%8.2lf\n", C[resultatbo][5]);
                        fprintf(fout2, "Ponderacio Merits=%8.2lf\n", C[resultatbo][6]);

                        // Impressió matriu C
                        fprintf(fout2, "\n\nMATRIU PESOS QUE COMPLEIXEN CONDICIONS\n" );
                        fprintf(fout2, "CAS \t Pond F Pond Mèr \t pes_u \t pes_es \t pes_cd \t minim quadrat\n" );
                        for(i=0; i<compt; i++){
                        fprintf(fout2, "%4lf %8.2lf %8.2lf %8.2lf %8.2lf %8.2lf %8.2lf\n", C[i][0],C[i][5], C[i][6], C[i][1],C[i][2],C[i][3],C[i][4]);
                        }


                    printf("\nTotal puntuacio=%6.2lf\n", totalpt);
                    for(i=0; i<N; i++){
                        printf("%4.2le %4.2le %4.2le %4.2le\n", Mer[i][0], Mer[i][1], Mer[i][2], Mer[i][3]);
                    }

    fclose(fin);
    fclose(fin2);
    fclose(finmer);
    fclose(fout);
    fclose(fout2);

return 0;
}





void uniform(int N, int **A, double *u){
    int i, j, total=0;

        printf("Uniform\n");
    for(i=0; i<N; i++){
        for(j=0; j<N; j++){
            total+=A[i][j];
        }
    }


    for(i=0; i<N; i++){
        u[i]= (double) total/N;
        printf("%6.2lf ", u[i]);
    }
    printf("\n");


    return;
}

void equalsplit(int N, int **A, double *es){
    int i, j, alpha;
    printf("Equal Split\n");
    for(i=0; i<N; i++){
        alpha=0;
        for(j=0; j<N; j++){
            alpha= alpha + A[i][j] + A[j][i];
        }
        es[i]=alpha/2;
        printf("%6.2lf ", es[i]);
    }
    printf("\n");

    return;
}

void concede(int N, int **A, double *cd){
    int i, j, total=0, alpha;
    printf("Concede and divide\n");
    for(i=0; i<N; i++){
        for(j=0; j<N; j++){
            total+=A[i][j];
        }
    }

    for(i=0; i<N; i++){
        alpha=0;
        for(j=0; j<N; j++){
            alpha= alpha + A[i][j] + A[j][i];
        }
        cd[i]=((N-1)*alpha-total)/(N-2);
        printf("%6.2lf ", cd[i]);
    }
    printf("\n");


    return;
}

void puntuacio(int N, double **Mer, double *pt){
    int i, j;

    for(i=0; i<N; i++){
        pt[i]= (5*Mer[i][0] + (Mer[i][1]/100) + (Mer[i][2]/2) + Mer[i][3]);
    }

    return;
}
