#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(); // закрытие файла
}

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(); // закрытие файла
}

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> sorted_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
sorted_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 для пропуска не буквенных символов и продолжения работы.
}
}

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

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


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

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

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

return 0;
}