#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#ifdef IS32BIT
#define ALGS 7
#else
#define ALGS 8
#endif

#define RANGES 4

#ifndef MAX_SIZE
#define MAX_SIZE 32768
#endif

#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif

/*
static void Print_Alg(uint16_t alg){
	if(alg>(ALGS-1)){
		printf("error");
		return;
	}
	uint8_t n1;
#ifdef IS32BIT
	const char *algs[] = {"byte_loop", "loop", "unrolled_loop", "rep_byte", "rep_4byte", "vector_loop", "libcall"};
#else
	const char *algs[] = {"byte_loop", "loop", "unrolled_loop", "rep_byte", "rep_4byte", "rep_8byte", "vector_loop", "libcall"};
#endif
	printf("\t%s", algs[alg]);
	for(n1=strlen(algs[alg]); n1<14; n1++)
		printf(" ");
}
*/

int main(int argc, char **argv){
	FILE *in;
	uint16_t a,b,c; //,d,e;
	//uint8_t z = 0;
	uint16_t cur_wins = 0;
	uint16_t max_wins = 0;
	uint32_t cur_cycles = 0;
	uint16_t winning_starts[RANGES] = {0,0,0,0};
	//uint16_t winning_algs[RANGES] = {0,0,0,0};
	uint32_t *data[ALGS];
	//uint8_t *ties;
	uint32_t read_buffer_size = 64;
	char *read_buffer;
	uint16_t start_a = 0;
	uint16_t start_b = 0;
	uint16_t start_c = 0;
	uint16_t start_d = 0;
	//const uint16_t min_start_a = 0;
	const uint16_t min_start_b = 1;
	const uint16_t min_start_c = 2;
	const uint16_t min_start_d = 3;
	//const uint16_t max_end_a = MAX_SIZE-3;
	//const uint16_t max_end_b = MAX_SIZE-2;
	const uint16_t max_end_c = MAX_SIZE-1;
	const uint16_t max_end_d = MAX_SIZE;
	//const uint16_t max_start_d = MAX_SIZE-1;
	//uint16_t coord_a = 0;
	//uint16_t coord_b = 0;
	//uint8_t alg_a = 0;
	//uint16_t winners[ALGS] = {0,0,0,0,0,0,0,0};
	// [end][]
	uint16_t rollingwins_a[MAX_SIZE][ALGS]; //[0] = member 0
	uint16_t rollingwins_b[MAX_SIZE][(ALGS*2+1)]; //
	//uint16_t rollingwins_c[MAX_SIZE-1][ALGS]; //[0..1] = empty
	//uint16_t rollingwins_d[MAX_SIZE][ALGS];   //[0..2] = empty
	// [start][end][]
	//uint16_t rollingwins_b[MAX_SIZE-1][MAX_SIZE-2][ALGS];
	//uint16_t **rollingwins_b;

	//[start-1][end]  -2 so no sub needed each time
	//uint16_t **rollingwins_b[MAX_SIZE-2];

	uint16_t saved[RANGES];
	uint16_t algtmpa[ALGS];
	uint16_t algtmpb[ALGS];
	uint16_t algtmpc[ALGS];
	uint16_t tmpcount[RANGES][ALGS];
#ifdef IS32BIT
        const char *algs[] = {"byte_loop", "loop", "unrolled_loop", "rep_byte", "rep_4byte", "vector_loop", "libcall"};
#else
        const char *algs[] = {"byte_loop", "loop", "unrolled_loop", "rep_byte", "rep_4byte", "rep_8byte", "vector_loop", "libcall"};
#endif

	printf("Testing to %u\n", max_end_d);

	for(a=0; a<ALGS; a++){
		data[a] = (uint32_t *)malloc(sizeof(uint32_t)*max_end_d);
	}
	//ties = (uint32_t *)malloc(sizeof(uint8_t)*max_end_d);
	read_buffer = (char *)malloc(read_buffer_size + 1);
	(void)memset( (void *)read_buffer, '\0', read_buffer_size + 1);
	//(void)memset((void *)rollingwins, '\0', sizeof(uint16_t)*MAX_SIZE*ALGS);
	(void)memset( (void *)saved, '\0', sizeof(uint16_t)*RANGES);


	(void)memset((void *)rollingwins_a, '\0', sizeof(uint16_t)*(MAX_SIZE)*ALGS);
	(void)memset((void *)rollingwins_b, '\0', sizeof(uint16_t)*(MAX_SIZE-2)*(ALGS*2+1));

	c = 0;
	for(a=0; a<8; a++){
#ifdef IS32BIT
		if(a == 5)
			continue;
#endif
		(void)sprintf(read_buffer, "results/r%u.txt", a+1);
		in = fopen(read_buffer, "r");
		b = 0;
		(void)memset( (void *)read_buffer, '\0', read_buffer_size + 1);
		while( fgets(read_buffer, read_buffer_size, in) != NULL){
			if(b == max_end_d)
				break;
			data[c][b] = atoi(read_buffer);
			b++;
		}
		fclose(in);
		c++;
	}
	free(read_buffer);
printf("here 1\n");
	//tally up rolling wins/ties for min_start_a
	for(start_a = 0; start_a<max_end_d; start_a++){
		cur_cycles = UINT32_MAX;
		//a = data[b][start_a];
		for(b=0; b<ALGS; b++){
			if(data[b][start_a]<cur_cycles)
				cur_cycles = data[b][start_a];
		}
		for(b=0; b<ALGS; b++){
			if(data[b][start_a] == cur_cycles){
				rollingwins_a[start_a][b]++;
				//ties[start_a] |= (uint8_t)(b+1);
			}
		}
	}

	max_wins = 0;
	for(start_d = min_start_d; start_d<max_end_d; start_d++){
		//pick best d rolling win
		saved[3]=0;
		for(b=0; b<ALGS; b++){
			a = (rollingwins_a[max_end_d-1][b] - rollingwins_a[start_d-1][b]);
			if(a > saved[3]){
				//winners[3] = b;
				saved[3] = a;
			}
		}
		//cur_wins = 0;
		for(start_c = min_start_c; start_c<start_d; start_c++){
			//cur_wins = 0;
			saved[2]=0;
			for(b=0; b<ALGS; b++){
				//wins_total - wins_d - wins_b - wins_a = wins_c
				a =  (rollingwins_a[start_d-1][b] - rollingwins_a[start_c-1][b]);
				if(a > saved[2]){
					//winners[2] = b;
					saved[2] = a;
				}
			}

			for(start_b = min_start_b; start_b<start_c; start_b++){
				saved[0] = 0;
				saved[1] = 0;
				cur_wins = 0;
				//a
				for(b=0; b<ALGS; b++){
					a = rollingwins_a[start_b-1][b];
					if(a > saved[0])
						saved[0] = a;
				}
				//b
				for(b=0; b<ALGS; b++){
					a = rollingwins_a[start_c-1][b] - rollingwins_a[start_b-1][b];
					if(a > saved[1])
						saved[1] = a;
				}



				for(a=0; a<RANGES; a++)
					cur_wins += saved[a];
				if(cur_wins < max_wins)
					continue;
				max_wins = cur_wins;
				winning_starts[1] = start_b;
				winning_starts[2] = start_c;
				winning_starts[3] = start_d;
				//winning algs later :/
			}
		}


	}
printf("here 4\n");
	(void)memset((void *)tmpcount, '\0', sizeof(uint16_t)*RANGES*ALGS);
	printf("config with most wins in first %u:\n", max_end_d);
	printf("start\talg/s\n");
	for(a=0; a<RANGES; a++){
		if(a != 3)
			c = winning_starts[a+1];
		else
			c = max_end_d;
		for(start_a = winning_starts[a]; start_a<c; start_a++){
			cur_cycles = UINT32_MAX;
			for(b=0; b<ALGS; b++){
				if(data[b][start_a]<cur_cycles)
					cur_cycles = data[b][start_a];
			}
			for(b=0; b<ALGS; b++){
				if(data[b][start_a] == cur_cycles){
					tmpcount[a][b]++;
				}
			}
		}
		max_wins = 0;
		for(b=0; b<ALGS; b++){
			if(tmpcount[a][b] > max_wins)
				max_wins = tmpcount[a][b];
		}
		printf("%u\t", winning_starts[a]);
		for(b=0; b<ALGS; b++){
			if(tmpcount[a][b] == max_wins)
				printf("%s(%u) ", algs[b], b);
		}
		printf("\n");
	}
printf("here 5\n");
	for(a=0; a<ALGS; a++)
		free(data[a]);
	//free(ties);

	return 0;
}
