#include <iostream> // библиотке ввода-вывода
#include <string> // библиотека строк
#include <vector> // библиотека векторов (динамических массивов без ограничений памяти)

using namespace std;

class Page {
    string page_title; // заголовок
    string page_text; // текст
    vector <string> page_words; // массив слов текста

    public:

    vector <string> transform_text_to_words(string file_text){ // разбиение текста на отдельные слова
        vector <string> words; // массив для хранения слов строки (используется вектор для устранения ограничения на размер памяти)
        string word = "";

        for (int i = 0; i <= file_text.size(); i++) { // цикл на прохождение строки
            if (!(isspace(file_text[i]) || ispunct(file_text[i]) || file_text[i] == '\0')){
                word.push_back(file_text[i]);
                continue;
            }
            if (word.empty()) continue;
            words.push_back(word);
            word.clear();
        }

        return words; // возвращаем отсортированный массив
    }

    void input_title(string title){ page_title = title; }

    void input_text(string text){ page_text = text; page_words = transform_text_to_words(page_text); }
    // удаление искомого слова на странице
    void delete_target_word(string target_word){
        string new_text = "";

        for (int i = 0; i < page_words.size(); i++){ // цикл на массив слов, содержащихся в тексте
            if (target_word == page_words[i]) continue; // если искомое слово совпадает с текущим - пропускаем итерацию
            new_text.append(page_words[i]);
            new_text.append(" ");
        }

        this->page_text = new_text; // заменяем текст страницы на новый
    }

    string get_text(){ return page_text; }

    string get_title(){ return page_title; }
    // подсчёт вхождений искомого слова
    int get_count_target_word(string target_word){
        int count = 0;

        for (int i = 0; i < page_words.size(); i++){
            if (page_words[i] == target_word){
                count++;
            }
        }

        return count;
    }
};

class Book {
    vector <Page> pages; // количество страниц
    vector <int> count_target_word_in_pages; // количество найденного искомого слова на странице

    public:

    void input_pages_size(int size){ // ввод количества страниц
        pages.resize(size);
        count_target_word_in_pages.resize(size);
    }

    void input_pages(){ // ввод значений страниц
        string title = ""; // заголовок
        string text = ""; // текст
        // последовательный ввод
        for (int i = 0; i < pages.size(); i++){
            cout << "\n\n\t\tInput " << i+1 << " page's title: ";
            getline(cin, title);
            pages[i].input_title(title);

            cout << "\n\t\tInput " << i+1 << " page's text:\n\n\t\t\t";
            getline(cin, text);
            pages[i].input_text(text);
        }
    }
    // вывод страниц
    void output_pages(){
        for (int i = 0; i < pages.size(); i++)
            cout << "\n\n\t\t" << i+1 << " page's title: " << pages[i].get_title() << "\n\t\t" << i+1 << " page's text:\n\n\t\t\t" << pages[i].get_text();
    }
    // удаление искомого слова на заданной странице
    void delete_target_word(string target_word, int page_index){ pages[page_index].delete_target_word(target_word); }
    // подсчёт вхождений искомого слова на всех страницах
    int get_count_target_word(string target_word){
        int count = 0;

        for (int i = 0; i < pages.size(); i++){
            count_target_word_in_pages[i] = pages[i].get_count_target_word(target_word);
        }

        for (int i = 0; i < count_target_word_in_pages.size(); i++){
            count += count_target_word_in_pages[i];
        }

        return count;
    }
    // получение количества страниц
    int get_book_size(){ return pages.size(); }
};

class Library {
    float postfix_increment_overload; // переменная для перегрузки опреатора постфиксинкремента

    int pages_size; // количество страниц

    int book_index = -1; // индекс книги
    int book_max; // количество встречаемового слова в книге

    static int count_book_for_search; // количество книг для поиска слова
    static vector <int> numbers_book_for_search; // номера книг для поиска

    vector <Book> libre; // массив объектов класса "Book"
    vector <int> count_target_word_in_library; // массив для подсчёта количества найденных вхождений введённого слова

    public: // публичные функции
    // получение количества страниц
    int get_pages_size(){ return this->pages_size; }
    // получение индекса книги, в которой наибольшее число раз встречается введённое слово
    int get_book_index(){ return this->book_index; }

    // статическая функция для вывода статических полей (getter, если угодно)
    static void get_static_fields(){
        cout << "\nBooks count for searching target word: ";
        cout << count_book_for_search;
    
        cout << "\nBooks indexs for searching target word: ";
        numbers_book_for_search.resize(count_book_for_search);
        for (int i = 0; i < count_book_for_search; i++){
            cout << numbers_book_for_search[i] << ", ";
        }
        cout << "\n";
    }
    // статическая функция переопределения статических полей класса (setter)
    static void set_static_fields(){
        int num;
        cout << "\nEnter books count for searching target word: ";
        cin >> count_book_for_search;

        if (count_book_for_search < 1){
            cout << "Count can't be less than 1.\n";
            exit(0);
        }

        cout << "\nInput books indexs for searching target word\n";
        numbers_book_for_search.resize(count_book_for_search);
        for (int i = 0; i < count_book_for_search; i++){
            cin >> num;
            numbers_book_for_search[i] = num-1;
        }
    }
    /* конструктор с параметром по умолчанию
    Library(int size){ 
        libre.resize(size);
        count_target_word_in_library.resize(size);
        cout << "Constructor " << this << " initialized\n";
    }
    */
    // конструктор с параметром по умолчанию
    Library(int size = 1){
        libre.resize(size);
        count_target_word_in_library.resize(size);
        cout << "Constructor " << this << " initialized\n";
    }
    // ввод библиотеки
    void input_library(){
        for (int i = 0; i < libre.size(); i++){
            cout << "\n\tInput " << i+1 << " book page's quantity: ";
            cin >> pages_size;
            cin.get();
            cout << endl;

            libre[i].input_pages_size(pages_size);
            libre[i].input_pages();
        }
    }
    // вывод библиотеки
    void output_library(){
        cout << "\n\nOutput lybrary";

        for (int i = 0; i < libre.size(); i++){
            cout << "\n\n\t" << i+1 << " book:";
            libre[i].output_pages();
        }

        cout << "\n\n";
    }
    // поиск книги, в которой введённое слово встречается наибольшее число раз
    int get_book_index(string target_word){
        for (int i = 0; i < numbers_book_for_search.size(); i++){
            count_target_word_in_library[i] = libre[numbers_book_for_search[i]].get_count_target_word(target_word);
        }

        book_max = count_target_word_in_library[0];
        for (int i = 0; i < count_target_word_in_library.size(); i++){
            if (book_max <= count_target_word_in_library[i]){
                book_max = count_target_word_in_library[i];
                book_index = i;
            }
        }

        if (book_max == 0) book_index = -1; // если слово нигде не найдено, то устанвливаем индекс на -1

        return book_index;
    }
    // проверка на наличие страницы в книге
    bool check_page_exist(int page_index){ return (page_index >= 0 && page_index < libre[book_index].get_book_size()); }

    void delete_target_word(string target_word, int page_index){ libre[book_index].delete_target_word(target_word, page_index); }

    void operator++(int _num){ // перегрузка оператора постинкремента
        this->postfix_increment_overload = 0;
        this->postfix_increment_overload = _num + 30; 
    }

    float get_postfix_increment_overload() { return this->postfix_increment_overload; } // возвращение переменной, задействованной в перегрузке унарного оператора

    ~Library(){ // деструктор
        cout << "Destructor " << this << " initialized\n";
    }
};

ostream& operator<< (ostream& out, Library& _lib) //перегрузка оператора вывода
{
    return out << "Book index: " << _lib.get_book_index() << " | Pages: " << _lib.get_pages_size() << "\n\n";
}
// статитические поля и функции здесь отвечают за количество книг,а также за номера страниц, 
// в которых будет осуществлятляться поиск слова, введённого пользователем
int Library::count_book_for_search = 1; // определение по умолчанию
vector <int> Library::numbers_book_for_search = {0};    

int main(){
    char static_choise; // изменение значений статических переменных
    int books_size; // количество книг
    int book_index; // индекс найденной книги
    int page_index; // индекс выбранной страницы
    
    string target_word; // искомое слово

    Library *lib; // указатель для последующей инициализации объекта (АКА динамика для 4 (8) задания)
    
    system("clear"); // очистка экрана
    // ввод количества книг в библиотеке
    cout << "Input library size: ";
    cin >> books_size;
    cin.get();
    cout << endl;
    
    if (books_size > 0){ // проблема с областью видимости в if. Уточнить у преподавателя.
        lib = new Library(books_size); // явная инициализация объекта с передачей параметра
    }
    else { // явная инициализация объекта без передачи параметра
        cout << "\nLibrary's size can't be less than 1, so it's sets to 1.\n";
        lib = new Library();
    }
    // ввод библиотеки
    (*lib).input_library();

    // изменение статических полей по желанию
    Library::get_static_fields();
    cout << "\nDo you want to set static fields after input? (y/n): "; cin >> static_choise;
    if (static_choise == 'y') Library::set_static_fields();
    // ввод искомого слова
    cout << "\n\nInput target word: ";
    cin >> target_word;
    cin.get();
    cout << endl;
    // получение индекс книги, в которой искомое слово встречается наибольшее число раз
    book_index = (*lib).get_book_index(target_word);

    if (book_index == -1){ // если индекс -1, то искомое слово нигде не найдено, соответственно - завершаем программу
        cout << "\nInputed word doesn't find.\n";
        return 0;
    }
    // вывод найденной книги
    cout << "\nIndex of found book: " << book_index + 1 << endl;
    // ввод номера страницы, на которой надо удалить слово
    cout << "\n\nInput book's page: ";
    cin >> page_index;
    cin.get();
    cout << endl << endl;
    // проверка на наличие данной страницы
    if (!((*lib).check_page_exist(page_index - 1))){ // если страницы не существует, то завершаем программу
        cout << "Inputed index page doesn't exist.\n";
        delete lib; // удаление динамического объекта для чистки ОЗУ
        return 0;
    }

    (*lib).delete_target_word(target_word, page_index - 1); // удаление искомого слова на данной странице

    (*lib).output_library(); // вывод библиотеки

    (*lib).operator++(book_index + 1); // вывод перегруженного оператора постинкремента

    cout << (*lib); // вывод значений через перегрузку оператора вывода

    delete lib; // удаление динамического объекта для чистки ОЗУ

    return 0;
}