/* Tanvir Ahmed
Solution of programming Assignment 1
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include	"leak_detector_c.h"

typedef struct student{
   int id;
   char *lname; //stores last name of student
   float *scores; //stores scores of the student. Size is taken from num_scores array.
   float std_avg; //average score of the student (to be calculated)
}student;


typedef struct course{
   char *course_name; //stores course name
   int num_sections; //number of sections
   student **sections;//stores array of student arrays(2D array). Size is num_sections;
   int *num_students;//stores array of number of students in each section. Size is num_sections;
   int *num_scores; //stores array of number of assignments in each section. Size is num_sections;
} course;

student **read_sections(FILE *fp, int num_students[], int num_scores[], int num_sections);

course *read_courses(FILE *fp, int *num_courses);

void display_sections(student **sections, int num_students[], int num_scores[], int num_sections);

void process_courses(course *courses, int num_courses);

void release_sections(student **sections, int num_sections, int *num_students, int *num_scores);

void release_courses( course *courses, int num_courses);

int main(void) {
  //atexit(report_mem_leak); //for memory leak report
  FILE *fp = fopen("tmp01.in", "r");
  int num_test;
  course *courses; //to be used for courses array
  fscanf(fp, "%d", &num_test); //number of test cases.

  //for each test case
  for(int i=0; i<num_test; i++)
  {
    int num_courses; //to keep track number of course
    //course *courses;
    printf("test case %d\n", i+1);

    courses = read_courses(fp, &num_courses); //read everything
    process_courses(courses, num_courses); //process everything
    release_courses(courses, num_courses); //free everything
    printf("\n");
  }
  //printf("Completed\n");
  fclose(fp);
  return 0;
}

/*
Allocates memory for all the courses, fillup the data fromt he file
and returns the allocated memory for all the courses filled with data
*/
course *read_courses(FILE *fp, int *num_courses)
{
  //read number of courses
  fscanf(fp, "%d", num_courses);
 // printf("--%d--", *num_courses); //passed

  //allocate memory for all the courses
  course *courses = (course*) malloc(sizeof(course) * *num_courses);
  //to be used for reading name from file
  char cname[50];

  //for each course
  for(int c = 0; c< *num_courses; c++)
  {
    //read course name
    fscanf(fp, "%s",  cname);
    int len = strlen(cname);
    //allocte memory to store course name and copy to the strucutre's member
    courses[c].course_name = malloc(len+1);
    strcpy(courses[c].course_name, cname);

    //read number of sections
    fscanf(fp, "%d", &courses[c].num_sections);

    //allocate memory for num_students array. Will be used to store number of students for each section of courses[c]
    courses[c].num_students = (int*) malloc(sizeof(int) * courses[c].num_sections);

     //allocate memory for num_scores array. Will be used to store number of assignments for each section of courses[c]
    courses[c].num_scores = (int*) malloc(sizeof(int) * courses[c].num_sections);

   //calling read_seciton for courses[c]. The arrays will be filldup by the function
    courses[c].sections = read_sections(fp, courses[c].num_students, courses[c].num_scores, courses[c].num_sections);

  }

  //return the fully loaded courses array
  return courses;

}

/*
read all the data for all the section of a couse and return it. Also, fillup the num_students and num_scores array from the file
*/

student **read_sections(FILE *fp, int num_students[], int num_scores[], int num_sections)
{
  //to store data for num_sections number of sections (2D array of student, each 1D array is a section)
  student **sections = (student**) malloc(sizeof(student *) * num_sections);
  char lname[50];

  //for each section
  for(int s = 0; s<num_sections; s++)
  {
    //read num of student and num of scores for the section
    fscanf(fp, "%d %d", &num_students[s], &num_scores[s]);

    //allocate memory for all students in the section
    sections[s] = (student*) malloc(sizeof(student)*num_students[s]);

    //for each student of section number s
    for(int st = 0; st<num_students[s]; st++)
    {
      //read last name
      fscanf(fp, "%d %s", &sections[s][st].id, lname);

      //allocate memory and copy lanme to the structure
      sections[s][st].lname = malloc(strlen(lname) + 1);
      strcpy(sections[s][st].lname, lname);

      //allocate memory for score of the student st for section s
      sections[s][st].scores = (float *)malloc (sizeof(float) * num_scores[s]);

      //to calculate avg of the student
      float sum = 0;

      //working for score of a particular student
      for(int sc = 0; sc<num_scores[s]; sc++)
      {
        fscanf(fp, "%f", &sections[s][st].scores[sc]);
        sum +=  sections[s][st].scores[sc];
      }

     //sore average for student st of section s
      sections[s][st].std_avg = sum/num_scores[s];

/*debug
      if(strcmp(sections[s][st].lname, "edward") == 0)
      {
        printf("--%f %d %f--", sum, num_scores[s], sections[s][st].std_avg);
      }
 */
    }
  }
  //return the fully loaded section
  return sections;

}

//to display the details of the courses
void process_courses(course *courses, int num_courses)
{
  //for each course
  for (int c = 0; c<num_courses; c++)
  {
    //printcourse name
    printf("%s ", courses[c].course_name);

    //print details fo the sections
    display_sections(courses[c].sections, courses[c].num_students, courses[c].num_scores, courses[c].num_sections);


  }

}

//print details for the sections of a course
void display_sections(student **sections, int num_students[], int num_scores[], int num_sections)
{

  //to store average of each section for displaying later after pass_count
  float *section_avg = (float *) malloc(num_sections * sizeof(float));
  //for each section
  int max_st_idx = 0;
  int max_sec_idx = 0;
  int pass_count = 0;

  float max_avg = -1;

  //for each section
  for(int s = 0; s<num_sections; s++)
  {
    //to calculate sum of the std_avg of the section
    float sum_section = 0;
     //for each student of section number s
    for(int st = 0; st<num_students[s]; st++)
    {
      //for calculating pass_count
      if (sections[s][st].std_avg >=70 )
      {
        pass_count++;
      }
      sum_section += sections[s][st].std_avg; //summing up averages of all the students

      //to track the student with highest average
      if(sections[s][st].std_avg>max_avg)
      {
        max_avg = sections[s][st].std_avg;
        max_st_idx = st;
        max_sec_idx = s;
      }
    }

    //average of the section
    section_avg[s] = sum_section/num_students[s];
  }

  printf("%d ", pass_count);

  for(int i = 0; i<num_sections; i++)
    printf("%.2f ", section_avg[i]);

  printf("%d %s %.2f\n",
    sections[max_sec_idx][max_st_idx].id,
    sections[max_sec_idx][max_st_idx].lname,
    sections[max_sec_idx][max_st_idx].std_avg
    );

  //free allocated section_avg
  free(section_avg);

}

//to free the memory for all the courses

void release_courses( course *courses, int num_courses)
{
  //for each course
  for (int c = 0; c<num_courses; c++)
  {
    //free the course name
    free(courses[c].course_name);

    //to free memory for all the sections
    release_sections(courses[c].sections, courses[c].num_sections, courses[c].num_students, courses[c].num_scores);

    //free the num_students and num_scores array.
    free(courses[c].num_students);
    free(courses[c].num_scores);
  }

  //finally free the courses at the end
  free(courses);
}

//free all the sections of a course and all internal allocated memroy
void release_sections(student **sections, int num_sections, int *num_students, int *num_scores)
{
  //for each section
  for(int s = 0; s<num_sections; s++)
  {
    //for each student
    for(int st = 0; st<num_students[s]; st++)
    {
      //free the laname and scores
      free(sections[s][st].lname);
      free(sections[s][st].scores);
    }
    //free the section
    free(sections[s]);
  }
  //finally free the sections
  free(sections);
}


