#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

#define BYTE_LOOP (0x1U)
#define LOOP      (0x2U)
#define UNROLLED  (0x4U)
#define REP_BYTE  (0x8U)
#define REP_4BYTE (0x10U)
#define REP_8BYTE (0x20U)
#define VEC_LOOP  (0x40U)
#define LIBCALL   (0x80U)

/*
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(" ");
}


uint16_t Highest_alg_win(uint16_t *array){
	uint16_t a = 0;
	uint16_t best = 0;
	while(a < ALGS){
		if(array[a]>best){
			best = array[a];
		}
		a++;
	}
	return best;
}
*/

int main(int argc, char **argv){
	FILE *in;
	uint16_t a,b,c,d,e;
	//uint8_t z = 0;
	size_t cur_wins = 0;
	size_t max_wins = 0;
	size_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_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};
	uint16_t rollingwins[MAX_SIZE][ALGS];

	uint16_t saved[RANGES][2];

	

#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*2);

	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);

	//tally up rolling wins/ties
	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[start_a][b]++;
				//ties[start_a] |= (uint8_t)(b+1);
			}
		}
	}

//	for(a=0; a<ALGS; a++)
//		free(data[a]);

	max_wins = 0;
	//loop the start of c
	for(start_c = min_start_c; start_c<max_start_d; start_c++){
		//wins before c
		//loop to find best a/b split
		cur_wins = 0;
		for(start_b = min_start_b; start_b<start_c; start_b++){
			//max wins for an a alg with this start_b
			//a = Highest_alg_win(rollingwins[start_b-1]);
			a = 0;
			for(b=0; b<ALGS; b++){
				d = rollingwins[start_b-1][b];
				if(d>a){
					a = d;
					saved[0][1] = b;
				}
			}
			d = 0;
			for(b=0; b<ALGS; b++){
				c = rollingwins[start_c-1][b] - rollingwins[start_b-1][b];
				if(c > d){
					d = c;
					saved[1][1] = b;
				}
			}
			//if highest combo
			if(a+d > cur_wins){
				cur_wins = a+d;
				coord_a = start_b;
				saved[0][0] = saved[0][1];
				saved[1][0] = saved[1][1];
			}
		}
		//wins after c
		e = 0;
		for(start_d = start_c+1; start_d<max_end_d; start_d++){
			d = 0;
			for(b=0; b<ALGS; b++){
				//wins in the c range
				c = rollingwins[start_d-1][b] - rollingwins[start_c-1][b];
				//c = rollingwins[max_end_d][b] - rollingwins[start_c-1][b] - rollingwins[coord_a][b];
				if(c>d){
					d = c;
					saved[2][1] = b;
				}
			}
			a = 0;
			for(b=0; b<ALGS; b++){
				//wins in d range
				c = rollingwins[max_end_d-1][b] - rollingwins[start_d-1][b];
				if(c>a){
					a = c;
					saved[3][1] = b;
				}
			}
			if(a+d > e){
				e = a+d;
				coord_b = start_d;
				saved[2][0] = saved[2][1];
				saved[3][0] = saved[3][1];
			}
		}
		cur_wins += e;
		if(cur_wins > max_wins){
			//save
			max_wins = cur_wins;
			winning_starts[1] = coord_a;
			winning_starts[2] = start_c;
			winning_starts[3] = coord_b;
			for(a=0; a<RANGES; a++)
				winning_algs[a] = saved[a][0];
		}
	}


	//translate winning_starts into algs candidates

	//ties = (uint8_t *)malloc(sizeof(uint8_t)*max_end_d);
	(void)memset((void *)rollingwins, '\0', sizeof(uint16_t)*MAX_SIZE*ALGS);
	printf("config with most wins in first %u:\n", max_end_d);
	printf("start\talg/s\n");
for(a=0; a<RANGES; a++)
printf("%u %u\n", winning_starts[a], winning_algs[a]);

	for(a=0; a<RANGES; a++){
		//(void)memset((void *)ties, '\0', sizeof(uint8_t)*max_end_d);
		if(a != 3)
			c = winning_starts[a+1];
		else
			c = max_end_d;
		//max_wins = 0;
		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][a] == cur_cycles){
					//winners[b] = 1;
					rollingwins[a][b]++;
					//if(rollingwins[a][b]>max_wins)
					//	max_wins = rollingwins[a][b];
					//ties[a] |= (uint8_t)(b+1);
				}
			}
		}

		max_wins = 0;
		//find highest
		for(b=0; b<ALGS; b++){
			if(rollingwins[a][b] > max_wins)
				max_wins = rollingwins[a][b];
		}
		printf("%u\t", winning_starts[a]);

		//c = 0;
		//print ends
		for(b=0; b<ALGS; b++){
			//if(winners[b])
			if(rollingwins[a][b] == max_wins)
				 printf("%s(%u) ", algs[b], b);
		}


		//for(b=1; b<256; b<<=2){
		//	if(ties[a] | b)
		//		printf("%s(%u) ", algs[c], c);

		//	c++;
		//}
		printf("\n");
	}



	for(a=0; a<ALGS; a++)
		free(data[a]);

	//free(ties);

	return 0;
}
