#include <iostream>
#include <cstdlib>
#include <ctime>

#include "sort_algorithms.hpp"
#include "row.hpp"

row<int>* make_row(int* src, int size)
{
	return new row<int>(src,size);
}

int main()
{
	srand(static_cast<unsigned>(time(nullptr)));
	int* b = new int[10];
	for (int i=0; i<10; i++)
		b[i] = rand() % 100;

	row<int>* a = new row<int>(b, 10);

	std::cout << "=== row<T> class demo ===\n\n";
	std::cout << "Original  : " << *a << "\n\n";

	// copy constructor test
	row<int> copy_a(*a);
	std::cout << "Copy-constructor: " << copy_a << "\n";

	// assignment operator test
	int tmp_arr[3] = {1,2,3};
	row<int> assigned(tmp_arr, 3);
	std::cout << "'assigned' before assignment: " << assigned << "\n";
	assigned = *a;
	std::cout << "assigned = *Orignal \n";
	std::cout << "Assign op : " << assigned << "\n";

	// operator[] and at()
	std::cout << "a[0]      : " << (*a)[0] << "\n";
	std::cout << "a.at(0)   : " << a->at(0) << "\n";
	try {
		a->at(999);
	} catch (const std::out_of_range& e) {
		std::cout << "at(999)   : caught expected exception – " << e.what() << "\n";
	}

	std::cout << "\n=== Sorting algorithms (each on a fresh copy) ===\n\n";

	// bubble sort
	{
		row<int>* a = make_row(b,10);
		bubble_sort(*a);
		std::cout << "Bubble    : " << *a << "\n";
		delete a;
	}

	// selection sort
	{
		row<int>* a = make_row(b,10);
		selection_sort(*a);
		std::cout << "Selection : " << *a << "\n";
		delete a;
	}

	// insertion sort
	{
		row<int>* a = make_row(b,10);
		insertion_sort(*a);
		std::cout << "Insertion : " << *a << "\n";
		delete a;
	}

	// merge sort
	{
		row<int>* a = make_row(b,10);
		merge_sort(*a);
		std::cout << "Merge     : " << *a << "\n";
		delete a;
	}

	// quick sort
	{
		row<int>* a = make_row(b,10);
		quick_sort(*a);
		std::cout << "Quick     : " << *a << "\n";
		delete a;
	}

	// enum sort
	{
		row<int>* a = make_row(b,10);
		enumeration_sort(*a);
		std::cout << "Enum      : " << *a << "\n";
		delete a;
	}

	// cleanup
	delete a;
	delete[] b;

	return 0;
}
