// File: inclass23.cpp
// This program reads in student names and scores from a file, computes the
// average score for each student and displays the student names, average
// score, and letter grade in descending order.  It does this using a vector
// of Student objects
//
// Input: number of students, student names and scores
// Output: student names, average score, and letter grade
// ----------------------------------------------------------------------
// Class: CS 210                         Instructor: Drs. Hwang & Roberts
// Assignment: In-class Exercise for 4/4/07 & 4/5/07
// Programmer(s): <fill in your names>

#include <iostream>   // cin, cout, <<, >>, ignore
#include <fstream>    // ifstream
#include <string>     // string, getline
#include <iomanip>    // setw
#include <vector>     // vector
#include "student.h"  // Student
using namespace std;

// Function prototypes
void InteractiveOpen (ifstream & inStream);
void InteractiveOpen (ofstream & outStream);
void ReadData (vector <Student> & students);
void SortData (vector <Student> & students);
int FindIndexOfLargest (const vector<Student> students, int startIndex);
void Swap (Student & first, Student & second);
void DisplayData (const vector<Student> & students);
void WriteData (const vector<Student> & students);

// Global constants
const int MAX_FILE_NAME = 80; // Maximum number of characters in file name

int main ()
{
   vector<Student> students;  // vector of Student objects

   // Read in data and compute average scores
   ReadData (students);
   
   // Sort data in descending order by average score
   SortData (students);

   // Display data with letter grades in table format
   DisplayData (students);
   
   // Write sorted data back into a file
   WriteData (students);
   return 0;
}  // end main

// Function: InteractiveOpen (for input file streams)
// Asks the user for a file name and connects the file to theIFStream
void InteractiveOpen (ifstream & inStream)  
                         // RECEIVED & PASSED BACK: input file stream
{
   char inputFileName[MAX_FILE_NAME];  // input file name

   cout << "\nEnter the name of the input file: ";
   cin >> inputFileName;

   inStream.open(inputFileName);

   if (!inStream.is_open())
   {
      cerr << "\n***InteractiveOpen(): unable to open "
           << inputFileName << endl;
      exit(1);
   }  // end if
}  // end InteractiveOpen for input file streams

// Function: InteractiveOpen (for output file streams)
// Asks the user for a file name and connects the file to theIFStream
void InteractiveOpen (ofstream & outStream)  
                         // RECEIVED & PASSED BACK: input file stream
{
   char outputFileName[MAX_FILE_NAME];  // output file name

   cout << "\nEnter the name of the output file: ";
   cin >> outputFileName;

   outStream.open(outputFileName);

   if (!outStream.is_open())
   {
      cerr << "\n***InteractiveOpen(): unable to open "
           << outputFileName << endl;
      exit(1);
   }  // end if
}  // end InteractiveOpen for output file streams

// Function: ReadData
// Reads in number of students, names and scores of students from a file
// Computes average score (averageScore[i]) for each student (name[i])
void ReadData (vector<Student> & students)      // PASSED BACK: vector of students
{
   ifstream inStream;  // input file stream
   int numStudents;
   Student aStudent;

   // Open data file
   InteractiveOpen(inStream);

   // Read in number of students
   inStream >> numStudents;
   inStream.ignore();   // get rid of the trailing newline
   
   // For each student, read in student data
   for (int i = 0; i < numStudents; i++)
   {
      inStream >> aStudent;  // will take out trailing newline like getline()
      students.push_back(aStudent);
   }
      
   // Close file
   inStream.close();
}  // end ReadData

// Function: SortData
// Sorts both arrays into descending order based on average score
void SortData (vector<Student> & students) 
                   // REC'D & PASSED BACK: vector of students
{
   int indexOfLargest;   // index of largest average each pass
   
   // Sort based on average score in descending order using selection
   // sort algorithm
   for (unsigned int pass = 0; pass < students.size() - 1; pass++)
   {
      indexOfLargest = FindIndexOfLargest(students, pass);
      Swap (students[pass], students[indexOfLargest]);
   }  // end for
}  // end SortData

// Function: FindIndexOfLargest
// Returns: index of the largest element starting with startIndex
int FindIndexOfLargest (const vector<Student> aVector, 
                                         // REC'D: vector to search
                        int startIndex)  // REC'D: index to start search
{
   int indexOfLargest = startIndex;  // index of largest average seen so far

   // Consider each element from startIndex+1 to end
   for (unsigned int i = startIndex+1; i < aVector.size(); i++)
      if (aVector[i] > aVector[indexOfLargest])
         indexOfLargest = i;    // element at index i is largest now
   return indexOfLargest;
}  // end FindIndexOfLargest

// Function:Swap (for Students)
// Exchanges two values
void Swap (Student & first,    // RECEIVED & PASSED BACK: first number
           Student & second)   // RECEIVED & PASSED BACK: second number
{
   Student temporary = first;
   first = second;
   second = temporary;
}  // end Swap

// Function: DisplayData
// Displays student names, average scores, and letter grades to screen
// in tabular format
void DisplayData (const vector <Student> & students) 
                               // REC'D: vector of students
{
   // Magic code to set formatting to one decimal place
   cout.setf(ios::fixed);
   cout.setf(ios::showpoint);
   cout.precision(1);

   cout << "Here are the grades of the students\n\n";

   // Table heading
   cout << "Name                    Average       Grade\n"
        << "-------------------------------------------\n";

   // For each student print out name, average score, and letter grade
   for (unsigned int i = 0; i < students.size(); i++)
      cout << left << setw(20) << students[i].Name()
           << right << setw(10) << students[i].AverageScore()
           << setw(12) << students[i].LetterGrade() << endl;
}  // end DisplayData

// Function: WriteData
// Writes student data out into a file in the format expected by ReadData
void WriteData (const vector<Student> & students)
                               // REC'D: vector of students
{
   ofstream outStream;

   // Open data file
   InteractiveOpen (outStream);

   // Write number of students
   outStream << students.size() << endl;

   // Write each student's information
   for (unsigned int i = 0; i < students.size(); i++)
      outStream << students[i] << endl;

   // Close file
   outStream.close();
}  // end WriteData
