/**
 * Copyright © 2016 Xavier G. <xavier@kindwolf.org>
 * This work is free. You can redistribute it and/or modify it under the
 * terms of the Do What The Fuck You Want To Public License, Version 2,
 * as published by Sam Hocevar. See the COPYING file for more details.
 */

/**
 * This file is a skeleton intended to test a sorting algorithm.
 * To use it, create foobar.c with the following contents:
 *   void array_sort(unsigned int **array, unsigned int count) {
 *       do_stuff_here();
 *   }
 *   #define ARRAY_SORT 1
 *   #include "common.c"
 * Then compile it by running: gcc foobar.c -o foobar
 * Executing foobar will run your sorting function to sort an array of
 * integers.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>


unsigned int *array;
int verbose;


#define VERBOSE(level, format, ...) \
	if (verbose >= level) fprintf(stdout, format, __VA_ARGS__);


void array_fill(unsigned int *array, unsigned int count, unsigned int max) {
	if (!array || !count) return;
	if (!max) max = RAND_MAX;
	for (unsigned int i = 0; i < count; ++ i) {
		array[i] = rand() % max;
	}
}

void array_display(unsigned int *array, unsigned int count, const char *prefix, const char *suffix) {
	if (!array) return;
	if (prefix) printf(prefix);
	printf("[");
	for (unsigned int i = 0; i < count; ++ i) {
		printf(i ? ", %d" : "%d", array[i]);
	}
	printf("]");
	if (suffix) printf(suffix);
}

int usage(char *program_name) {
	fprintf(stderr, "Usage: %s [count]\n", program_name);
	exit(EXIT_FAILURE);
}

int main(int argc, char **argv, char **envp) {
	int count_arg;
	char *endptr, *verbose_ve;
	struct timeval before_start, after_end, diff;
	unsigned int count;
	unsigned int max;

	/* By default, generate an array of 100 integers between 0 and 10000: */
	count = 100;
	max = 10000;
	verbose = -1;

	/* Accept a single, optional command-line argument to override count: */
	if (argc > 2) {
		usage(argv[0]);
	}
	/* Attempt to parse that argument as a positive integer: */
	if (argc == 2) {
		errno = 0;
		count_arg = strtol(argv[1], &endptr, 10);
		/* Check endptr to ensure some digits were found: */
		if (!errno && endptr != argv[1] && count_arg >= 0) {
			count = count_arg;
		}
		else {
			usage(argv[0]);
		}
	}

	/* Allow overriding verbosity through an environment variable: */
	if ((verbose_ve = getenv("SORTING_VERBOSE"))) {
		verbose = strtol(verbose_ve, NULL, 10);
	}

	/* Require memory for an array of integers, fill it with random crap: */
	array = malloc(sizeof(unsigned int) * count);
	srand(time(NULL));
	array_fill(array, count, max);
	array_display(array, count, "Before: ", "\n\n");

	/* Look at our watch, do the work, look at our watch again: */
	printf("=> About to sort %u items\n", count);
	gettimeofday(&before_start, NULL);
#ifdef ARRAY_SORT
	array_sort(&array, count);
#endif
	gettimeofday(&after_end, NULL);

	/* Compute how much time the work took and display the results: */
	timersub(&after_end, &before_start, &diff);
	printf("<= Sorted %u items in %ld.%06lds\n\n", count, diff.tv_sec, diff.tv_usec);
	array_display(array, count, "After: ", "\n");

	return 0;
}