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

using namespace std;

void print_menu(){
    cout << "1. Create a new file" << endl;
    cout << "2. Read a file" << endl;
}

string get_file_text(){
    string file_text; // переменная, для хранения текста файла
    char s; // переменная, для хранения символа
    ifstream fin("f1.txt"); // открытие файла на чтение под именем f1.txt

    if (!fin){ // если файл не открылся
        cout << "\nError during opening file. -1\n"; // вывод сообщения об ошибке
        exit(1); // завершение программы
    }

    // посимвольное считывание символов в файле и добавление в строку
	while (fin.get(s))
        file_text.push_back(s);

    fin.close(); // закрытие файла

    return file_text; // возврат полученной строки
}

void output_file_text(string file_text){
    ofstream fout("f1.txt"); // открытие файла на запись под именем f1.txt

    if (!fout){ // если файл не открылся
        cout << "\nError during opening file. -2\n"; // вывод сообщения об ошибке
        exit(2); // завершение программы
    }
    // цикл на прохождение строки
    for (int i = 0; i < file_text.size(); i++)
        fout << file_text[i]; // посимвольный вывод текста в файл  

    fout.close(); // закрытие файла

    cout << "\nText saved to file.\n" << endl;
}

void output_file_words(vector <string> sorted_text){
    ofstream fout("f2.txt"); // открытие файла на запись под именем f2.txt

    if (!fout){ // если файл не открылся
        cout << "\nError during opening file. -3\n"; // вывод сообщения об ошибке
        exit(3); // завершение программы
    }
    // цикл на прохождение массива
    for (int i = 0; i < sorted_text.size(); i++)
        fout << sorted_text[i] << endl; // вывод в файл элемента массива с последующим переносом строки

    fout.close(); // закрытие файла

    cout << "Successful writing to a file." << endl;
}

vector <string> buble_sort(vector <string> words){ // сортировка пузырьком по размеру слов от меньшего к большему
    for (int i = 0; i < words.size(); i++){ // нет, ну правда, что ещё сюда писать
        for (int j = 0; j < words.size() - 1; j++){
            if (words[j].size() > words[j + 1].size()){
                swap(words[j], words[j + 1]); 
            }
        }
    }

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

vector <string> get_sort_words(string file_text){
    vector <string> words; // массив для хранения слов строки (используется вектор для устранения ограничения на размер памяти)
    int start = 0; // счётчик начала слова
    int end = 0; // // счётчик конца слова
    int skip_count = 0; // счётчик пропусков

    for (int i = 0; i <= file_text.size(); i++) { // цикл на прохождение строки
        if (skip_count > 0){ // если есть ряд символов без букв
            skip_count--; // уменьшаем счётчик пропусков
            continue; // переходим на следующую итерацию до следующей буквы в строке
        }
        if (ispunct(file_text[i]) || isspace(file_text[i]) || file_text[i] == '\0'){ // если текущий символ строки не является буквой, то
            skip_count = 0; // обнуляем счётчик от нового слова
            end = i; // счётчик окончания равен текущему значению i
            words.push_back(file_text.substr(start, (end-start))); // добавляем в массив слов часть строки от значения счётчика start. 
            // (end - start) нужен для вычисления количества символов
            while (ispunct(file_text[end]) || isspace(file_text[end])){ // пока текущий символ не является буквой,
                end++; // увеличиваем переменную end
                skip_count++; // увеличиваем количество пропусков в цикле по количеству итераций end
            } // цикл необходим для перехода к следующему слову, так как в задании не указан разделитель слов.

            start = end; // присваиваем счётчику start значение от end для пропуска не буквенных символов и продолжения работы.
        }
    }

    words = buble_sort(words); // сортируем полученный массив слов

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

int main(){
    int choise; // переменная, отвечающая за выбор пользователя
    string file_text; // переменная, для хранения текста файла f1
    string user_text; // переменная, для хранения текста, введённого пользователем
    vector <string> words; // массив отсортированных слов

    print_menu(); // вывод меню с вариантами
    cin >> choise; // получение выбора пользователя
    cin.get(); // очищает строку от оставшихся символов

    switch (choise) // проверка ввода пользователя
    {
    case 1: // если выбран вариант 1
        // получение текста от пользователя
        cout << "\nEnter text:\n\n";
        getline(cin, user_text);
        // перезапись файла f1 и записывание внутрь него текста пользователя
        output_file_text(user_text);

        file_text = get_file_text(); // получение текста из файла f1

        // преообразование полученного текста в массив слов с последующей его сортировкой по размеру от меньшего к большему
        words = get_sort_words(file_text);
        
        output_file_words(words); // вывод отсортированного массива слов в файл f2
        break;
    
    case 2: // если выбран вариант 2
        file_text = get_file_text(); // получение текста из файла f1

        // преообразование полученного текста в массив слов с последующей его сортировкой по размеру от меньшего к большему
        words = get_sort_words(file_text);
        
        output_file_words(words); // вывод отсортированного массива слов в файл f2
        break;
    
    default: // реакция по умолчанию
        cout << "\nIncorrect input\n"; // вывод сообщения об ошибке
        break; // остановка конструкции
    }

    return 0;
}