// Poniej znajduje si w peni zmodyfikowana klasa studentCollection z rozdziau 7.
// Skada si ona z dodatku "dyurny" (zaimplementowanego za pomoc wzorca zasad),
// jak rwnie implementacji iteratora.

#include <iostream>
using std::string;
using std::cout;

// klasa studentRecord, uyta pniej przez studentCollection

class studentRecord {
public:
   studentRecord();
   studentRecord(int newGrade, int newID, string newName);
   int grade();
   void setGrade(int newGrade);
   int studentID();
   void setStudentID(int newID);
   string name();
   void setName(string newName);
   string letterGrade();
protected:
   bool isValidGrade(int grade);
private:
   int _grade;
   int _studentID;
   string _name;
};

bool studentRecord::isValidGrade(int grade) {
   if ((grade >= 0) && (grade <= 100)) 
      return true;
   else 
      return false;
}

int studentRecord::grade() {
   return _grade;
}

void studentRecord::setGrade(int newGrade) {
   if (isValidGrade(newGrade))
      _grade = newGrade;
}

string studentRecord::letterGrade() {
   if (!isValidGrade(_grade)) return "BD";
   const int numberCategories = 9;
   const string gradeLetter[] = {"2", "3-", "3", "3+", "4-", "4", "4+", "5-", "5"};
   const int lowestGradeScore[] = {0, 61, 66, 71, 76, 81, 86, 91, 96};
   int category = 0;
   while (category < numberCategories && lowestGradeScore[category] <= _grade)
      category++;
   return gradeLetter[category - 1];
}

int studentRecord::studentID() {
   return _studentID;
}

void studentRecord::setStudentID(int newID) {
   _studentID = newID;
}

string studentRecord::name() {
   return _name;
}

void studentRecord::setName(string newName) {
   _name = newName;
}

studentRecord::studentRecord(int newGrade, int newID, string newName) {
   setGrade(newGrade);
   setStudentID(newID);
   setName(newName);
}

studentRecord::studentRecord() {
   setGrade(0);
   setStudentID(-1);
   setName("");
}

// ZASADY

typedef bool (* firstStudentPolicy)(studentRecord r1, studentRecord r2);

bool higherGrade(studentRecord r1, studentRecord r2) {
   return r1.grade() > r2.grade();
}

bool lowerStudentNumber(studentRecord r1, studentRecord r2) {
   return r1.studentID() < r2.studentID();
}

bool nameComesFirst(studentRecord r1, studentRecord r2) {
   return strcmp(r1.name().c_str(), r2.name().c_str()) < 0;
}

// zmodyfikowana klasa studentCollection
// dodano metod "firstStudent" oraz zaimplementowano wzorzec zasad i wzorzec iteratora

class studentCollection {
private:
   struct studentNode {
      studentRecord studentData;
	   studentNode * next;
   };
public:
   studentCollection();
   ~studentCollection();
   studentCollection(const studentCollection &copy);
   studentCollection& operator=(const studentCollection &rhs);
   void addRecord(studentRecord newStudent);
   studentRecord recordWithNumber(int IDnum);
   void removeRecord(int IDnum);
   void setFirstStudentPolicy(firstStudentPolicy f);
   studentRecord firstStudent();
   studentRecord recordAt(int position);
   friend class scIterator;
   scIterator firstItemIterator();
private:
   firstStudentPolicy _currentPolicy;
   typedef studentNode * studentList;
   studentList _listHead;
   void deleteList(studentList &listPtr);
   studentList copiedList(const studentList copy);
};

studentCollection::studentCollection() {
   _listHead = NULL;
   _currentPolicy = NULL;
}

studentRecord studentCollection::recordAt(int position) {
   studentNode * loopPtr = _listHead;
   int i = 1;
   while (loopPtr != NULL && i < position) {
      i++;
      loopPtr = loopPtr->next;
   }
   if (loopPtr == NULL) {
      studentRecord dummyRecord(-1, -1, "");
      return dummyRecord;
   } else {
      return loopPtr->studentData;
   }
}

void studentCollection::setFirstStudentPolicy(firstStudentPolicy f) {
   _currentPolicy = f;
}

studentRecord studentCollection::firstStudent() {
   if (_listHead == NULL || _currentPolicy == NULL) {
      studentRecord dummyRecord(-1, -1, "");
      return dummyRecord;
   }
   studentNode * loopPtr = _listHead;
   studentRecord first = loopPtr->studentData;
   loopPtr = loopPtr->next;
   while (loopPtr != NULL) {
      if (_currentPolicy(loopPtr->studentData, first)) {
         first = loopPtr->studentData;
      }
      loopPtr = loopPtr->next;
   }
   return first;
}

void studentCollection::deleteList(studentList &listPtr) {
   while (listPtr != NULL) {
      studentNode * temp = listPtr;
      listPtr = listPtr->next;
      delete temp;
   }
}

studentCollection::~studentCollection() {
   deleteList(_listHead);
}

studentCollection::studentList studentCollection::copiedList(const studentList copy) {
   if (copy == NULL) {
      return NULL;
   }
   studentList newList = new studentNode;
   newList->studentData = copy->studentData;
   studentNode * oldLoopPtr = copy->next;
   studentNode * newLoopPtr = newList;
   while (oldLoopPtr != NULL) {
      newLoopPtr->next = new studentNode;
      newLoopPtr = newLoopPtr->next;
      newLoopPtr->studentData = oldLoopPtr->studentData;
      oldLoopPtr = oldLoopPtr->next;
   }
   newLoopPtr->next = NULL;
   return newList;
}

studentCollection::studentCollection(const studentCollection &copy) {
   _listHead = copiedList(copy._listHead);
}

studentCollection& studentCollection::operator=(const studentCollection &rhs) {
   if (this != &rhs) {
      deleteList(_listHead);
      _listHead = copiedList(rhs._listHead);
   }
   return *this;
}

void studentCollection::addRecord(studentRecord newStudent) {
   studentNode * newNode = new studentNode;
   newNode->studentData = newStudent;
   newNode->next = _listHead;
   _listHead = newNode;
}

void studentCollection::removeRecord(int IDnum) {
   studentNode * loopPtr = _listHead;
   studentNode * trailing = NULL;
   while (loopPtr != NULL && loopPtr->studentData.studentID() != IDnum) {
      trailing = loopPtr;
      loopPtr = loopPtr->next;
   }
   if (loopPtr == NULL) return;
   if (trailing == NULL) {
      _listHead = _listHead->next;
   } else {
      trailing->next = loopPtr->next;
   }
   delete loopPtr;
}

studentRecord studentCollection::recordWithNumber(int IDnum) {
   studentNode * loopPtr = _listHead;
   while (loopPtr != NULL && loopPtr->studentData.studentID() != IDnum) {
      loopPtr = loopPtr->next;
   }
   if (loopPtr == NULL) {
      studentRecord dummyRecord(-1, -1, "");
      return dummyRecord;
   } else {
      return loopPtr->studentData;
   }
}

class scIterator {
public:
   scIterator();
   scIterator(studentCollection::studentNode * initial);
   void advance();
   bool pastEnd();
   studentRecord student();
private:
   studentCollection::studentNode * current;
};

scIterator::scIterator() {
   current = NULL;
}
	
scIterator::scIterator(studentCollection::studentNode * initial) {
   current = initial;
}

scIterator studentCollection::firstItemIterator() {
   return scIterator(_listHead);
}

void scIterator::advance() {
   if (current != NULL) 
      current = current->next;
}

bool scIterator::pastEnd() {
   return current == NULL;
}

studentRecord scIterator::student() {
   if (current == NULL) {
      studentRecord dummyRecord(-1, -1, "");
      return dummyRecord;
   } else {
      return current->studentData;
   }
}

int main() {
   // kod testowy
   // inicjalizacja obiektw studentCollection
   studentRecord s1(89, 38746, "Fryderyk");
   studentRecord s2(98, 49965, "Lucjan");
   studentRecord s3(77, 25354, "Joanna");
   studentRecord s4(80, 55432, "Artur");
   studentCollection sc;
   sc.addRecord(s1);
   sc.addRecord(s2);
   sc.addRecord(s3);
   sc.addRecord(s4);

   // implementacja testowej zasady
   sc.setFirstStudentPolicy(higherGrade);
   studentRecord test = sc.firstStudent();
   cout << "Student z najwysz ocen: " << test.name().c_str() << "\n";
   sc.setFirstStudentPolicy(lowerStudentNumber);
   test = sc.firstStudent();
   cout << "Student o najniszym identyfikatorze: " << test.name().c_str() << "\n";
   sc.setFirstStudentPolicy(nameComesFirst);
   test = sc.firstStudent();
   cout << "Nazwa studenta jako pierwsza w kolejnoci alfabetycznej: " << test.name().c_str() << "\n";

   // testowy iterator
   scIterator iter;
   int gradeTotal = 0;
   int numRecords = 0;
   iter = sc.firstItemIterator();
   while (!iter.pastEnd()) {
      numRecords++;
      gradeTotal += iter.student().grade();
      iter.advance();
   }
   double average = (double) gradeTotal / numRecords;

   return 0;
}

---

#include <iostream>
using std::string;
using std::cout;

// klasa studentRecord, uywana przez insertionSort

class studentRecord {
public:
   studentRecord();
   studentRecord(int newGrade, int newID, string newName);
   int grade();
   void setGrade(int newGrade);
   int studentID();
   void setStudentID(int newID);
   string name();
   void setName(string newName);
   string letterGrade();
protected:
   bool isValidGrade(int grade);
private:
   int _grade;
   int _studentID;
   string _name;
};

bool studentRecord::isValidGrade(int grade) {
   if ((grade >= -1) && (grade <= 100)) 
      return true;
   else 
      return false;
}

int studentRecord::grade() {
   return _grade;
}

void studentRecord::setGrade(int newGrade) {
   if (isValidGrade(newGrade))
      _grade = newGrade;
}

string studentRecord::letterGrade() {
   if (!isValidGrade(_grade)) return "BD";
   const int numberCategories = 9;
   const string gradeLetter[] = {"2", "3-", "3", "3+", "4-", "4", "4+", "5-", "5"};
   const int lowestGradeScore[] = {0, 61, 66, 71, 76, 81, 86, 91, 96};
   int category = 0;
   while (category < numberCategories && lowestGradeScore[category] <= _grade)
      category++;
   return gradeLetter[category - 1];
}

int studentRecord::studentID() {
   return _studentID;
}

void studentRecord::setStudentID(int newID) {
   _studentID = newID;
}

string studentRecord::name() {
   return _name;
}

void studentRecord::setName(string newName) {
   _name = newName;
}

studentRecord::studentRecord(int newGrade, int newID, string newName) {
   setGrade(newGrade);
   setStudentID(newID);
   setName(newName);
}

studentRecord::studentRecord() {
   setGrade(0);
   setStudentID(-1);
   setName("");
}

void insertionSortStudentRecord(studentRecord sra[], int arraySize) {
   int start = 0;
   int end = arraySize - 1;
   for (int i = start + 1; i <= end; i++) {
      for (int j = i; j > start && sra[j-1].grade() > sra[j].grade(); j--) {
         studentRecord temp = sra[j-1];
         sra[j-1] = sra[j];
         sra[j] = temp;
      }
   }
}


int main() {
   // kod testowy
   const int ARRAY_SIZE = 5;
   studentRecord testArray[ARRAY_SIZE];
   studentRecord stu0(88, 2938, "Artur");
   studentRecord stu1(99, 2938, "Tadeusz");
   studentRecord stu2(70, 4875, "Teodor");
   studentRecord stu3(95, 1152, "Sylwia");
   studentRecord stu4(85, 1152, "Bogdan");
   testArray[0] = stu0;
   testArray[1] = stu1;
   testArray[2] = stu2;
   testArray[3] = stu3;
   testArray[4] = stu4;
   insertionSortStudentRecord(testArray, ARRAY_SIZE);

   // wywietlmy nazwy i oceny, aby sprawdzi, czy zostay poprawnie posortowane
   for (int i = 0; i < ARRAY_SIZE; i++) {
      // acuch, uzyskany z metody name(), musi zosta przeksztacony na format jzyka C,
      // aby mona go byo wywietli
      cout << testArray[i].name().c_str() << " " << testArray[i].grade() << "\n";
   }

   return 0;
}