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

typedef struct {
    char * grade;
    int * hws;
    int * quizzes;
    int sid;
} Student;

typedef struct {
    int num_hws;
    int num_quizzes;
    int size;
    Student * students;
} Course;

char ** course_grades( Course * );
int find_minimum( int *, int );
float hw_points( int *, int );
float quiz_points( int *, int );
char * student_grade( Student *, int, int );
int sum_list( int *, int );

int main() {

    int i;
    int num_hws = 12;
    int num_quizzes = 9;
    char ** grades;

    int * hw_scores = malloc( num_hws * sizeof( int ) );
    hw_scores[0] = 25;
    hw_scores[1] = 20;
    hw_scores[2] = 18;
    hw_scores[3] = 22;
    hw_scores[4] = 25;
    hw_scores[5] = 20;
    hw_scores[6] = 23;
    hw_scores[7] = 25;
    hw_scores[8] = 17;
    hw_scores[9] = 15;
    hw_scores[10] = 23;
    hw_scores[11] = 24;

    int * quiz_scores = malloc( num_quizzes * sizeof( int ) );
    quiz_scores[0] = 50;
    quiz_scores[1] = 32;
    quiz_scores[2] = 43;
    quiz_scores[3] = 38;
    quiz_scores[4] = 40;
    quiz_scores[5] = 46;
    quiz_scores[6] = 35;
    quiz_scores[7] = 50;
    quiz_scores[8] = 42;

    Student * course_list = malloc( 3 * sizeof( Student ) );

    course_list[0].quizzes = quiz_scores;
    course_list[0].hws = hw_scores;
    course_list[0].sid = 0;

    // You can test out the student_grade function on a single student like this:
    // printf( "\n" );
    // printf( "Student #0 earned grade:  %s\n", student_grade( &course_list[0], num_hws, num_quizzes ) );
    printf( "\n" );

    hw_scores = malloc( num_hws * sizeof( int ) );
    quiz_scores = malloc( num_quizzes * sizeof( int ) );

    for ( i = 0; i < num_hws; i++ ) {
        hw_scores[i] = 18;
    }
    for ( i = 0; i < num_quizzes; i++ ) {
        quiz_scores[i] = 36;
    }

    course_list[1].hws = hw_scores;
    course_list[1].quizzes = quiz_scores;
    course_list[1].sid = 1;

    hw_scores = malloc( num_hws * sizeof( int ) );
    quiz_scores = malloc( num_quizzes * sizeof( int ) );

    for ( i = 0; i < num_hws; i++ ) {
        hw_scores[i] = 25;
    }
    for ( i = 0; i < num_quizzes; i++ ) {
        quiz_scores[i] = 50;
    }

    course_list[2].hws = hw_scores;
    course_list[2].quizzes = quiz_scores;
    course_list[2].sid = 2;

    Course cop3275;
    cop3275.num_hws = num_hws;
    cop3275.num_quizzes = num_quizzes;
    cop3275.size = 3;
    cop3275.students = course_list;

    grades = course_grades( &cop3275 );

    for ( i = 0; i < 3; i++ ) {
        printf( "Student SID #%d earned grade %s\n", course_list[i].sid, course_list[i].grade );

        // free up allocated memory
        free( course_list[i].hws );
        free( course_list[i].quizzes );
    }

    // free up allocated memory
    free( grades );
    free( course_list );

    printf( "\n" );
    return 0;
}

char ** course_grades( Course * course ) {

    int i;
    char ** grades;

    // allocate memory for the size of the course
    grades = malloc( ( *course ).size * sizeof( char ) );

    Student * students = ( *course ).students;

    for ( i = 0; i < ( *course ).size; i++ ) {
        grades[i] = student_grade( students + i, ( *course ).num_hws, ( *course ).num_quizzes );
    }

    return grades;
}

int find_minimum( int * list, int N ) {
    int i, index = 0;

    for ( i = 1; i < N; i++ ) {
        if ( list[i] < list[index] ) {
            index = i;
        }
    }

    return index;
}

float hw_points( int * hws, int num_hws ) {
    int min;
    float hw_total = 0;

    min = find_minimum( hws, num_hws );
    hw_total = sum_list( hws, num_hws );

    hw_total = ( ( hw_total - hws[min] ) / ( ( num_hws - 1 ) * 25 ) ) * 40;

    return hw_total;
}

float quiz_points( int * quizzes, int num_quizzes ) {
    int min;
    float quiz_total = 0;

    min = find_minimum( quizzes, num_quizzes );
    quiz_total = sum_list( quizzes, num_quizzes );

    quiz_total = ( ( quiz_total - quizzes[min] ) / ( ( num_quizzes - 1 ) * 50 ) ) * 60;

    return quiz_total;
}

char * student_grade( Student * student, int num_hws, int num_quizzes ) {
    char * grade;
    float hwp, qp, total;

    hwp = hw_points( ( *student ).hws, num_hws );
    qp = quiz_points( ( *student ).quizzes, num_quizzes );

    total = hwp + qp;

    if ( total >= 92 ) {
        grade = "A";
    }
    else if ( total >= 89 && total < 92 ) {
        grade = "A-";
    }
    else if ( total >= 86 && total < 89 ) {
        grade = "B+";
    }
    else if ( total >= 82 && total < 86 ) {
        grade = "B";
    }
    else if ( total >= 79 && total < 82 ) {
        grade = "B-";
    }
    else if ( total >= 76 && total < 79 ) {
        grade = "C+";
    }
    else if ( total >= 72 && total < 76 ) {
        grade = "C";
    }
    else if ( total >= 69 && total < 72 ) {
        grade = "C-";
    }
    else if ( total >= 66 && total < 69 ) {
        grade = "D+";
    }
    else if ( total >= 62 && total < 66 ) {
        grade = "D";
    }
    else if ( total >= 59 && total < 62 ) {
        grade = "D-";
    }
    else {
        grade = "E";
    }

    ( *student ).grade = grade;

    // print each calculation along the way
    printf( "SID#:   %d\n", ( *student ).sid );
    printf( "Total:  %f\n", total );
    printf( "Grade:  %s\n", grade );
    printf( "\n" );

    return grade;
}

int sum_list( int * list, int N ) {
    int i, total = 0;

    for ( i = 0; i < N; i++ ) {
        total = total + list[i];
    }

    return total;
}
