#include "pch.h"
#include <iostream>
#include <conio.h>
#include <string>
#include <iomanip>
#include <windows.h>

using namespace std;

class TRAIN {
private:
	string nomer, des, hour, min;
	int number;
	TRAIN *next;//указатель на следующий
public:
	void set_all_data(TRAIN **top);//заполнить данные
	void del(TRAIN **top, int &numberFirst);//удалить элемент стека по названию
	void show(TRAIN **top);//показать всё
	void search(TRAIN **top);//найти 
	void swap(TRAIN **first, TRAIN **second, int &numberFirst, int &numberSecond);
	void take_out(TRAIN **top);//удалить всё
};

void Cleaning() {
	cin.clear();
	while (cin.get() != '\n');
}

void Protect(int &n, string temp, int m, int k);

int main() {
	system("mode con cols=85 lines=30");
	SetConsoleCP(1251); //русификация 
	SetConsoleOutputCP(1251); //русификация
	int numberFirst = 0, numberSecond = 0;
	TRAIN *top_in = nullptr;
	TRAIN *top_out = nullptr;
	TRAIN poezd; //взаимодейтсвие с функциями класса
	int n; //номер пункта меню
	int end_flag = 0; //выход из программы
	int flag_v = 0; //флаг ввода
	do {
		system("cls");
		cout << "Меню:" << endl;
		cout << "1. Добавить поезд" << endl;
		cout << "2. Удалить поезд" << endl;
		cout << "3. Вывод информации" << endl;
		cout << "4. Поиск по времени прибытия" << endl;
		cout << "5. Перевод поезда из прибывающих в задерживающиеся" << endl;
		cout << "6. Перевод поезда из задерживающихся в прибывающие" << endl;
		cout << "7. О программе" << endl;
		cout << "8. Помощь" << endl;
		cout << "9. Выход\n" << endl;
		Protect(n, "\nВведите номер пункта меню: ", 1, 9);
		cout << "\nДля продолжения нажмите любую клавишу..." << endl;
		_getch();
		system("cls");
		switch (n) {
		case 1:
			do {
				poezd.set_all_data(&top_in);
				cout << "\nВы хотите продолжить? (1 - Да, 2 - Нет)" << endl;
				Protect(flag_v, "\nВаш выбор: ", 1, 2);
			} while (flag_v == 1);

			cout << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 2:
			if (top_in) {
				flag_v = 0;
				do {
					poezd.del(&top_in, numberFirst);
					cout << "\nВы хотите продолжить? (1 - Да, 2 - Нет)" << endl;
					Protect(flag_v, "\nВаш выбор: ", 1, 2);
				} while (flag_v == 1);
			}
			else {
				cout << "\nCписок пуст!" << endl;
			}

			cout << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 3:
			do {
				system("cls");
				cout << "1. Посмотреть список прибывающих поездов" << endl;
				cout << "2. Посмотреть список задерживающихся поездов" << endl;
				cout << "3. Посмотреть оба списка" << endl;
				cout << "4. Вернуться в главное меню" << endl;
				Protect(n, "\nВведите номер пункта меню: ", 1, 4);
				cout << "\nДля продолжения нажмите любую клавишу..." << endl;
				_getch();
				system("cls");
				switch (n) {
				case 1:
					if (top_in) {
						cout << "\nПрибывающие поезда:\n" << endl;
						poezd.show(&top_in);
					}
					else {
						cout << "\nСписок пуст!" << endl;
					}

					cout << "\nДля продолжения нажмите любую клавишу..." << endl;
					_getch();
					break;
				case 2:
					if (top_out) {
						cout << "\nЗадерживающиеся поезда:\n" << endl;
						poezd.show(&top_out);
					}
					else {
						cout << "\nВы ещё не перемещали поезда!" << endl;
					}

					cout << "\nДля продолжения нажмите любую клавишу..." << endl;
					_getch();
					break;
				case 3:
					cout << "Поезда и задерживающиеся, и прибывающие:" << endl;
					if (top_in) {
						cout << "\nПрибывающие поезда:\n" << endl;
						poezd.show(&top_in);
					}
					else {
						cout << "\nСписок пуст!\n" << endl;
					}
					if (top_out) {
						cout << "\nЗадерживающиеся поезда:\n" << endl;
						poezd.show(&top_out);
					}
					else {
						cout << "\nВы ещё не перемещали поезда!\n" << endl;
					}

					cout << "Для продолжения нажмите любую клавишу..." << endl;
					_getch();
				}
			} while (n != 4);
			break;
		case 4:
			flag_v = 0;
			if (top_in) {
				do {
					poezd.search(&top_in);
					cout << "\nВы хотите продолжить? (1 - Да, 2 - Нет)" << endl;
					Protect(flag_v, "\nВаш выбор: ", 1, 2);
				} while (flag_v == 1);
			}
			else {
				cout << "\nСписок пуст!" << endl;
			}
			cout << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 5:
			if (top_in) {
				flag_v = 0;
				do {
					poezd.swap(&top_in, &top_out, numberFirst, numberSecond);
					cout << "\nВы хотите продолжить? (1 - Да, 2 - Нет)" << endl;
					Protect(flag_v, "\nВаш выбор: ", 1, 2);
				} while (flag_v == 1);
			}
			else {
				cout << "\nСписок пуст!" << endl;
			}

			cout << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 6:
			if (top_out) {
				flag_v = 0;
				do {
					poezd.swap(&top_out, &top_in, numberSecond, numberFirst);
					cout << "\nВы хотите продолжить? (1 - Да, 2 - Нет)" << endl;
					Protect(flag_v, "\nВаш выбор: ", 1, 2);
				} while (flag_v == 1);
			}
			else {
				cout << "\nВы ещё не перемещали поезда!" << endl;
			}

			cout << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 7:
			cout << "\n Вариант №7\n Классы\n Версия 1.1\n 2019 г.\n Разработчик Мошкин Виталий" << endl;
			cout << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 8:
			cout << "Текст задания:\n" << endl;
			cout << "Описать класс, реализующий стек и работу с ним.\n1.)Класс должен содержать следующие сведения об отправлении поездов дальнего следования:\n*номер поезда;\n*пункт отправления;\n*время прибытия." << endl;
			cout << "2.)В классе должны быть реализованы следующие операции над стеком:\n*добавление данных о поездах в информационную систему;\n*удаление данных о поезде по введенному номеру поезда;\n*вывод информации обо всех поездах;\n*вывод информации о поезде, время которого введено с клавиатуры;" << endl;
			cout << "3.)Программа должна обеспечивать диалог с помощью меню." << endl;
			cout << "4.)В программе должны быть созданы два экземпляра класса:\nприбывающие и задерживающиеся поезда, а также должна быть предусмотрена \nвозможность перевода поезда из прибывающих в задерживающиеся и наоборот по введенному времени прибытия (при этом информация о данном поезде удаляется из одного списка и добавляется в другой).\nПри выводе информации о поездах, пользователь должен выбрать какой список выводить\n(прибывающих или задерживающихся поездов), либо вывести все поезда из обоих списков." << endl;
			cout << endl << "\nДля продолжения нажмите любую клавишу..." << endl;
			_getch();
			break;
		case 9:
			poezd.take_out(&top_in);
			poezd.take_out(&top_out);
			end_flag++;
		}
	} while (end_flag == 0);
	cout << " Нажмите любую клавишу для выхода..." << endl;
	_getch();
	return 0;
}

void TRAIN::set_all_data(TRAIN **top) {
	system("cls");
	TRAIN *new_item = new TRAIN;
	string str;
	int temp;
	cout << "Введите номер поезда: ";
	getline(cin, str);
	while (str.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\nВы ничего не ввели!" << endl;
		cout << "\nВведите номер поезда: ";
		getline(cin, str);
	}
	new_item->nomer = str;

	cout << "\nВведите пункт отправления: ";
	getline(cin, str);
	while (str.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\nВы ничего не ввели!" << endl;
		cout << "\nВведите пункт отправления: ";
		getline(cin, str);
	}
	new_item->des = str;

	cout << "\nВведите время прибытия(часы): ";
	getline(cin, str);
	while (str.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\nВы ничего не ввели!" << endl;
		cout << "\nВведите время прибытия(часы): ";
		getline(cin, str);
	}
	new_item->hour = str;

	cout << "\nВведите время прибытия(минуты): ";
	getline(cin, str);
	while (str.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\nВы ничего не ввели!" << endl;
		cout << "\nВведите время прибытия(минуты): ";
		getline(cin, str);
	}
	new_item->min = str;
	temp = 0;
	new_item->next = *top;
	(*top) = new_item;
}

void TRAIN::del(TRAIN **top, int &numberFirst) {
	TRAIN *current = *top;
	TRAIN *previous = 0;
	string str;

	char proof;
	int numberOfMatches = 0, poezdNumber;
	cout << " Введите номер поезда, который нужно удалить: ";
	getline(cin, str);
	cout << endl;
	while (current) {
		if (current->nomer == str) {
			cout << "Номер поезда:       | " << (current)->nomer << endl;
			cout << "Пункт отправления:  | " << (current)->des << endl;
			cout << "Время прибытия:     | " << (current)->hour << ":" << (current)->min << endl;
			cout << " " << endl;
			numberOfMatches++;

		}
		previous = current;
		current = current->next;
	}
	current = *top;
	previous = nullptr;
	if (numberOfMatches > 0) {
		if (numberOfMatches > 1) {
			cout << endl << " Найденные поезда." << endl << endl
				<< " Введите номер поезда, которого вы хотите удалить: ";
			while (!(cin >> poezdNumber) || (cin.peek() != '\n') || (poezdNumber < 1) || (poezdNumber > numberOfMatches)) {
				Cleaning();
				cout << " Ошибка! Выберите номер поезда " << numberOfMatches << ": ";
			}
			Cleaning();
			for (int i = 0; i < poezdNumber; i++) {
				while (current->nomer != str) {
					previous = current;
					current = current->next;
				}
				if (i != (poezdNumber - 1)) {
					previous = current;
					current = current->next;
				}
			}
		}
		else {
			while (current->nomer != str) {
				previous = current;
				current = current->next;
			}
		}
		cout << endl << " Вы уверены, что хотите удалить эот поезд? (Да/Нет): ";
		cin >> proof;
		Cleaning();
		if (proof == 'д' || proof == 'Д') {
			if (!previous) { //Первый элемент
				*top = (*top)->next;
				free(current);
			}
			else {
				if (!(current->next)) { //Конец
					previous->next = current->next;
					free(current);
				}
				else { //Середина
					previous->next = current->next;
					free(current);
				}
			}
			numberFirst--;
			cout << endl << " Удаление завершено успешно!" << endl << endl;
		}
		else {
			cout << endl << " Удаление отменено!" << endl << endl;
		}
	}
	else {
		cout << endl << " Удаление отменено, так как подходящий поезд не найден!" << endl << endl;
	}
}

void TRAIN::show(TRAIN **top) {
	TRAIN *current = *top;
	int i = 1; //счётчик 
	while (current) {
		cout << "Номер поезда:       | " << (current)->nomer << endl;
		cout << "Пункт отправления:  | " << (current)->des << endl;
		cout << "Время прибытия:     | " << (current)->hour << ":" << (current)->min << endl;
		current = current->next;
		i++;
		cout << "\n";
	}
}

void TRAIN::search(TRAIN **top) {
	system("cls");
	string time_h, time_m;
	bool flag = false;
	cout << " Введите время для поиска (часы): ";
	getline(cin, time_h);
	while (time_h.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\n Вы ничего не ввели!" << endl;
		cout << "\n Введите время для поиска (часы): ";
		getline(cin, time_h);
	}
	cout << " Введите время для поиска (минуты): ";
	getline(cin, time_m);
	while (time_m.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\n Вы ничего не ввели!" << endl;
		cout << "\n Введите время для поиска (минуты): ";
		getline(cin, time_m);
	}
	cout << "\nВаше время: " << time_h << ":" << time_m << endl << endl;
	cout << " Следующие поезда отправятся после вашего времени: " << endl;
	for (int i = 0; i < 85; i++) {
		cout << '_';
		Sleep(10);
	}
	cout << endl;
	TRAIN *current = *top;
	while (current) {
		if ((time_h < current->hour) || (time_h == current->hour && time_m < current->min)) {
			cout << " Номер поезда:       | " << current->nomer << endl;
			cout << " Пункт отправления:  | " << current->des << endl;
			cout << " Время прибытия:     | " << current->hour << ":" << current->min << endl << endl;
			flag = true;
			current = current->next;
		}
		else {
			current = current->next;
		}
	}
	if (flag == false) {
		cout << endl << "\t\t Извините, но в базе данных либо отсутствуют, поезда, которые" << endl
			<< "\t\t отправятся после вашего времени, либо они задерживаются :(" << endl;
	}
}

void TRAIN::swap(TRAIN **topFirst, TRAIN **topSecond, int &numberFirst, int &numberSecond) {
	TRAIN *current = *topFirst;
	TRAIN *previous = nullptr;
	bool tableHeader = false;
	char proof;
	int number, numberOfMatches = 0;
	string nomerNumberSwap, time_h, time_m;
	cout << " Введите время прибытия поезда, который хотите переместить (часы): ";
	getline(cin, time_h);
	while (time_h.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\n Вы ничего не ввели!" << endl;
		cout << "\n Введите время прибытия поезда, который хотите переместить (часы): ";
		getline(cin, time_h);
	}
	cout << " Введите время прибытия поезда, который хотите переместить (минуты): ";
	getline(cin, time_m);
	while (time_m.length() == 0) {
		cin.clear();
		cin.sync();
		cout << "\n Вы ничего не ввели!" << endl;
		cout << "\n Введите время прибытия поезда, который хотите переместить (минуты): ";
		getline(cin, time_m);
	}
	cout << endl;
	while (current) {
		if (current->hour == time_h && current->min == time_m) {
			if (!tableHeader) {
				tableHeader = true;
			}
			numberOfMatches++;
			cout << "Номер поезда:       | " << (current)->nomer << endl;
			cout << "Пункт отправления:  | " << (current)->des << endl;
			cout << "Время прибытия:     | " << (current)->hour << ":" << (current)->min << endl;
			cout << " " << endl;
		}
		previous = current;
		current = current->next;
	}
	current = *topFirst;
	previous = nullptr;
	if (numberOfMatches > 0) {
		if (numberOfMatches > 1) {
			cout << endl << " Найдено несколько поездов, время прибытия которых совпадает с введённым вами временем." << endl << endl
				<< "Введите номер поезда, который вы хотите переместить: ";
			getline(cin, nomerNumberSwap);
			while (current->nomer != nomerNumberSwap) {
				previous = current;
				current = current->next;
			}
		}
		cout << endl << " Вы уверены, что хотите переместить этот поезд? (Да/Нет): ";
		cin >> proof;
		Cleaning();
		if (proof == 'д' || proof == 'Д') {
			TRAIN *new_item = new TRAIN;

			new_item->nomer = (current)->nomer;
			new_item->des = (current)->des;
			new_item->hour = (current)->hour;
			new_item->min = (current)->min;
			new_item->number = (current)->number;

			new_item->next = *topSecond;
			*topSecond = new_item;
			if (current == *topFirst) {
				*topFirst = current->next;
				delete(current);
			}
			else {
				previous->next = current->next;
				delete(current);
			}
			numberFirst--;
			numberSecond++;
			cout << endl << " Перемещение завершено успешно!" << endl << endl;
		}
		else {
			cout << endl << " Перемещение отменено пользователем!" << endl << endl;
		}
	}
	else {
		cout << endl << " Перемещение отменено, так как не найден номер удовлетворяющий запросу!" << endl << endl;
	}
}

void TRAIN::take_out(TRAIN  **top) {
	TRAIN *old_header = *top;
	while (*top) {
		(*top) = (*top)->next;
		delete(old_header);
		old_header = *top;
	}
}

void Protect(int &n, string temp, int m, int k) {
	int flag = 0;
	char str[80];
	do { //проверка ввода
		flag = 0;
		cout << temp;
		cin.getline(str, 79);
		if (!atoi(str)) {
			cout << "Вы ввели недопустимое значение! Повторите ввод.\n\n";
			flag++;
		}
		else {
			n = atoi(str);
			if (n < m || n > k) {
				cout << "Вы ввели недопустимое значение! Повторите ввод.\n\n";
				flag++;
			}
		}
	} while (flag != 0);
	cout << "\n";
}