#include <iostream>
#include <vector>

using namespace std;

int input_count();

class Student {
    string last_name; // фамилия ученика
    int grade; // оценка ученика

    public:

    void input(){
        // переменные для ввода фамилии и оценки
        string last_name;
        int grade = 0;

        while (last_name.empty()){
            cout << "\t\t\tInput student's last name: ";
            cin >> last_name;
            cin.get();
        }

        while (grade < 2 || grade > 5){
            cout << "\t\t\tInput student's grade: ";
            cin >> grade;
            cin.get();
        }
        
        cout << "\n";
        // присваивание переменным объекта значений из переменных ввода
        this->last_name = last_name;
        this->grade = grade;
    }

    void output(){ // вывод фамилии и оценки
        cout << "Student's last name: " << this->last_name << "\n\t\t\t";
        cout << "Student's grade: " << this->grade << "\n\n";
    }

    string get_last_name(){ return this->last_name; } // получение фамилии

    int get_grade(){ return this->grade; } // получение оценки
};

class Journal {
    vector <Student> journal; // массив с объектами класса Student
    vector <int> bad_grades; // массив для подсчёта количества двоешников

    public:

    void input(){ // ввод объектов класса Student
        int count = 0;

        while (count < 1){
            cout << "\tInput students count: ";
            cin >> count;
            cin.get();
            cout << "\n";
        }

        journal.resize(count);
        
        for (int i = 0; i < count; i++){
            cout << "\t\tInput " << i+1 << " student's data:\n\n";
            journal[i].input();
        }
        
        cout << "\n";
    }

    void output(){ // вывод массива с объектами Student
        for (int i = 0; i < journal.size(); i++){
            cout << "\t\t" << i+1 << " student's data:\n\n\t\t\t";
            journal[i].output();
        }
    }

    int get_bad_grade(){ // получение количества и индексов учеников с оценкой 2
        for (int i = 0; i < journal.size(); i++){
            if (journal[i].get_grade() == 2) // если оценка равна 2
                this->bad_grades.push_back(i); // добавляем индекс в массив двоешников
        }
        
        return this->bad_grades.size(); // возвращаем размер массива, то бишь количество двоешников
    }

    void output_bad_grade(){ // вывод двоешников
        for (int i = 0; i < this->bad_grades.size(); i++){
            cout << "\t\t" << i+1 << " student's data:\n\n\t\t\t";
            journal[this->bad_grades[i]].output();
        }
    }

    void delete_in_list(int _worst_students_count){ // функция для удаления учеников с фамилиями, совпадающими со списком пользователя 
        vector <Student> new_journal; // создание нового объекта
        int count = 0;

        for (int i = 0; i < journal.size(); i++){
            if (journal[i].get_grade() == 2){ // если фамилия есть в списке пользователя
                if (count >= _worst_students_count) goto add;
                count++;
                continue; // пропускаем её
            }
            add: ;
            new_journal.push_back(journal[i]); // добавляем ученика в новый список
        }

        this->journal = new_journal; // присваиваем значение нового журнала в переменную объекта
    }
};

class JournalsDB {
    vector <Journal> journal_db; // массив с объектами класса Journal
    vector <int> bad_grades; // целочисленный массив для подсчёта двоешников

    static int worst_students_count;

    public:

    static int get_wost_students_count(){ return worst_students_count; }

    static void set_worst_students_count(int _worst_students_count){
        worst_students_count = _worst_students_count;
    }

    JournalsDB(){
        cout << "Constructor " << this << " initialized\n\n";
        input(input_count());
    }

    JournalsDB(int count){ // конструктор
        cout << "Constructor " << this << " initialized\n\n";
        input(count); // выхов функции ввода у объекта
    }
/*  Конструктор с аргументом по умолчанию
    JournalsDB(int count = 1){
        cout << "Constructor " << this << " initialized\n\n";
        input(count); // выхов функции ввода у объекта
    }
*/
    ~JournalsDB(){ // деструктор
        cout << "\nDestructor " << this << " initialized\n\n"; //
    }

    void input(int count){ // функция ввода
        journal_db.resize(count);

        for (int i = 0; i < count; i++){
            cout << "Input " << i+1 << " journal:\n\n";
            journal_db[i].input();
        }
        
        cout << "\n\n";
    }

    void output(){ // функция вывода
        cout << "Output jouranls database\n\n";

        for (int i = 0; i < journal_db.size(); i++){
            cout << i+1 << " journal:\n\n";
            journal_db[i].output();
        }

        cout << "\n\n";
    }

    int get_bag_grade(){ // функция получения двоешников
        int count = 0; // количество двоешников в целом

        bad_grades.resize(journal_db.size());

        for (int i = 0; i < bad_grades.size(); i++){
            bad_grades[i] = journal_db[i].get_bad_grade(); // получаем значения на каждый отдельный журнал
        }

        for (int i = 0; i < bad_grades.size(); i++){
            count += bad_grades[i]; // подсчитываем общее количество
        }

        return count; // возвращаем общее количество двоешников
    }

    int get_wost_journal(){ // функция нахождения журнала с наибольшим количеством двоешников
        int worst_journal = -1; // по умолчанию индекс отсутствует
        int count = 0; // переменная для нахождения наибольшего значения
        // обычный алгоритм поиска наибольшего значения
        for (int i = 0; i < bad_grades.size(); i++){
            if (bad_grades[i] > count){
                count = bad_grades[i];
                worst_journal = i; // если значение в массиве больше count, то обновляем последний, а также индекс худшего журнала
            }
        }

        return worst_journal; // возвращаем индекс
    }

    void output_bad_grade(){ // вывод учеников с оценкой 2
        cout << "Output jouranls with worst students\n\n";

        for (int i = 0; i < bad_grades.size(); i++){
            if (bad_grades[i] <= 0)
                continue;
            cout << i+1 << " journal:\n\n";
            journal_db[i].output_bad_grade();
        }
    }

    void delete_in_list(int worst_journal){ // удаление введённых фамилий
        journal_db[worst_journal].delete_in_list(worst_students_count); // вызов функции удаления в журнале с найденным индексом
    }

    void operator++(int wors_journal){
        cout << "Worst journal in overload: " << wors_journal + 1 << endl;
    }
};

ostream& operator<< (ostream& out, JournalsDB& _jdb) //перегрузка оператора вывода
{
    return out << "Output overload worst journal: " << _jdb.get_wost_journal() + 1 << "\n\n";
}

enum ConstructorChoise{ // enum тут больше для понтов, но по факту тот же самый switch case, как в задании с файлами
    DEFAULT,
    WITH_PARAMETERS
};

int input_count(){ // так как мне ну очень лень писать эти строчки по 5 раз, я просто сделал здесь функцию, на 6 строке объявил прототип, чтобы компилятор не ругался
    int count = 0;

    while (count < 1){
        cout << "Input journals count: ";
        cin >> count;
        cin.get();
        cout << "\n";
    }

    return count;
}

int JournalsDB::worst_students_count = 1; // количество студентов для удаления по умолчанию - 1

int main(){
    JournalsDB* school_journals_db;

    int worst_journal = -1; // индекс журнала с большим количеством двоешников
    int bad_grade_count = 0; // общее количество двоешников

    int choise; // выбор типа конструктора

    char change_count_students; // изменить количество студентов для удаления
    int count_students; // новое количество студентов для удаления

    cout << "Please, choose constructor's type:" << "\n";
    cout << "1. Default constructor (without parameters)." << "\n";
    cout << "2. Constructor with parameters." << "\n";

    cin >> choise;

    switch (choise - 1) // отнимаем 1, так как отсчёт идёт с нуля
    {
    case ConstructorChoise::DEFAULT:
        cout << "\n" << "DEFAULT" << "\n\n";
        school_journals_db = new JournalsDB(); // инициализация объекта класса JournalsDB
        break;
    case ConstructorChoise::WITH_PARAMETERS:
        cout << "\n" << "WITH_PARAMETERS" << "\n\n";
        school_journals_db = new JournalsDB(input_count()); // инициализация объекта класса JournalsDB и передача введённого размера для количества журналов 
        break;
    default:
        cout << "\n" << "Incorrect input." << "\n\n";
        return 0;
        break;
    }

    bad_grade_count = (*school_journals_db).get_bag_grade(); // получение общего количества двоешников

    cout << "Total number of worst students: " << bad_grade_count << "\n\n"; // вывод общего количества двоешников

    (*school_journals_db).output_bad_grade(); // вывод всех двоешников

    worst_journal = (*school_journals_db).get_wost_journal(); // получение индекса журнала с наибольшим количеством двоешников

    if (worst_journal == -1){ // если такого журнала нет, то выводим сообщение об этом и завершаем программу
        cout << "The worst journal doesn't exist.\n";
        return 0;
    }

    cout << "\n\nThe worst journal is " << worst_journal+1 << "\n\n"; // вывод полученного индекса

    cout << "Count students for delete: " << JournalsDB::get_wost_students_count << endl;
    cout << "Do you want to change that value? y/n "; cin >> change_count_students;

    if (change_count_students == 'y') {
        cout << "Input new count: "; cin >> count_students;
        JournalsDB::set_worst_students_count(count_students);
    }

    (*school_journals_db).delete_in_list(worst_journal); // вызов функции для удаления фамилий

    (*school_journals_db).output(); // вывод журналов

    (*school_journals_db).operator++(worst_journal);

    cout << "\n";

    cout << (*school_journals_db);

    delete school_journals_db;

    return 0; // конец
}