#include "Dice_Funcs.h"

static uint8_t Has_Straight(uint8_t *roll_results, uint8_t dice){
	/* return 1 if dice are a straight, else 0 
	should only be run when dice == full amount (first roll)*/
	if(dice == 1)
		return 1;
	if(dice == 0)
	return 0;
	uint8_t num1 = 0;
	uint8_t num2 = SIDES;
	uint8_t match_found = 0;
	uint8_t *roll_results_ordered = malloc(dice*sizeof(uint8_t) );

	//find lowest rolled number
	for(num1=0; num1<dice; num1++){
		if(roll_results[num1] < num2)
			num2 = roll_results[num1];
	}
	roll_results_ordered[0] = num2;

	//search for roll that is 1 higher than previous for dice, return 0 if broken
	for(num1=1; num1<dice; num1++){
		match_found = 0;
		for(num2=0; num2<dice; num2++){
			if(roll_results[num2] == roll_results_ordered[num1-1]+1){
				roll_results_ordered[num1] = roll_results[num2];
				match_found = 1;
				break;
			}
		}
		if(match_found == 0)
			return 0;
	}
	free(roll_results_ordered);
	return 1;
}

static uint8_t Has_Three_Pair(uint8_t *num_counts, uint8_t dice){
	/* return 1 if has 3 pair else 0 */
	if(dice < 6)
		return 0;
	uint8_t num1 = 0;
	uint8_t num2 = 0;
	for(num1=0; num1<SIDES; num1++){
		if(num_counts[num1] > 1)
			num2++;
	}
	if(num2 > 2)
		return 1;
	return 0;
}

static uint32_t Roll_Dice(uint32_t p_num){
//static uint32_t Roll_Dice(uint64_t *s, struct Player_Data *pd){
	uint32_t num1, num2, num3;

	//uint8_t roll_results[Dice];
	uint8_t *roll_results = (uint8_t *)malloc(Dice * sizeof(uint8_t));

	uint8_t num_counts[SIDES];
	uint32_t num_scores[SIDES];

	//uint8_t kept_dice[DICE];
	uint8_t *kept_dice = (uint8_t *)malloc(Dice * sizeof(uint8_t));

	uint32_t score = 0;
	uint32_t score_final = 0;
	uint32_t rolling_dice = Dice;
	uint8_t turn_not_over = 1;

	while(turn_not_over == 1){
		printf("\t");
		for(num2=0; num2<rolling_dice; num2++){
			roll_results[num2] = lrand(&(pd[p_num].rseed)) % SIDES + 1;
			printf("%u ", roll_results[num2]);
		}
		printf("\n");
		sleep(1);
		(void)memset(num_counts, '\0', sizeof(uint8_t) * SIDES);
        for(num2=0; num2<rolling_dice; num2++){
            num_counts[ roll_results[num2]-1 ]++;
        }
		(void)memset(num_scores, '\0', sizeof(uint32_t) * SIDES);
		(void)memset(kept_dice, '\0', sizeof(uint8_t) * Dice);
		//set kept_dice
		for(num2=0; num2<rolling_dice; num2++){
			if(roll_results[num2] == 1 || roll_results[num2] == 5){
				kept_dice[num2] = 1;
			}
		}
		for(num2=0; num2<SIDES; num2++){
			if(num_counts[num2] > 2){
				for(num3=0; num3<rolling_dice; num3++){
					if(roll_results[num3] == num2+1)
						kept_dice[num3] = 1;
				}
			}
		}
		//set num_scores
		for(num2=0; num2<SIDES; num2++){
			if(num2 == 0){
				if(num_counts[0] < 3){
					num_scores[0] = 100*num_counts[0];
					continue;
				}
				num_scores[0] = 1000;
				for(num3=3; num3<num_counts[0]; num3++){
					num_scores[0] *= 2;
				}
				continue;
			}
			if(num2 == 4){
				if(num_counts[4] < 3){
					num_scores[4] = 50*num_counts[4];
					continue;
				}
				num_scores[4] = 500;
				for(num3=3; num3<num_counts[4]; num3++){
					num_scores[4] *= 2;
				}
				continue;
			}
			if(num_counts[num2] < 3)
				continue;
			num_scores[num2] = 100*(num2+1);
			for(num3=3; num3<num_counts[num2]; num3++){
				num_scores[num2] *= 2;
			}
		}
		score = 0;
		for(num3=0; num3<SIDES; num3++){
			score += num_scores[num3];
		}
		if(rolling_dice > 5){
			if( Has_Three_Pair(num_counts, rolling_dice) ){
			//must do entirely different if greater than 6 dice
			//could potentially have multiple three pairs ...
			//or three pairs + 1 + 5 + 3 of kind + etc.
				if(score < Three_Pairs_Score){
					rolling_dice = Dice;
					score_final += Three_Pairs_Score;
					continue;
				}
			}
		}
		if(rolling_dice == Dice){
			if( Has_Straight(roll_results, rolling_dice) ){
				if(score < Straight_Score){
					rolling_dice = Dice;
					score_final += Straight_Score;
					continue;
				}
			}
		}
		//do zilch test here
		if(score == 0){
			turn_not_over = 0;
			score_final = 0;
			continue;
		}
		num1 = rolling_dice; //backup
		num3 = 0;
		for(num2=0; num2<rolling_dice; num2++){
			if(kept_dice[num2] == 1)
				num3++;
		}
		if(rolling_dice == num3){
			rolling_dice = Dice;
			score_final += score;
			//can use all dice
			continue;
		}else{
			rolling_dice -= num3;
		}
		//decide what dice to keep/roll or to end turn here
		if(pd[p_num].onboard != 1){
			if(score_final+score < Min_Get_Onboard){
				//must keep rolling
				num3 = 0;
				//have 3+ of kind ?
				for(num2=0; num2<SIDES; num2++){
					if(num_counts[num2] > 2){ //FIXME: for more than 6 dice
						rolling_dice = num1 - num_counts[num2];
						num3 = 1;
						score_final += num_scores[num2];
						break;
					}
				}
				if(num3 == 1)
					continue;
				//keep only a 1 to increase probabilities?
				if(num_counts[0] != 0){ //we have a 1
					if(num_counts[0] < 3){ //we have less than 1000
						//keep just 1
						rolling_dice = num1 - 1;
						score_final += 100;
						continue;
					}
					//keep them all
					rolling_dice = num1 - num_counts[0];
					score_final += num_scores[0];
					continue;
				}
				//have only a 5 ?
				if(num_counts[4] != 0){ //we have a 5
					rolling_dice = num1 - 1;
					score_final += 50;
					continue;
				}
				//FIXME: function return value for main cleanup ie: errno
				printf("Error 1 !\n");
				exit(0);
			}
		}
		if(score_final+score < pd[p_num].min_score_will_keep){
			//must keep rolling
			num3 = 0;
			for(num2=0; num2<SIDES; num2++){
				if(num_counts[num2] > 2){//FIXME: for more than 6 dice
					rolling_dice = num1 - num_counts[num2];
					num3 = 1;
					score_final += num_scores[num2];
					break;
				}
			}
			if(num3 == 1)
				continue;
			if(num_counts[0] != 0){
				if(num_counts[0] < 3){
					rolling_dice = num1 - 1;
					score_final += 100;
					continue;
				}
				rolling_dice = num1 - num_counts[0];
				score_final += num_scores[0];
				continue;
			}
			if(num_counts[4] != 0){
				rolling_dice = num1 - 1;
				score_final += 50;
				continue;
			}
			//FIXME: see above
			printf("Error 2 !\n");
			exit(0);
		}else{
			turn_not_over = 0;
		}
		if( rolling_dice < pd[p_num].min_dice_will_roll){
			//will keep rolling if new rolling_dice value is not too low
			//take score and end turn
			turn_not_over = 0;
		}
		score_final += score;
	}
	free(roll_results);
	free(kept_dice);
	return score_final;
}

void *Worker_Func(void *data){
	uint32_t num1, num2;
	uint32_t turn = 0;
	uint8_t ten_k_reached = 0;
	uint32_t tentative_winner = 0;
	uint32_t leader_score = 0;
	
	struct timeval cur;
	gettimeofday(&cur, NULL);
	//pd = (struct Player_Data *)malloc(sizeof(struct Player_Data) * Num_Players);
	pd[0].rseed = (uint64_t)cur.tv_usec + 3;

	while(1==1){
		sleep(1);
		
		if(Exit_Program)
			break;
	}
	//free(pd);
	pthread_exit(NULL);
}