/*
    4._zadatak_Ispit_jul_2017_v3.c          13.03.2018.

    Ova verzija radi sa razlicitim brojem polozenih ispita po studentu.

4. zadatak Ispit jul 2017

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;

*/

// Moramo prvo formirati cvor liste i onda njega ubaciti na kraj liste

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>              // zbog atoi()

#define SIZE_IME 51             // za jedan vise zbog '\0' na kraju stringa
#define SIZE_BRINDEKSA 10       // za jedan vise zbog '\0' na kraju stringa
#define SIZE_SIFRAISPITA 7      // za jedan vise zbog '\0' na kraju stringa
#define MAX_BRISPITA 50         // 50 ispita tokom studiranja
#define MAX_SIZETEKST 600       // SifraIspita + ; + ocena = 8 + ; + 2 = 11+1=12 . 12 * 50 = 600

typedef struct student STUDENT;

struct student{
    char ImeIPrezime[SIZE_IME];
    char BrojIndeksa[SIZE_BRINDEKSA];
    char SifraIspita[MAX_BRISPITA][SIZE_SIFRAISPITA];
    int ocena[MAX_BRISPITA];
    float ProsecnaOcena;        // ovo je dodato u listu zbog sortiranja po prosecnoj oceni
    int BrojPolozenihIspita;    // takodje
};


typedef struct cvor CVOR;
typedef CVOR* PCVOR;
struct cvor{
    STUDENT podatak;
    PCVOR sledeci;
};



// Prikazuje sadrzaj cvorova liste glava
void prikazi_listu(char *tekst, PCVOR glava)
{
    int i;

    printf("\n%s\n",tekst);

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

            printf("\n | %-14s %10s ",
                glava->podatak.ImeIPrezime,
                glava->podatak.BrojIndeksa );

            for( i=0; i < glava->podatak.BrojPolozenihIspita; i++ ){

                printf(" %4s %2d ",
                glava->podatak.SifraIspita[i],
                glava->podatak.ocena[i]);
            }

            printf(" %5.2f %2d | \n",
                glava->podatak.ProsecnaOcena,
                glava->podatak.BrojPolozenihIspita );

            glava = glava->sledeci;
        }
    }

    printf("\n");
}


// Na kraj liste glava dodaje vec napravljeni novi cvor
// Funkcija ne zavisi od sadrzaja cvorova liste glava.
// Dobija se isti redosled cvorova u odnosu na niz.
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
    }
}


// Medjusobno zamenjuje sadrzaje dva cvora i,j.
// To je pomocna funkcija za funkcije sortiranja.
void zameni_medjusobno_sadrzaje_cvorova( PCVOR *i, PCVOR *j)
{                                           // argumenti su pointeri jer funkcija menja cvorove i,j.
    PCVOR mem;                              // deklaracija pomocnog cvora liste

    mem = (PCVOR)malloc(sizeof(CVOR));      // rezervisemo memoriju za cvor mem

    if(mem == NULL) {                       // obrada eventualne greske pri rezervisanju memorije
        printf("\n Greska pri rezervisanju memorije za cvor mem ! \n");
        exit(1);                            // prekidamo program
    }

    mem->podatak = (*i)->podatak;           // zamena sadrzaja dva cvora
    (*i)->podatak = (*j)->podatak;
    (*j)->podatak = mem->podatak;
}


// Sortiranje liste
void sortiraj_listu_po_float_prosecna_ocena_opadajuce( PCVOR *glava )
{
     PCVOR i,j;                              // pomocni cvorovi za sortiranje

    for(i=*glava; i; i=i->sledeci)          // od prvog do poslednjeg cvora (tada je i = NULL)
        for(j=*glava; j; j=j->sledeci)      // od prvog do poslednjeg cvora (tada je j = NULL)
                                  // > za nerastuci (obrnuti) redosled sortiranja
            if( i->podatak.ProsecnaOcena > j->podatak.ProsecnaOcena )       // KRITERIJUM SORTIRANJA !
                // MORAMO MEDJUSOBNO ZAMENITI SVE SADRZAJE CVOROVA (putnike vagona) i,j
                zameni_medjusobno_sadrzaje_cvorova( &i, &j ); // predajemo adrese jer funkcija menja cvorove
}




int main(void)
{
    FILE *fp;
    PCVOR novi = NULL;                      // pocetne vrednosti su obavezno NULL
    PCVOR glava = NULL;
    PCVOR rep = NULL;
    int i, k, duzina;                       // j je indeks za tekst2
    int ZbirOcenaJednogStudenta;
    char ImeUlaznogFajla[] = "studenti.txt";
    char tekst[MAX_SIZETEKST];
    char tekst2[SIZE_SIFRAISPITA];
    char ch;

    fp=fopen(ImeUlaznogFajla,"r");          // Otvaramo ulazni txt fajl za citanje
    if(fp == NULL){
        printf("\n Greska pri otvaranju ulaznog fajla \"%s\". \n",ImeUlaznogFajla);
        exit(1);
    }

    // Marko Markovic;0001/2016;P1;8;OIKT;9;UIS;6;

    // Od pocetka do kraja fajla ucitavamo jedan po jedan podatak i smestamo ga u listu
    while ( 1 ) {    // prva beskonacna petlja koja se prekida sa break

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

        ZbirOcenaJednogStudenta=0;          // resetujemo ZbirOcenaJednogStudenta

        // Ucitavamo iz reda ImeIPrezime i BrojIndeksa uz proveru da li smo stigli do kraja fajla
        // format za ucitavanje "%[^;]" znaci da ucitavamo dok ne naidjemo na tackazarez  !!!
        // format za ucitavanje "%*c" ucitava BILO KOJI znak iz datoteke, ali ga nigdje ne zapisuje  !!!
        if( fscanf(fp,"%[^;]%*c%[^;]%*c",
                novi->podatak.ImeIPrezime,
                novi->podatak.BrojIndeksa ) == EOF )
            break;
//        printf("\n|%s|\n",novi->podatak.ImeIPrezime);
//        printf("\n|%s|\n",novi->podatak.BrojIndeksa);

        novi->podatak.BrojPolozenihIspita=0; // resetujemo brojac polozenih ispita

        // Mi jos ne znamo broj polozenih predmeta (promenljiv je) i moramo da ga odredimo.
        // Do sada smo ucitali ImeIPrezime i BrojIndeksa.
        // Sada cemo, do kraja reda ili do kraja fajla,
        // ucitavati parove SifraIspita i ocena.
        // Podatak ocena cemo ucitavati u tekst2,
        // pa tekst2 pretvoriti u float i dodeliti cvoru novi
        while ( 2 ) {    // druga beskonacna petlja koja se prekida sa break

            if( fscanf(fp,"%[^;]%*c%[^;]%*c",
                    novi->podatak.SifraIspita[novi->podatak.BrojPolozenihIspita],
                    tekst2 ) == EOF )
                break;

            novi->podatak.ocena[novi->podatak.BrojPolozenihIspita] = atoi(tekst2);

//            printf("\n novi->podatak.SifraIspita = %s \n",novi->podatak.SifraIspita[novi->podatak.BrojPolozenihIspita]);
//            printf("\n novi->podatak.ocena = %d \n",novi->podatak.ocena[novi->podatak.BrojPolozenihIspita]);

            ZbirOcenaJednogStudenta += novi->podatak.ocena[novi->podatak.BrojPolozenihIspita];
//            printf("\n ZbirOcenaJednogStudenta = %d \n", ZbirOcenaJednogStudenta );

            novi->podatak.BrojPolozenihIspita++;    // brojimo polozene predmete
//            printf("\n novi->podatak.BrojPolozenihIspita = %d \n",novi->podatak.BrojPolozenihIspita );

            // provera da li smo stigli do kraja reda
            if ( (ch=fgetc(fp)) == '\n' )   {
//                printf("\n *** Prekidamo drugu beskonacnu while(1) petlju\n");
                break;  // prekidamo drugu beskonacnu while(1) petlju
            } else {
                ungetc( ch, fp );           // vracamo ch u fajl
            }

        } // while ( 2 ) { // druga beskonacna petlja koja se prekida sa break


        // Sada konacno imamo broj polozenih ispita za tog jednog studenta.
        // Racunamo prosecnu ocenu tog jednog studenta:
        novi->podatak.ProsecnaOcena = (float)ZbirOcenaJednogStudenta / (float)novi->podatak.BrojPolozenihIspita;

        novi->sledeci=NULL;                 // Obavezno jer je to novi cvor.

        dodaj_na_kraj(&glava,&rep,novi);

    } // while ( 1 ) { // prva beskonacna petlja koja se prekida sa break


    prikazi_listu(" Lista je: ",glava);

    //Sortiranje neopadajuce po prosecnim ocenama
    sortiraj_listu_po_float_prosecna_ocena_opadajuce(&glava);

    prikazi_listu(" Lista sortirana opadajuce po prosecnim ocenama je: ",glava);


    fclose(fp);


    printf("\n\n\n");
    system("PAUSE");

    return 0;
}