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

#define ALGS 8
#define RANGES 4
#define MAX_SIZE 32768

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


int main(int argc, char **argv){
	FILE *in;
	uint16_t a,b,c=0;
	size_t cur_wins = 0;
	size_t max_wins = 0;
	//size_t cur_fastest = 0;
	size_t cur_cycles = 0;

//	uint16_t positions_alg[4] = {0,0,0,0};
//	uint16_t positions_start[4] = {0,0,0,0};
//	uint16_t positions_end[4] = {0,0,0,0};
//	uint16_t positions_max[4] = {32764, 32765, 32766, 32767};

	uint16_t winning_starts[4] = {0,0,0,0};
	uint8_t winning_algs[4] = {0,0,0,0};
	uint32_t data[ALGS][MAX_SIZE];
	uint32_t fastest[MAX_SIZE];
	uint32_t read_buffer_size = 64;
	char *read_buffer = (char *)malloc(read_buffer_size + 1);
	(void)memset( (void *)read_buffer, '\0', read_buffer_size + 1);

	uint16_t test_max = MAX_SIZE; // = atoi(argv[1]);
	//uint16_t end_a = 0;
	//uint16_t end_b = 0;
	uint16_t start_a = 0;
	uint16_t start_b = 0;
	uint16_t start_c = 0;
	uint16_t start_d = 0;
	uint16_t min_start_a = 0;
	uint16_t min_start_b = 1;
	uint16_t min_start_c = 2;
	uint16_t min_start_d = 3;
	//uint16_t max_end_a = test_max - 3;
	//uint16_t max_end_b = test_max - 2;
	//uint16_t max_end_c = test_max - 1;
	uint16_t max_end_d = test_max;

//	uint16_t wins_a = 0;
//	uint16_t wins_b = 0;
//	uint16_t wins_c = 0;
	//uint16_t wins_d = 0;

	//uint16_t min_end_a = 1;
	//uint16_t min_end_b = 2;
	uint8_t alg_a = 0;
//	uint8_t alg_b = 0;
//	uint8_t alg_c = 0;
//	uint8_t alg_d = 0;

uint16_t wins_Ra[8] = {0,0,0,0,0,0,0,0};
uint16_t wins_Rb[8] = {0,0,0,0,0,0,0,0};
uint16_t wins_Rc[8] = {0,0,0,0,0,0,0,0};
uint16_t wins_Rd[8] = {0,0,0,0,0,0,0,0};
uint16_t wins_Ra_t[8] = {0,0,0,0,0,0,0,0};
uint16_t wins_Rb_t[8] = {0,0,0,0,0,0,0,0};
uint16_t wins_Rc_t[8] = {0,0,0,0,0,0,0,0};
//uint16_t wins_Rd_t[8] = {0,0,0,0,0,0,0,0};
uint16_t winners[4] = {0,0,0,0};

	if(argc != 1)
		test_max = atoi(argv[1]);
	printf("Testing to %u\n", test_max);

	for(a=0; a<ALGS; 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_SIZE)
				break;
			data[a][b] = atoi(read_buffer);
			b++;
		}
		fclose(in);
	}
	free(read_buffer);

	//put only the times of the fastest in new array
	for(a=0; a<MAX_SIZE; a++){
		cur_cycles = UINT32_MAX;
		for(b=0; b<ALGS; b++){
			if(data[b][a]<cur_cycles){
				cur_cycles = data[b][a];
				c = b;
			}
		}
		fastest[a] = c;
	}


//start_a = min_start_a;

	//calculate wins for each alg of each range on start (NOTE: will be 1 position checked unless mins_start_* changed)
	//except range d where max_end_d - min_start_d are checked
	for(start_d = min_start_d; start_d<max_end_d; start_d++){
		for(alg_a=0; alg_a<ALGS; alg_a++){
			if(fastest[start_d] == alg_a)
				wins_Rd[alg_a]++;
		}
	}

        for(start_c = min_start_c; start_c<min_start_d; start_c++){
                for(alg_a=0; alg_a<ALGS; alg_a++){
                        if(fastest[start_c] == alg_a)
                                wins_Rc[alg_a]++;
                }
        }

        for(start_b = min_start_b; start_b<min_start_c; start_b++){
                for(alg_a=0; alg_a<ALGS; alg_a++){
                        if(fastest[start_b] == alg_a)
                                wins_Rb[alg_a]++;
                }
        }

        for(start_a = min_start_a; start_a<min_start_b; start_a++){
                for(alg_a=0; alg_a<ALGS; alg_a++){
                        if(fastest[start_a] == alg_a)
                                wins_Ra[alg_a]++;
                }
        }




	//start range d
	for(start_d = min_start_d; start_d<max_end_d; start_d++){
		printf("%u/MAX_SIZE\n", start_d);
		(void)memcpy((void *)wins_Rc_t, (const void *)wins_Rc, sizeof(uint16_t)*ALGS);
		//start range c
		for(start_c = min_start_c; start_c<start_d; start_c++){
			(void)memcpy((void *)wins_Ra_t, (const void *)wins_Ra, sizeof(uint16_t)*ALGS);
			(void)memcpy((void *)wins_Rb_t, (const void *)wins_Rb, sizeof(uint16_t)*ALGS);
			//start range b
			for(start_b = min_start_b; start_b<start_c; start_b++){
				b=0;
				for(a=0; a<ALGS; a++){
					if(wins_Rd[a]>b){
						b = wins_Rd[a];
						winners[3] = a;
					}
				}

				b=0;
				for(a=0; a<ALGS; a++){
					if(wins_Rc_t[a]>b){
						b = wins_Rc_t[a];
						winners[2] = a;
					}
				}

				b=0;
				for(a=0; a<ALGS; a++){
					if(wins_Rb_t[a]>b){
						b = wins_Rb_t[a];
						winners[1] = a;
					}
				}

				b=0;
				for(a=0; a<ALGS; a++){
					if(wins_Ra_t[a]>b){
						b = wins_Ra_t[a];
						winners[0] = a;
					}
				}

				//add together for cur_wins

				//for(alg_a=0; alg_a<ALGS; alg_a++){
				cur_wins = wins_Rd[winners[3]] + wins_Rc_t[winners[2]] + wins_Rb_t[winners[1]] + wins_Ra_t[winners[0]];
				if(cur_wins > max_wins){
					//continue;
					//winning_starts[0] = start_a;
					winning_starts[1] = start_b;
					winning_starts[2] = start_c;
					winning_starts[3] = start_d;
					winning_algs[0] = winners[0];
					winning_algs[1] = winners[1];
					winning_algs[2] = winners[2];
					winning_algs[3] = winners[3];
					max_wins = cur_wins;
				}
					//cur_wins=0;

					//selectively incremember alg in range a that gained a win
					//A range is different ?
					//wins_Ra[fastest[start_a]]--;
				//}
				//selectively decremember alg in range b that gained a win
				wins_Rb_t[fastest[start_b]]--;
				wins_Ra_t[fastest[start_b]]++;
			}
			//selectively decremember alg in range c that gained a win
			wins_Rc_t[fastest[start_c]]--;
			wins_Rb_t[fastest[start_c]]++;
			
		}
		//selectively decrement alg that lost a win
		wins_Rd[fastest[start_d]]--;
		wins_Rc[fastest[start_d]]++;
	}

/*
	positions_start[0] = 0;
	//positions_start[0] = positions_max[0];

	positions_max[0]=test_max-2;
	positions_max[1]=test_max-1;

	for(positions_end[0]=positions_max[0]; positions_end[0]>positions_start[0]; positions_end[0]--){
		//printf("%u/64\n", positions_end[0]);
		positions_start[1] = positions_end[0];
		for(positions_end[1]=positions_max[1]; positions_end[1]>positions_start[1]; positions_end[1]--){
			for(positions_alg[0]=0; positions_alg[0]<ALGS; positions_alg[0]++){
				for(positions_alg[1]=0; positions_alg[1]<ALGS; positions_alg[1]++){
					//for(positions_alg[2]=0; positions_alg[2]<ALGS; positions_alg[2]++){
					//	for(positions_alg[3]=0; positions_alg[3]<ALGS; positions_alg[3]++){
							cur_wins = 0;
							for(a=0; a<test_max; a++){
								if(a < positions_start[1]){
									b = positions_alg[0];
								}else{
									b = positions_alg[1];
								}
								if(fastest[a] == data[b][a])
									cur_wins++;
							}
							if(cur_wins < max_wins)
								continue;
							for(a=0; a<2; a++){
								winning_starts[a] = positions_start[a];
								winning_algs[a] = positions_alg[a];
							}
							max_wins = cur_wins;
							//}
						//}
					//}
				}
			}
		}
	}
*/

	printf("config with most wins in first %u:\n", test_max);
	printf("winning_alg\tstart\n");
	for(a=0; a<4; a++){
		printf("\t%u\t\t%u\n", winning_algs[a], winning_starts[a]);
	}
	//printf("\n");
	//printf("\n");
	//printf("\n");

	return 0;
}
