# Load all the necessary modules.
reload ("func_ra", 1, 1);

reload ("func_ra_sort", 1, 1);
#reload ("func_ra_sort", 0, 0);

# *************************
# * Some global variables *
# *************************

# **********************************
# * START USER DEFINABLE VARIABLES *
# **********************************

# What to test?
test_bubblesort = FALSE;
test_bubblesort2 = TRUE;
test_mergesort = FALSE;
test_mergesort2 = TRUE;
test_quicksort = FALSE;
test_quicksort2 = TRUE;

# Number of elements in array to sort
racount = 199; #200;

# Smallest element value in array to sort
min_elem = -500;

# Largest element value in array to sort
max_elem = 500;

# Number of sorting loops 
loopcount = 3;

# Whether to report result of sorted array (can be long if lots of elements)
report_sorted_array = TRUE;

# ********************************
# * END USER DEFINABLE VARIABLES *
# ********************************



# the range of the element values
elem_range = max_elem - min_elem;

# Total time for iteratations.
totaltime = 0;
starttime = 0;



# *****************************
# * Some supporting functions *
# *****************************

# Reports the content of a sequential array.
function array_report (inout ra[]) {
	auto ralen, i, fidx, lidx;
	array_get_first_last_index (ra, fidx, lidx);

	for (i = fidx; i <= lidx; i++) {
		report_msg (i &"="& ra[i]);
	}
}

# Verifies that the array is sorted
function array_verify_sort (inout ra[], in startindex, in lastindex) {
	auto last, curr, fidx, lidx, i;
	
	if (nargs < 2) {
		array_get_first_last_index (ra, fidx, lidx);
	} else if (nargs == 3) {
		fidx = startindex;
		lidx = lastindex;
	} else {
		return (report_param_msg ("array_verify_sort"));
	}
	for (i = fidx; i <= lidx; i++) {
		curr = ra[i];
		if (i == fidx) {
			# first time
			last = curr;
		} else {
			if (curr < last) {
				tl_step ("ERROR", FAIL, "Value of index " & i &": '"& curr &"' is smaller than the previous value: '"& last &"'");
				return E_GENERAL_ERROR;
			}
			last = curr;
		}
	}
	return E_OK;
}




# *************************************************************
# * Create an array, and populate it with some random numbers
# *************************************************************
public ra[], ra1[];
array_clear (ra);
for (i = 0; i < racount; i++) { ra[i] = (int (rand() * elem_range)) + min_elem; }




# *********************
# * M E R G E S O R T *
# *********************
if (test_mergesort) {
	totaltime = 0;
	report_msg ("Mergesort...");
	# warmup
	array_shuffle(ra);
	res = array_mergesort (ra);
	for (i = 0; i < loopcount; i++) {
		array_shuffle (ra);
		start_transaction ("Mergesort");
		starttime = get_time();
		res = array_mergesort (ra);
		totaltime += get_time() - starttime;
		end_transaction ("Mergesort", (res == E_OK) ? PASS : FAIL);
	}

	report_msg ("Average time: " & (totaltime / loopcount) & " seconds");
	array_verify_sort (ra);

	if (report_sorted_array) {
		report_msg ("***********************");
		report_msg ("Sorted array from Mergesort:");
		array_report (ra);
		report_msg ("***********************");
	}
}


# ***********************
# * M E R G E S O R T 2 *
# ***********************
if (test_mergesort2) {
	totaltime = 0;
	report_msg ("Mergesort2...");
	# warmup
	array_shuffle(ra);
	res = array_mergesort2 (ra);
	for (i = 0; i < loopcount; i++) {
		array_shuffle (ra);

		array_clear (ra1);
		ra1[0] = 75;
		ra1[1] = 2;
		ra1[2] = 55;
		array_append(ra, ra1);
		array_add(ra1, 75);
		array_add(ra1, 2);
		array_add(ra1, 55);

		start_transaction ("Mergesort2");
		starttime = get_time();
		#res = array_mergesort2 (ra);
		res = array_mergesort2 (ra1, 3, racount + 2);
		totaltime += get_time() - starttime;
		end_transaction ("Mergesort2", (res == E_OK) ? PASS : FAIL);
	}

	report_msg ("Average time: " & (totaltime / loopcount) & " seconds");
	array_verify_sort (ra1, 3, racount + 2);

	if (report_sorted_array) {
		report_msg ("***********************");
		report_msg ("Sorted array from Mergesort2:");
		array_report (ra);
		report_msg ("***********************");
	}
}




# *********************
# * Q U I C K S O R T *
# *********************
if (test_quicksort) {
	totaltime = 0;
	report_msg ("Quicksort...");
	# warmup
	array_shuffle(ra);
	res = array_quicksort (ra);
	for (i = 0; i < loopcount; i++) {
		array_shuffle (ra);
		start_transaction ("Quicksort");
		starttime = get_time();
		res = array_quicksort (ra);
		totaltime += get_time() - starttime;
		end_transaction ("Quicksort", (res == E_OK) ? PASS : FAIL);
	}

	report_msg ("Average time: " & (totaltime / loopcount) & " seconds");
	array_verify_sort (ra);

	if (report_sorted_array) {
		report_msg ("***********************");
		report_msg ("Sorted array from Quicksort:");
		array_report (ra);
		report_msg ("***********************");
	}
}

# ***********************
# * Q U I C K S O R T 2 *
# ***********************
if (test_quicksort2) {
	totaltime = 0;
	report_msg ("Quicksort2...");
	# warmup
	array_shuffle(ra);
	res = array_quicksort2 (ra);
	for (i = 0; i < loopcount; i++) {
		array_shuffle (ra);

		array_clear (ra1);
		ra1[0] = 75;
		ra1[1] = 2;
		ra1[2] = 55;
		array_append(ra, ra1);
		array_add(ra1, 75);
		array_add(ra1, 2);
		array_add(ra1, 55);

		start_transaction ("Quicksort2");
		starttime = get_time();
		res = array_quicksort2 (ra1, 3, racount + 2);
		totaltime += get_time() - starttime;
		end_transaction ("Quicksort2", (res == E_OK) ? PASS : FAIL);
	}

	report_msg ("Average time: " & (totaltime / loopcount) & " seconds");
	array_verify_sort (ra1, 3, racount + 2);

	if (report_sorted_array) {
		report_msg ("***********************");
		report_msg ("Sorted array from Quicksort2:");
		array_report (ra);
		report_msg ("***********************");
	}
}



# ***********************
# * B U B B L E S O R T *
# ***********************
if (test_bubblesort) {
	totaltime = 0;
	report_msg ("Bubblesort...");
	# warmup
	array_shuffle(ra);
	res = array_bubblesort (ra);
	for (i = 0; i < loopcount; i++) {
		array_shuffle (ra);
		start_transaction ("Bubblesort");
		starttime = get_time();
		res = array_bubblesort (ra);
		totaltime += get_time() - starttime;
		end_transaction ("Bubblesort", (res == E_OK) ? PASS : FAIL);
	}

	report_msg ("Average time: " & (totaltime / loopcount) & " seconds");
	array_verify_sort (ra);

	if (report_sorted_array) {
		report_msg ("***********************");
		report_msg ("Sorted array from Bubblesort:");
		array_report (ra);
		report_msg ("***********************");
	}
}

# *************************
# * B U B B L E S O R T 2 *
# *************************
if (test_bubblesort2) {
	totaltime = 0;
	report_msg ("Bubblesort2...");
	# warmup
	array_shuffle(ra);
	res = array_bubblesort2 (ra);
	for (i = 0; i < loopcount; i++) {
		array_shuffle (ra);

		array_clear (ra1);
		ra1[0] = 75;
		ra1[1] = 2;
		ra1[2] = 55;
		array_append(ra, ra1);
		array_add(ra1, 75);
		array_add(ra1, 2);
		array_add(ra1, 55);

		start_transaction ("Bubblesort2");
		starttime = get_time();
		res = array_bubblesort2 (ra1, 3, racount + 2);
		totaltime += get_time() - starttime;
		end_transaction ("Bubblesort2", (res == E_OK) ? PASS : FAIL);
	}

	report_msg ("Average time: " & (totaltime / loopcount) & " seconds");
	array_verify_sort (ra1, 3, racount + 2);

	if (report_sorted_array) {
		report_msg ("***********************");
		report_msg ("Sorted array from Bubblesort2:");
		array_report (ra);
		report_msg ("***********************");
	}
}
