/*Предметна область - бібліотека.
Розв'язувані задачі: видача довідок про наявність книг, журналів, газет. Реалізувати наступні сервіси:
Заповнення бази даних
Перегляд даних про всі джерела
Доповнення бази даних записом джерела
Видалення джерела із бази даних
Упорядкування по полях: тип інформаційного джерела (книга, журнал, газета) і назва
Пошук: наявність заданої книги (відомі автор і назва), наявність заданого журналу
Вибірка: книги автора ХХ; книги певної категорії (фантастика, детектив тощо), журнали за певний рік (відомі рік і назва журналу)
Обчислення: кількість книг деякої категорії
Корекція: видалення зведень про газети за певний рік
Табличний звіт: список боржників книг певного автора
Для обробки даних скористатися динамічним масивом покажчиків на структури відповідного типу.
*/

#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <fstream>
#include<windows.h>

using namespace std;

struct Date
{
	int day;
	int month;
	int year;
};
struct Item
{
	int serial_number;
	string source_type;
	string name;
	string author;
	int year;
	string genre;
	string publisher;
	string is_given;
};

#pragma region Show_library
//Вивід бібліотеки на екран
void print_source(Item *source)
{
	cout << setw(17) << "Serial number" << " :   " << source->serial_number << endl
		<< setw(17) << left << "Type" << " :   " << source->source_type << endl
		<< setw(17) << left << "Name" << " :   " << source->name << endl
		<< setw(17) << left << "Author" << " :   " << source->author << endl
		<< setw(17) << left << "Date" << " :   " << source->year << endl
		<< setw(17) << left << "Genre" << " :   " << source->genre << endl
		<< setw(17) << left << "Publiher" << " :   " << source->publisher << endl
		<< setw(17) << left << "Given to" << " :   " << source->is_given << endl
		<< "--------------------------------------------------------------------------------" << endl;
}

void print_sources(Item *sources, const int quantity)
{
	//cout << setw(20) << "Book name" << setw(20) << "Author" << setw(15) << "Publisher" << setw(15) << "Genre" << endl;
	cout << "List of sources" << endl << endl;
	for (Item *ptr = sources; ptr < sources + quantity; ++ptr)
	{
		print_source(ptr);
	}
}
#pragma endregion

#pragma region Save_file
void save_file(Item *sources, const int file_size)
{
	char confirm;
	system("cls");
	do
	{
		cout << "Are you sure you want to save changes? y/n : ";
		cin >> confirm;
	} while (confirm != 'y' && confirm != 'n');
	if (confirm == 'y')
	{
		string outFileName = "Library.txt";
		ofstream outFile;
		outFile.open(outFileName, ios_base::out);
		if (!outFile.is_open())
		{
			cout << "Can't open " << outFileName << " for writing. Exiting..." << endl;
			system("pause");
			exit(1);
		}
		int counter = 0;
		outFile << file_size;
		for (Item *ptr = sources; ptr < sources + file_size; ++ptr)
		{
			outFile << endl
				<< ptr->serial_number << ";"
				<< ptr->source_type << ";"
				<< ptr->name << ";"
				<< ptr->author << ";"
				<< ptr->year << ";"
				<< ptr->genre << ";"
				<< ptr->publisher << ";"
				<< ptr->is_given << ";";
		}
		outFile.close();
		cout << endl << "File saved" << endl << endl;
	}
	else
	{
		cout << endl << "Changes declined" << endl << endl;
	}
}
#pragma endregion

#pragma region Add_source
//заповнення бібліотеки користувачем
void get_sources_from_user(Item *source, int index)
{
	source->serial_number = index;
	int type = 0;
	do
	{
		cout << "Choose source type :" << endl
			<< "1. Book" << endl
			<< "2. Magazine" << endl
			<< "3. News paper" << endl << endl
			<< "Make a choice : ";
		cin >> type;
	} while (type < 1 || type > 3);
	switch (type)
	{
	case 1: source->source_type = "book";
		break;
	case 2: source->source_type = "magazine";
		break;
	case 3: source->source_type = "news paper";
		break;
	default:
		cout << "Wrong choice!" << endl;
		break;
	}
	cin.ignore();
	//cout << "Enter source type (book, magazine, news paper) : ";
	//getline(cin, source->source_type);
	cout << "Type the name of a source : ";
	getline(cin, source->name);
	cout << "Type the author of a source : ";
	getline(cin, source->author);
	cin >> source->year;
	//bool correct = false;
	//do
	//{
	//	cout << "Type the date of a source (01 12 2016) : ";
	//	cin >> sources[i].date.day >> sources[i].date.month >> sources[i].date.year;
	//	if (sources[i].date.day < 1 || sources[i].date.day > 31)
	//	{
	//		sources[i].date.day = NULL;
	//		correct = true;
	//	}
	//	else if (sources[i].date.month < 1 || sources[i].date.month > 12)
	//	{
	//		sources[i].date.month = NULL;
	//		correct = true;
	//	}
	//	else if (sources[i].date.year > 2016)
	//	{
	//		cout << "You've entered invalid year" << endl;
	//		correct = false;
	//	}
	//	else
	//	{
	//		correct = true;
	//	}
	//} while (correct != true);
	cout << "Type the publisher of a source : ";
	getline(cin, source->publisher);
	cout << "Type the genre of a source : ";
	getline(cin, source->genre);
	source->is_given = "no information";
}

void move_source(Item *src, const int count, Item *dst)
{
	for (Item *src_ptr = src, *dst_ptr = dst; src_ptr < src + count; ++dst_ptr, ++src_ptr)
	{
		//*dst_ptr = *src_ptr;
		//src_ptr = nullptr;
		dst_ptr->serial_number = src_ptr->serial_number;
		dst_ptr->source_type = src_ptr->source_type;
		dst_ptr->name = src_ptr->name;
		dst_ptr->author = src_ptr->author;
		dst_ptr->year = src_ptr->year;
		dst_ptr->genre = src_ptr->genre;
		dst_ptr->publisher = src_ptr->publisher;
		dst_ptr->is_given = src_ptr->is_given;
	}
}

Item* AddStruct(Item* source, int *file_size)
{
	int newSize = *file_size + 1;
	if (*file_size == 0)
	{
		source = new Item[newSize]; // виділення пам'яті для першої структури
	}
	else
	{
		Item *new_source = new Item[newSize];
		move_source(source, *file_size, new_source);
		print_sources(new_source, newSize);
		get_sources_from_user((new_source + newSize), newSize);

		delete[] source;
		source = new_source;
		delete[] new_source;
	}
	*file_size = newSize;
	return source;
}

void add_source(Item *sources, int file_size)
{
	char YesOrNot;
	do
	{
		sources = AddStruct(sources, &file_size);

		file_size++;
		do
		{
			cout << "Add onather source? (y/n): ";
			cin >> YesOrNot;
			cin.get();
		} while (YesOrNot != 'y' || YesOrNot != 'n');
		if (YesOrNot = 'n')
		{
			save_file(sources, file_size);
		}
	} while (YesOrNot != 'n');

	print_source(sources + file_size);

}
#pragma endregion

#pragma region Edit_source
//Редагування
void edit_book(Item *sources, const int quantity)
{
	system("cls");
	print_sources(sources, quantity);
	int choice;
	enum parameters
	{
		Exit,
		source_type,
		name,
		author,
		year,
		genre,
		publisher
	};

	do
	{
		cout << "Enter the number of book to edit : ";
		cin >> choice;
	} while (choice < 1 || choice > quantity);
	choice -= 1;

	int choice_parameter;
	do
	{
		cout << "You are about to edit " << sources[choice].name << endl << endl
			<< source_type << ". Source type" << endl
			<< name << ". Name" << endl
			<< author << ". Author" << endl
			<< year << ". Year of publication" << endl
			<< genre << ". Genre" << endl
			<< publisher << ". Publisher" << endl
			<< Exit << ". Exit" << endl << endl;
		do
		{
			cout << "Enter the parameter to edit : ";
			cin >> choice_parameter;
		} while (choice_parameter < 0 || choice_parameter > 6);

		cin.ignore();
		switch (choice_parameter)
		{
		case parameters::source_type:
		{
			int type = 0;
			do
			{
				cout << "Choose a source type :" << endl
					<< "1. Book" << endl
					<< "2. Magazine" << endl
					<< "3. News paper" << endl << endl
					<< "Make a choice : ";
				cin >> type;
			} while (type < 1 || type > 3);
			switch (type)
			{
			case 1: (sources + choice)->source_type = "book";
				break;
			case 2: (sources + choice)->source_type = "magazine";
				break;
			case 3: (sources + choice)->source_type = "news paper";
				break;
			default:
				cout << "Wrong choice!" << endl;
				break;
			}
		}
		break;
		case parameters::name:
		{
			cout << "Enter new name of the book : ";
			getline(cin, sources[choice].name);
		}
		break;
		case parameters::author:
			cout << "Enter new author of the book : ";
			getline(cin, sources[choice].author);
			break;
		case parameters::year:
			cout << "Enter new year of publication : ";
			cin >> sources[choice].year;
			break;
		case parameters::genre:
			cout << "Enter new genre of the book : ";
			getline(cin, sources[choice].genre);
			break;
		case parameters::publisher:
			cout << "Enter new publisher of the book : ";
			getline(cin, sources[choice].publisher);
			break;

		case parameters::Exit:
			cout << "Good bye!" << endl;
		default:
			break;
		}
		cout << endl << "Edited source :" << endl;
		print_source(sources + choice);
	} while (choice_parameter != 0);
	save_file(sources, quantity);
}
#pragma endregion

#pragma region Sorting
//Сортировка массива по названию книг
void sort_by_name(Item *sources, const int quantity)
{
	for (int i = 0; i < quantity; ++i)
	{
		for (int j = 0; j < quantity - 1 - i; ++j)
		{
			if (sources[j].name > sources[j + 1].name)
			{
				swap(sources[j], sources[j + 1]);
			}
		}
	}
}

//Сортировка массива по автору
void sort_by_author(Item *sources, const int quantity)
{
	for (int i = 0; i < quantity; ++i)
	{
		for (int j = 0; j < quantity - 1 - i; ++j)
		{
			if (sources[j].author > sources[j + 1].author)
			{
				swap(sources[j], sources[j + 1]);
			}
		}
	}
}

//Сортировка массива по издательству
void sort_by_publisher(Item *sources, const int quantity)
{
	for (int i = 0; i < quantity; ++i)
	{
		for (int j = 0; j < quantity - 1 - i; ++j)
		{
			if (sources[j].publisher > sources[j + 1].publisher)
			{
				swap(sources[j], sources[j + 1]);
			}
		}
	}
}

//Сортировка массива по типу
void sort_by_source_type(Item *sources, const int quantity)
{
	for (int i = 0; i < quantity; ++i)
	{
		for (int j = 0; j < quantity - 1 - i; ++j)
		{
			if (sources[j].source_type > sources[j + 1].source_type)
			{
				swap(sources[j], sources[j + 1]);
			}
		}
	}
}

//Сортировка массива по году
void sort_by_year(Item *sources, const int quantity)
{
	for (int i = 0; i < quantity; ++i)
	{
		for (int j = 0; j < quantity - 1 - i; ++j)
		{
			if (sources[j].year > sources[j + 1].year)
			{
				swap(sources[j], sources[j + 1]);
			}
		}
	}
}

//Сортировка массива по жанру
void sort_by_genre(Item *sources, const int quantity)
{
	for (int i = 0; i < quantity; ++i)
	{
		for (int j = 0; j < quantity - 1 - i; ++j)
		{
			if (sources[j].genre > sources[j + 1].genre)
			{
				swap(sources[j], sources[j + 1]);
			}
		}
	}
}

//меню сортування книг
void sort_sources(Item *sources, const int quantity)
{
	enum Sorting
	{
		exit, source_type, name, author, year, genre, publisher
	};
	int choice;
	do
	{
		do
		{
			cout << "Sort sources by :" << endl
				<< source_type << ". Type of source" << endl
				<< name << ". Name" << endl
				<< author << ". Author" << endl
				<< year << ". Year" << endl
				<< genre << ". Genre" << endl
				<< publisher << ". Publisher" << endl
				<< exit << ". Exit" << endl << endl
				<< "Enter the parameter : ";
			cin >> choice;
		} while (choice < exit || choice > publisher);
		switch (choice)
		{
		case source_type: sort_by_source_type(sources, quantity);
			break;
		case name: sort_by_name(sources, quantity);
			break;
		case author: sort_by_author(sources, quantity);
			break;
		case year: sort_by_year(sources, quantity);
			break;
		case genre: sort_by_genre(sources, quantity);
			break;
		case publisher: sort_by_publisher(sources, quantity);
			break;
		case 0: cout << "Thanks!" << endl;
			break;
		default:
			break;
		}
		system("cls");
		cout << "Sorted ";
		print_sources(sources, quantity);
	} while (choice != 0);
}
#pragma endregion

#pragma region Find_source
//Поиск книг по автору
void search_by_author(Item *sources, const int quantity) // Можна шукати як по прізвищу так і по імені
{
	int counter = 0;
	cin.ignore();
	string search_word;
	cout << "Enter author's name : ";
	getline(cin, search_word);
	bool is_in = false;
	for (int i = 0; i < quantity; ++i)
	{
		int k = -1;
		k = sources[i].author.find(search_word);
		if (k >= 0)
		{
			is_in = true;
			cout << "--------------------------------------------------------------------------------" << endl;
			print_source(sources + i);
			++counter;
		}
	}
	if (is_in == false)
	{
		cout << "No match found." << endl;
	}
	else
	{
		cout << endl << counter << "sources found" << endl << endl << endl;
	}
}

//Поиск книги по названию
void search_by_name(Item *sources, const int quantity) // Можна шукати по будь-якому слові в назві
{
	int counter = 0;
	cin.ignore();
	string search_word;
	cout << "Enter the name of book: ";
	getline(cin, search_word);
	bool is_in = false;
	for (int i = 0; i < quantity; ++i)
	{
		int k = -1;
		k = sources[i].name.find(search_word);
		if (k >= 0)
		{
			is_in = true;
			cout << "--------------------------------------------------------------------------------" << endl;
			print_source(sources + i);
			++counter;
		}
	}
	if (is_in == false)
	{
		cout << "--------------------------------------------------------------------------------" << endl
			<< "No match found." << endl << endl
			<< "--------------------------------------------------------------------------------" << endl;
	}
	else
	{
		cout << endl << counter << "sources found" << endl << endl << endl;
	}
}

void search_by_publisher(Item *sources, const int quantity) // Можна шукати по будь-якому слові в назві
{
	int counter = 0;
	cin.ignore();
	string search_word;
	cout << "Enter the publisher of sources : ";
	getline(cin, search_word);
	bool is_in = false;
	for (int i = 0; i < quantity; ++i)
	{
		int k = -1;
		k = sources[i].publisher.find(search_word);
		if (k >= 0)
		{
			is_in = true;
			cout << "--------------------------------------------------------------------------------" << endl;
			print_source(sources + i);
			++counter;
		}
	}
	if (is_in == false)
	{
		cout << "--------------------------------------------------------------------------------" << endl
			<< "No match found." << endl << endl
			<< "--------------------------------------------------------------------------------" << endl;
	}
	else
	{
		cout << endl << counter << "sources found" << endl << endl << endl;
	}
}

void search_book(Item *sources, const int quantity)
{
	int choice;
	do
	{
		do
		{
			cout << "Search book by :" << endl
				<< "1. Name" << endl
				<< "2. Author" << endl
				<< "3. Publisher" << endl
				<< "0. Exit" << endl << endl
				<< "Enter the parameter : ";
			cin >> choice;
		} while (choice < 0 || choice > 3);

		switch (choice)
		{
		case 1: search_by_name(sources, quantity);
			break;
		case 2: search_by_author(sources, quantity);
			break;
		case 3: search_by_publisher(sources, quantity);
			break;
		case 0: cout << "Thanks!" << endl;
			break;
		default:
			break;
		}
	} while (choice != 0);
}

void search_magazine(Item *sources, const int quantity)
{
	string name;
	cout << "Enter the name of magazine or news paper : ";
	cin.ignore();
	getline(cin, name);
	int year;
	cout << "Enter the year of magazine or news paper : ";
	cin >> year;
	Item *search_source = new Item;
	bool is_in = false;
	for (Item *ptr = sources; ptr < sources + quantity; ++ptr)
	{
		int k = -1;
		k = ptr->name.find(name);
		if (k >= 0)
		{
			if (ptr->year == year)
			{
				is_in = true;
				cout << "--------------------------------------------------------------------------------" << endl;
				print_source(ptr);
				break;
			}
		}
	}
	if (is_in == false)
	{
		cout << "--------------------------------------------------------------------------------" << endl
		<< "No match found." << endl << endl
		<< "--------------------------------------------------------------------------------" << endl;
	}
}

void search_source(Item *sources, const int quantity)
{
	enum Variants
	{
		exit, book, magazine
	};
	int choice = 0;
	do
	{
		do
		{
			cout << "Choose what do you want to find :" << endl
				<< book << ". Book" << endl
				<< magazine << ". Magazine or News paper" << endl
				<< exit << ". Cancel" << endl
				<< "Your choice : ";
			cin >> choice;
		} while (choice < exit || choice > magazine);
		switch (choice)
		{
		case book: search_book(sources, quantity);
			break;
		case magazine: search_magazine(sources, quantity);
			break;
		case exit: cout << "CANCELED" << endl;
			break;;
		default:
			break;
		}
	} while (choice != exit);
}
#pragma endregion

/*void create_array(ifstream *read_file, int lib_size, Item *sources)
{
	string item_param;
	int i = 0;
	while (!read_file.eof())
	{
	cout << i << endl;
	getline(read_file, item_param, ';');
	sources[i].source_type = item_param;

	getline(read_file, item_param, ';');
	sources[i].name = item_param;
	cout << sources[i].name << endl;

	getline(read_file, item_param, ';');
	sources[i].author = item_param;

	getline(read_file, item_param, ';');
	sources[i].year = atoi(item_param.c_str()); //i = atoi(string_name.c_str());

	getline(read_file, item_param, ';');
	sources[i].genre = item_param;

	getline(read_file, item_param, ';');
	sources[i].publisher = item_param;

	getline(read_file, item_param, ';');
	sources[i].is_given = item_param;

	i++;
	read_file.seekg(2, ios::cur);
	}
}*/

int get_sources_quantity(ifstream read_file)
{
	int quant = 0;
	string number;
	read_file >> number;
	quant = atoi(number.c_str());
	return quant;
}

int get_position(int lib_size)
{
	int counter = 0;
	if (lib_size <= 0)
	{
		counter = 0;
	}
	else if (lib_size < 10)
	{
		counter = 1;
	}
	else
	{
		do
		{
			lib_size /= 10;
			++counter;
		} while (lib_size >= 1);
	}
	return counter;
}

void main()
{

	ifstream read_file;
	string read_file_name = "Library.txt";

	read_file.open(read_file_name, ios_base::in);
	if (!read_file.is_open())
	{
		cerr << "Cannot open " << read_file_name << " for reading. Exiting...." << endl;
		system("pause");
		exit(1);
	}

	int lib_size = 0;
	string number;
	read_file >> number;
	lib_size = atoi(number.c_str());
	cout << "Library consists of " << lib_size << " sources" << endl << endl;
	Item *sources = new Item[lib_size];
	string item_param;
	int i = 0;
	int position = get_position(lib_size);
	read_file.seekg(position + 2);

	for (; i < lib_size; ++i)
	{
		getline(read_file, item_param, ';');
		sources[i].serial_number = atoi(item_param.c_str());

		getline(read_file, item_param, ';');
		sources[i].source_type = item_param;

		getline(read_file, item_param, ';');
		sources[i].name = item_param;

		getline(read_file, item_param, ';');
		sources[i].author = item_param;

		getline(read_file, item_param, ';');
		sources[i].year = atoi(item_param.c_str()); //i = atoi(string_name.c_str());

		getline(read_file, item_param, ';');
		sources[i].genre = item_param;

		getline(read_file, item_param, ';');
		sources[i].publisher = item_param;

		getline(read_file, item_param, ';');
		sources[i].is_given = item_param;

		read_file.seekg(2, ios::cur);
	}

	int choice;
	enum menu
	{
		Exit,
		Add,
		Print,
		Edit,
		Sort,
		Search
	};

	do
	{
		do
		{
			cout << Add << ". Add source" << endl
				<< Print << ". Print sources" << endl
				<< Edit << ". Edit sources" << endl
				<< Sort << ". Sort sources" << endl
				<< Search << ". Search source" << endl
				<< Exit << ". Exit" << endl << endl
				<< "Enter the action : ";
			cin >> choice;
		} while (choice < 0 || choice > 5);
		switch (choice)
		{
		case menu::Add: add_source(sources, lib_size);
			break;
		case menu::Print:
			print_sources(sources, lib_size);
			break;
		case menu::Edit:
			edit_book(sources, lib_size);
			break;
		case menu::Sort:
			sort_sources(sources, lib_size);
			break;
		case menu::Search:
			search_source(sources, lib_size);
			break;
		case menu::Exit:
			cout << "Good bye!" << endl;
		default:
			break;
		}
	} while (choice != 0);

	delete[] sources;
	system("pause");
}