#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>
#include <conio.h>

struct DATA
{
	int number=0;
	char surname[12], name[10], patronymic[15];
	int BirthDate, BirthMonth, BirthYear;
	char addresSTREET[16];
	int addresHOME;
	int mobileNUMBER;
};

int ENTER_CHOICE(void);
void NEW_DATA(FILE*);
void VIEW_DATA(FILE*);
void ENTER_DATA(struct DATA*);
void UPDATE_RECORD(FILE*);
void ADD_RECORD(FILE*);
void DELETE_RECORD(FILE*);
void SEARCH_RECORD(FILE*);
void SORT_DATA(FILE*);
int CHECK_INTEGER(int,int);

int main()
{
	//Русификация консоли ввода/вывода
	SetConsoleCP(1251); //установка кодовой страницы win-cp 1251 в поток ввода
	SetConsoleOutputCP(1251); //установка кодовой страницы win-cp 1251 в поток вывода

	FILE* cfPtr;
	char fname[20]; 
	int choice;
	int access_mode;

	printf("Продолжить работу в старом файле?\n"
		"(1)-Да (0)-Нет, я хочу создать новый\n->");
	scanf("%d", &access_mode);

	printf("Введите название файла (name.txt)\n-> ");
	//while (getchar() != '\n');
	//fgets(fname, sizeof(fname), stdin);
	scanf("%[^\n]", fname);

	do {
		system("cls");

		if (access_mode == 1) {
			if ((cfPtr = fopen(fname, "r+")) == NULL) {
				printf("File could not be opened.\n");
				return 0;
			}
		}
		else {
			if ((cfPtr = fopen(fname, "w+")) == NULL) {
				printf("File could not be opened.\n");
				return 0;
			}
			access_mode = 1;
		}

		choice = ENTER_CHOICE();

		switch (choice)
		{
		case 0: return 0;
		case 1:
			NEW_DATA(cfPtr);
			break;
		case 2:
			VIEW_DATA(cfPtr);
			break;
		case 3:
			UPDATE_RECORD(cfPtr);
			break;
		case 4:
			ADD_RECORD(cfPtr);
			break;
		case 5:
			DELETE_RECORD(cfPtr);
			break;
		case 6:
			SEARCH_RECORD(cfPtr);
			break;
		case 7:
			SORT_DATA(cfPtr);
			break;
		}
		fclose(cfPtr);
		if (choice != 0)
			system("\npause");
	} while (choice!=0);
}

int ENTER_CHOICE(void)
{
	int choice;
	char buf[100]; // строка для считывания введённых данных

	printf("Выберите, что вам нужно сделать\n"
		"0 -> Выход из программы\n"
		"1 -> Создание новой базы данных\n"
		"2 -> Просмотр существующей базы данных\n"
		"3 -> Редактирование базы данных\n"
		"4 -> Дополнение базы данных новыми записями\n"
		"5 -> Удаление записей из базы данных\n"
		"6 -> Поиск в базе данных\n"
		"7 -> Сортировка пользователей по фамилии\n-> ");
	/*scanf("%s", buf); */
	fgets(buf, sizeof(buf), stdin);// считываем строку
	 // пока ввод некорректен, сообщаем об этом и просим повторить его
	while (sscanf(buf, "%d", &choice) != 1 || choice < 0 || choice > 7)
	{
		printf("Неверно введено значение. Попробуйте снова ->"); // выводим сообщение об ошибке
		/*scanf("%s", buf);*/ 
		fgets(buf, sizeof(buf), stdin);// считываем строку повторно
	}
	return choice;
}

void NEW_DATA(FILE* fPtr)
{
	int ans = 1;
	struct DATA notebook;

	do{
		notebook.number++;
		ENTER_DATA(&notebook);

		fseek(fPtr, notebook.number * sizeof(struct DATA), SEEK_SET);
		fwrite(&notebook, sizeof(struct DATA), 1, fPtr);
		printf("Введите (1) - чтобы добавить еще (0) - закончить\n-> ");
		scanf("%d", &ans);
	} while (ans != 0);
}

void VIEW_DATA(FILE* readPtr)
{
	DATA buf;
	printf("%-2s| %-12s | %-10s | %-15s | %-13s | %-16s | %-11s |\n",
		"№","Фамилия","Имя","Отчество","Дата Рождения","Адрес","моб.телефон");
	fseek(readPtr, 0 * sizeof(struct DATA), SEEK_SET);
	while (fread(&buf, sizeof(buf), 1, readPtr)) {

		if(buf.number!=0)
		printf("%-2d| %-12s | %-10s | %-15s | %02d.%02d.%04d    | %-12s,%-3d | %-11d |\n",
			buf.number, buf.surname, buf.name, buf.patronymic,
			buf.BirthDate, buf.BirthMonth, buf.BirthYear,
			buf.addresSTREET, buf.addresHOME, buf.mobileNUMBER);
	}
}

int CHECK_INTEGER(int a, int b)
{
	char buf[256];
	int user_number;
	
	fgets(buf, sizeof(buf), stdin);
	while (sscanf(buf, "%d", &user_number) != 1 || user_number < a || user_number > b)
	{
		printf("Ошибка ввода. Попробуйте еще раз\n-> ");
		fgets(buf, sizeof(buf), stdin);
	}
	return user_number;
}

void ENTER_DATA(struct DATA* notebook)
{
	while (getchar() != '\n');
	printf("Введите фамилию -> ");
	fgets(notebook->surname, sizeof(notebook->surname), stdin);
	notebook->surname[strcspn(notebook->surname, "\n")] = 0;

	printf("Введите имя -> ");
	fgets(notebook->name, sizeof(notebook->name), stdin);
	notebook->name[strcspn(notebook->name, "\n")] = 0;

	printf("Введите отчество -> ");
	fgets(notebook->patronymic, sizeof(notebook->patronymic), stdin);
	notebook->patronymic[strcspn(notebook->patronymic, "\n")] = 0;
	
	printf("Введите дату рождения:\nДень -> ");
	notebook->BirthDate=CHECK_INTEGER(1, 31);
	printf("Месяц -> ");
	notebook->BirthMonth = CHECK_INTEGER(1, 12);
	printf("Год -> ");
	notebook->BirthYear = CHECK_INTEGER(1950, 2021);

	printf("Введите адрес:\nУлица -> ");
	fgets(notebook->addresSTREET, sizeof(notebook->addresSTREET), stdin);
	notebook->addresSTREET[strcspn(notebook->addresSTREET, "\n")] = 0;

	printf("Номер дома -> ");
	notebook->addresHOME = CHECK_INTEGER(1, 999);

	printf("Введите номер мобильного телефона -> ");
	notebook->mobileNUMBER = CHECK_INTEGER(1, 999999999);
}

void UPDATE_RECORD(FILE* fPtr)
{
	struct DATA notebook;
	int numper;
	VIEW_DATA(fPtr);
	printf("Введите номер человека, данные которого нужно изменить\n-> ");
	/*scanf_s("%d", &numper);*/
	while (getchar() != '\n');
	numper = CHECK_INTEGER(1, 999);

	notebook.number = numper;
	ENTER_DATA(&notebook);
	
	fseek(fPtr, (notebook.number) * sizeof(struct DATA), SEEK_SET);
	fwrite(&notebook, sizeof(struct DATA), 1, fPtr);
}

void ADD_RECORD(FILE* fPtr)
{
	struct DATA notebook;
	int ans = 1;
	int numper = 0;
	VIEW_DATA(fPtr);
	fseek(fPtr, 0 * sizeof(struct DATA), SEEK_SET);
	while (fread(&notebook, sizeof(notebook), 1, fPtr) == 1)
	{
		numper++;
	}
	notebook.number = numper;
	ENTER_DATA(&notebook);
	fseek(fPtr, notebook.number * sizeof(struct DATA), SEEK_SET);
	fwrite(&notebook, sizeof(struct DATA), 1, fPtr);
}

void DELETE_RECORD(FILE* fPtr)
{
	struct DATA notebook, blankClient = {0,"","","",0,0,0,"",0,0};
	int numper = 0;
	VIEW_DATA(fPtr);
	printf("Введите номер человека, данные которого нужно удалить из БД\n-> ");
	scanf("%d", &numper);
	notebook.number = numper;
	fseek(fPtr, notebook.number * sizeof(struct DATA), SEEK_SET);
	fread(&notebook, sizeof(struct DATA), 1, fPtr);
	if (notebook.number == 0)
		printf("Аккаунта с таким номером не существует\n");
	else {
		fseek(fPtr, notebook.number * sizeof(struct DATA), SEEK_SET);
		fwrite(&blankClient, sizeof(struct DATA), 1, fPtr);
	}
}

void SEARCH_RECORD(FILE* readPtr)
{
	struct DATA buf;
	char buf2[100];
	int choice;
	unsigned int search_mobile=1;
	bool flag = false;
	char search_surname[12] = { "0" }, search_name[10] = {"0"};

	while (getchar() != '\n');
	printf("Осуществить поиск по:\n(1) -> Имени и Фамилии\n(2) -> Номеру телефона\n-> ");
	fgets(buf2, sizeof(buf2), stdin);
	/*scanf("%s", buf2);*/
	while (sscanf(buf2, "%d", &choice) != 1 || choice < 0 || choice > 2)
	{
		printf("Неверно введено значение. Попробуйте снова ->"); // выводим сообщение об ошибке
		fgets(buf2, sizeof(buf2), stdin);
		/*scanf("%s", buf2);*/ // считываем строку повторно
	}
	switch (choice)
	{
	case 1:
		printf("Имя-> ");
		while (getchar() != '\n');
		fgets(search_name, sizeof(search_name), stdin);
		search_name[strcspn(search_name, "\n")] = 0;
		printf("Фамилия-> ");
		fgets(search_surname, sizeof(search_surname), stdin);
		search_surname[strcspn(search_surname, "\n")] = 0;
		break;
	case 2:
		printf("Номер телефона-> ");
		search_mobile = CHECK_INTEGER(1, 99999999);
		break;
	}
	fseek(readPtr, 0 * sizeof(struct DATA), SEEK_SET);
	while (fread(&buf, sizeof(buf), 1, readPtr))
	{
		if ((strcmp(search_name, buf.name) == 0 && strcmp(search_surname, buf.surname) == 0) || search_mobile == buf.mobileNUMBER)
		{
			printf("%-2s| %-12s | %-10s | %-15s | %-13s | %-16s | %-11s |\n",
				"№", "Фамилия", "Имя", "Отчество", "Дата Рождения", "Адрес", "моб.телефон");
			printf("%-2d| %-12s | %-10s | %-15s | %02d.%02d.%04d    | %-12s,%-3d | %-11d |\n",
				buf.number, buf.surname, buf.name, buf.patronymic,
				buf.BirthDate, buf.BirthMonth, buf.BirthYear,
				buf.addresSTREET, buf.addresHOME, buf.mobileNUMBER);
			flag = true;
		}
	}
	if (!flag)
		printf("Пользователь не найден...\n");
}

void SORT_DATA(FILE* fPtr)
{
	struct DATA blankClient, notebook= { 0,"","","",0,0,0,"",0,0 };
	int count_rec = 0;

	while (fread(&notebook, sizeof(notebook), 1, fPtr) == 1)
	{
		count_rec++;
	}
	
	for (int a = 0; a < count_rec; a++)
	{
		for (int b = 0; b < count_rec -1; b++)
		{
			fseek(fPtr, (b) * sizeof(struct DATA), SEEK_SET);
			fread(&notebook, sizeof(struct DATA), 1, fPtr);
			fseek(fPtr, (b+1) * sizeof(struct DATA), SEEK_SET);
			fread(&blankClient, sizeof(struct DATA), 1, fPtr);
			if (blankClient.number != 0)
			{
				if (strcmp(notebook.surname, blankClient.surname) > 0)
				{
					blankClient.number--;
					notebook.number++;
					fseek(fPtr, (b) * sizeof(struct DATA), SEEK_SET);
					fwrite(&blankClient, sizeof(struct DATA), 1, fPtr);
					fseek(fPtr, (b+1) * sizeof(struct DATA), SEEK_SET);
					fwrite(&notebook, sizeof(struct DATA), 1, fPtr);
				}
			}
		}
	}
	printf("Сортировка прошла успешно!\n");
}