/*

        4. zadatak Ispit jul 2017 v1


U ovoj verziji pojednostavili smo zadatak tako sto smatramo
da svi studenti imaju po 3 polozena ispita.

Verzija 2 je sa promenljivim brojem polozenih ispita po svakom studentu.

U svakoj liniji tekstualne ulazne datoteke studenti.txt.
nalaze se podaci o studentima i podaci o polozenim ispitima.
Svaka linija u ovoj ulaznoj datoteci se sastoji od vise kolona
koje su medjusobno odvojene znakom tackazarez (;).

U prvoj koloni se nalazi ime i prezime studenta (maksimalan broj karaktera je 50).
U drugoj koloni se nalazi broj indeksa studenta (maksimalan broj karaktera je 9).
Potom slede podaci o polozenim ispitima.

Za svaki ispit cuvaju se podaci o sifri ispita (maksimalan broj karaktera je 6)
i oceni sa tog ispita (ocene su u intervalu od 6 do 10).

Prebaciti podatke iz tekstualne datoteke studenti.txt u jednostruko spregnutu listu.
                                                                    (20 poena)

Sortirati ovu listu (u opadajucem redosledu prema prosecnoj oceni)
i prikazati njen sadrzaj.                                           (15 poena)


Prikaz jedne linije ulazne datoteke:
Marko Markovic;0001/2016;P1;8;OIKT;9;UIS;6;

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_SIZE 100
#define SIZE_IME 51     // veci za 1 zbog karaktera '\0' na kraju stringa
#define SIZE_INDEKS 10  // veci za 1 zbog karaktera '\0' na kraju stringa
#define SIZE_SIFRA 7    // veci za 1 zbog karaktera '\0' na kraju stringa

/*

NAPOMENA: Listu treba sortirati prema prosecnoj oceni sa polozenih ispita studenta,
i zato u listi treba odmah predvideti

int BrojPolozenihIspita i
float ProsecnaOcena

za svakog studenta.

*/

struct cvor{                    // struktura cvor, to je jedan element liste
                char imeiprezime[SIZE_IME];             // sadrzaj cvora
                char BrojIndeksa[SIZE_INDEKS];
                char SifraIspita1[SIZE_SIFRA];
                int ocena1;
                char SifraIspita2[SIZE_SIFRA];
                int ocena2;
                char SifraIspita3[SIZE_SIFRA];
                int ocena3;
                int BrojPolozenihIspita;
                float ProsecnaOcena;
                struct cvor *sledeci;           // i pointer na sledeceg clana
};
typedef struct cvor CVOR;       // jedan cvor liste CVOR
typedef CVOR* PCVOR;            // pointer na listu CVOR


// Prikazuje sadrzaj cvorova liste glava
void prikazi_listu(char *tekst, PCVOR glava)
{
    printf("\n%s\n",tekst);

    if(glava == NULL) {
        printf(" prazna. \n");
    } else {
         while(glava) {

            printf("\n | %-16s %-10s %6s %2d %6s %2d %6s %2d  %2d %5.2f | \n",
                glava->imeiprezime,
                glava->BrojIndeksa,
                glava->SifraIspita1,
                glava->ocena1,
                glava->SifraIspita2,
                glava->ocena2,
                glava->SifraIspita3,
                glava->ocena3,
                glava->BrojPolozenihIspita,
                glava->ProsecnaOcena );

            glava = glava->sledeci;
        }
    }

    printf("\n");
}


// Prikazuje sadrzaj jednog cvora tekuci
void prikazi_jedan_cvor_liste(char *tekst, PCVOR tekuci)
{
    printf("\n%s\n",tekst);

    if(tekuci == NULL) {
        printf(" prazan. \n");
    } else {
            printf("\n | %-16s %-10s %6s %2d %6s %2d %6s %2d  %2d %5.2f | \n",
                tekuci->imeiprezime,
                tekuci->BrojIndeksa,
                tekuci->SifraIspita1,
                tekuci->ocena1,
                tekuci->SifraIspita2,
                tekuci->ocena2,
                tekuci->SifraIspita3,
                tekuci->ocena3,
                tekuci->BrojPolozenihIspita,
                tekuci->ProsecnaOcena );
    }
}


// Na kraj liste glava dodaje vec napravljeni novi cvor
void dodaj_na_kraj (PCVOR *glava, PCVOR *rep, PCVOR novi)
{
    if(*glava == NULL) {     // ako je lista prazna
        *rep = novi;            // i rep i glava su taj novi cvor
        *glava = novi;
    } else {                // ako lista nije prazna
        (*rep)->sledeci = novi;  // sledeci od starog repa je taj novi
        *rep = novi;            // novi rep je taj novi
    }
}


// Sortira listu glava u opadajucem redosledu po prosenoj oceni studenta
void sortiraj_listu_po_prosecno_oceni_opadajuce( PCVOR *glava, PCVOR *rep )
{
    PCVOR i, j;                     // pomocne liste i i j
    int mem_int;                    // memorija za pamcenje integer-a
    float mem_float;                // memorija za pamcenje float-a
    char mem_string[SIZE_IME];      // memorija za pamcenje string-a

    for ( i=*glava; i; i=i->sledeci )       // i ide od glave do repa
        for ( j=*glava; j; j=j->sledeci )   // j ide od glave do repa
            if ( i->ProsecnaOcena > j->ProsecnaOcena ) { // KRITERIJUM SORTIRANJA

                // medjusobno zamenjujemo mesta svim podacima (sadrzajima cvorova i i j)

                strcpy(mem_string, i->imeiprezime); // sa stringovima mora strcpy()
                strcpy(i->imeiprezime, j->imeiprezime);
                strcpy(j->imeiprezime, mem_string);

                strcpy(mem_string, i->BrojIndeksa ); // sa stringovima mora strcpy()
                strcpy(i->BrojIndeksa, j->BrojIndeksa);
                strcpy(j->BrojIndeksa, mem_string);


                strcpy(mem_string, i->SifraIspita1 ); // sa stringovima mora strcpy()
                strcpy(i->SifraIspita1, j->SifraIspita1);
                strcpy(j->SifraIspita1, mem_string);

                mem_int = i->ocena1;
                i->ocena1 = j->ocena1;
                j->ocena1 = mem_int;


                strcpy(mem_string, i->SifraIspita2 ); // sa stringovima mora strcpy()
                strcpy(i->SifraIspita2, j->SifraIspita2);
                strcpy(j->SifraIspita2, mem_string);

                mem_int = i->ocena2;
                i->ocena2 = j->ocena2;
                j->ocena2 = mem_int;


                strcpy(mem_string, i->SifraIspita3 ); // sa stringovima mora strcpy()
                strcpy(i->SifraIspita3, j->SifraIspita3);
                strcpy(j->SifraIspita3, mem_string);

                mem_int = i->ocena3;
                i->ocena3 = j->ocena3;
                j->ocena3 = mem_int;


                mem_int = i->BrojPolozenihIspita;
                i->BrojPolozenihIspita = j->BrojPolozenihIspita;
                j->BrojPolozenihIspita = mem_int;

                mem_float = i->ProsecnaOcena ;
                i->ProsecnaOcena = j->ProsecnaOcena;
                j->ProsecnaOcena = mem_float;
            }
}




int main(void)
{
    FILE *p_ul_fajl;        // pointer na ulazni fajl
    PCVOR glava = NULL;     // deklarisemo listu (OBAVEZNO =NULL)
    PCVOR rep = NULL;       // deklarisemo rep liste (OBAVEZNO =NULL)
    PCVOR novi = NULL;      // deklarisemo cvor novi;
    PCVOR pom = NULL;       // deklarisemo pomocni cvor pom;
    char tekst[SIZE_IME];   // privremeni string
    char red[MAX_SIZE];     // string u koji smestamo jedan ucitani red iz ulaznog fajla
    int i,j;                // indeksi


    // Otvaramo ulazni txt fajl za citanje
    p_ul_fajl = fopen("studenti.txt","r");
    if( p_ul_fajl == NULL ) {
        printf("\n Greska pri otvaranju ulaznog fajla ulaz.txt ! \n");
        exit(1);
    }

    // Ucitavamo red po red do kraja fajla i podatke smestamo u cvor novi
    while( fgets(red,MAX_SIZE,p_ul_fajl) ){ // ucitavamo red po red do kraja fajla
                                     // fgets() ucitava i karakter '\n' na kraju reda
        red[ strlen(red)-1 ] = '\0'; // karakter '\n' na kraju reda zamenjujemo sa '\0'

        novi = (PCVOR)malloc(sizeof(CVOR)); // rezervisemo memoriju za cvor novi
        if(novi == NULL) {
            printf("\n Greska pri rezervisanju memorije! \n");
            exit(1);
        }

        // Iz reda ucitavamo podatke koji su razdvojeni karakterom ';'

        novi->BrojPolozenihIspita = 0; // resetujemo BrojPolozenihIspita

        // Ucitavamo imeiprezime
        i=0;    // resetujemo indeks stringa red[i]
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string imeiprezime
            novi->imeiprezime[j++] = red[i++];
        novi->imeiprezime[j] = '\0';  // zavrsavamo string koji ucitavamo

        // Ucitavamo BrojIndeksa
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string BrojIndeksa
            novi->BrojIndeksa[j++] = red[i++];
        novi->BrojIndeksa[j] = '\0';  // zavrsavamo string koji ucitavamo

        // Ucitavamo sifre ispita i ocene

        // Ucitavamo sifru 1. ispita
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string SifraIspita1
            novi->SifraIspita1[j++] = red[i++];
        novi->SifraIspita1[j] = '\0';  // zavrsavamo string koji ucitavamo

        // Ucitavamo ocenu 1. ispita
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string tekst
            tekst[j++] = red[i++];
        tekst[j] = '\0';  // zavrsavamo string koji ucitavamo
        novi->ocena1 = atoi(tekst); // ucitani string tekst pretvaramo u integer ocena1

        novi->BrojPolozenihIspita++; // uvecavamo BrojPolozenihIspita

        // Ucitavamo sifru 2. ispita
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string SifraIspita2
            novi->SifraIspita2[j++] = red[i++];
        novi->SifraIspita2[j] = '\0';  // zavrsavamo string koji ucitavamo

        // Ucitavamo ocenu 2. ispita
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string tekst
            tekst[j++] = red[i++];
        tekst[j] = '\0';  // zavrsavamo string koji ucitavamo
        novi->ocena2 = atoi(tekst); // ucitani string tekst pretvaramo u integer ocena2

        novi->BrojPolozenihIspita++; // uvecavamo BrojPolozenihIspita

        // Ucitavamo sifru 3. ispita
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string SifraIspita3
            novi->SifraIspita3[j++] = red[i++];
        novi->SifraIspita3[j] = '\0';  // zavrsavamo string koji ucitavamo

        // Ucitavamo ocenu 3. ispita
        i++;    // preskacemo karakter ';'
        j=0;    // resetujemo indeks stringa koji ucitavamo
        // Dok ne naidjemo na ';' ili na kraj reda
        while( red[i] != ';'  &&  red[i] != '\0' )  // ucitavamo string tekst
            tekst[j++] = red[i++];
        tekst[j] = '\0';  // zavrsavamo string koji ucitavamo
        novi->ocena3 = atoi(tekst); // ucitani string tekst pretvaramo u integer ocena3

        novi->BrojPolozenihIspita++; // uvecavamo BrojPolozenihIspita
        // Racunamo prosecnu ocenu
        novi->ProsecnaOcena =
         (float)(novi->ocena1 + novi->ocena2 + novi->ocena3) / novi->BrojPolozenihIspita;

        // OBAVEZNO =NULL inace prikaz poslednjeg cvora liste ne radi dobro
        novi->sledeci = NULL;


        // cvor novi smestamo na kraj liste glava da bi zadrzali isti redosled kao u fajlu
        dodaj_na_kraj(&glava,&rep,novi);

    }

    prikazi_listu(" Lista je: ",glava);

    sortiraj_listu_po_prosecno_oceni_opadajuce(&glava,&rep);

    prikazi_listu(" Lista sortirana po prosecnoj oceni opadajuce je: ",glava);


    // Zatvaramo ulazni i izlazni txt fajl
    fclose(p_ul_fajl);


    return 0;
}