// CIS22B - "Old" Assignment 3 Solution using structs

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <string>
using namespace std;

const unsigned short NumberOfStudents = 50;
const unsigned short PointsPossible = 400;
const unsigned short NumberOfAssignments = 8;

struct Assignments
{
    int assignment[NumberOfAssignments];
    int assignmentTotal;
};

struct Student
{
    int id;
    Assignments assignments;
    int labExercises;
    int midterm;
    int final;
    int codeLabPoints;
    int totalPoints;
    int percentOfTotal;
    string grade;
};

struct Class
{
    Student students[NumberOfStudents];
};

const string InputFilename = "c:/temp/ass1data.txt";
const string OutputFile1 = "c:/temp/ass2output1.txt";
const string OutputFile2 = "c:/temp/ass2output2.txt";

void readPointsFromFile(const string& filename,Class&);
int  calculateAssTotalPoints(int[]);
void calculateTotalPointsAndPercent(Class&);
void calculateGrades(Class&);
string getGradeFromPercent(int points);

void printReport(const string& filename, const Class&);
void printStudentRecord(ostream& out, const Student&);

void sortDataByColumn(Class&, string column = "id", char AscendingDecending = 'A');
void swapStudent(Student& a, Student& b);
void intSwap(int& a, int& b);
void stringSwap(string& a, string& b);



int main()
{
    Class students;

    readPointsFromFile(InputFilename,students);

    calculateTotalPointsAndPercent(students);

    calculateGrades(students);
    printReport(OutputFile1,students);

    // sort data by student ID
    sortDataByColumn(students);
    printReport(OutputFile1,students);

    // sort data by total points descending
    sortDataByColumn(students,"percent",'D');
    printReport(OutputFile2,students);
}

void readPointsFromFile(const string& filename, Class& data)
{
    ifstream fin(filename.c_str());

    if (!fin)
    {
        cerr << "Unable to open file, " << InputFilename << endl;
        exit(1);
    }
    for (int i = 0; i < NumberOfStudents; i++)
    {
        fin >> data.students[i].id;
        fin >> data.students[i].labExercises;
        for (int j = 0; j < NumberOfAssignments; j++)
        {
            fin >> data.students[i].assignments.assignment[j];
        }
        fin >> data.students[i].midterm;
        fin >> data.students[i].final;
        fin >> data.students[i].codeLabPoints;
    }
    fin.close();
}

int calculateAssTotalPoints(int data[])
{
    int min, sum;
    min = data[0];
    sum = data[0];

    // Determine sum and minimum of first 7 assignments
    for (int i = 1; i < NumberOfAssignments-1; i++)
    {
        if (min > data[i]) min = data[i];
        sum += data[i];
    }
    sum += data[NumberOfAssignments-1] - min;
    return sum;
}

void calculateTotalPointsAndPercent(Class& data)
{
    for (int i = 0; i < NumberOfStudents; i++)
    {
        data.students[i].assignments.assignmentTotal = calculateAssTotalPoints(data.students[i].assignments.assignment);
        data.students[i].totalPoints = data.students[i].midterm + data.students[i].labExercises + data.students[i].codeLabPoints + data.students[i].final + data.students[i].assignments.assignmentTotal;
        // Round points to the nearest int
        data.students[i].percentOfTotal = static_cast<int>((100. * data.students[i].totalPoints / PointsPossible +0.5));
    }
}

void calculateGrades(Class& data)
{
    for (int i = 0; i < NumberOfStudents; i++)
    {
        data.students[i].grade = getGradeFromPercent(data.students[i].percentOfTotal);
    }
}

string getGradeFromPercent(int pct)
{
    string grade;
    switch (pct/10)
    {
    case 6:
        grade = 'D';
        break;
    case 7:
        grade = 'C';
        break;
    case 8:
        grade = 'B';
        break;
    case 9:
    case 10:
        grade = 'A';
        break;
    default:
        grade = 'F';
    }
    if (pct >97) grade += '+';
    else if (pct > 59)
    {
        if (pct % 10 > 7) grade += '+';
        if (pct % 10 < 2) grade += '-';
    }
    return grade;
}

void printReport(const string& filename, const Class& data)
{
    ofstream fout(filename.c_str());

    if (!fout)
    {
        cerr << "Unable to open file, " << filename << endl;
        exit(2);
    }

    // Print headings
    fout << "Stdnt Id  Ex  ----- Assignments -----  Tot  Mi  Fin  CL  Pts  Pct  Gr" << endl;
    fout << "--------  --  -----------------------  ---  --  ---  --  ---  ---  --" << endl;

    for (int i = 0; i < NumberOfStudents; i++)
    {
        printStudentRecord(fout,data.students[i]);
    }
}

void printStudentRecord(ostream& out, const Student& student)
{
    out << setfill('0') << setw(8) << right << student.id << setfill(' ') << ' ';
    out << setw(3) << student.labExercises << ' ';
    for (int i = 0 ; i < NumberOfAssignments; i++)
        out << setw(3) << student.assignments.assignment[i];
    out << setw(5) << student.assignments.assignmentTotal
        << setw(4) << student.midterm
        << setw(5) << student.final
        << setw(4) << student.codeLabPoints
        << setw(5) << student.totalPoints
        << setw(5) << student.percentOfTotal << "  "
        << setw(2) << left << student.grade << endl;
}

void sortDataByColumn(Class& data, string column, char AscendingDecending)
{
    int i, j;
    int firstValue, secondValue;
    for (i = 0; i < NumberOfStudents - 1; i++)
    {
        for (j = i+1; j < NumberOfStudents; j++)
        {
            if (column == "id")
            {
                firstValue = data.students[i].id;
                secondValue = data.students[j].id;
            }
            else if (column == "percent")
            {
                firstValue = data.students[i].percentOfTotal;
                secondValue = data.students[j].percentOfTotal;
            }
            if (AscendingDecending == 'A')
            {
                if (firstValue > secondValue) swapStudent(data.students[i],data.students[j]);
            }
            else
            {
                if (firstValue < secondValue) swapStudent(data.students[i],data.students[j]);
            }
        }
    }
}

void    swapStudent(Student& a, Student& b)
{
    intSwap(a.id,b.id);
    for (int i = 0; i < NumberOfAssignments; i++)
        intSwap(a.assignments.assignment[i],a.assignments.assignment[i]);
    intSwap(a.labExercises,b.labExercises);
    intSwap(a.midterm,b.midterm);
    intSwap(a.final,b.final);
    intSwap(a.codeLabPoints,b.codeLabPoints);
    intSwap(a.totalPoints,b.totalPoints);
    intSwap(a.percentOfTotal,b.percentOfTotal);
    stringSwap(a.grade,b.grade);
}

void intSwap(int& a, int& b)
{
    int temp = a;
    a = b;
    b= temp;
}

void stringSwap(string& a, string& b)
{
    string temp = a;
    a = b;
    b= temp;
}