#include "Life.h"

/*
struct Species ***life;
struct Stats *stats;
struct Stats_T stats_t;
struct image_attr *ia;
struct Thread_I *thread_i;
struct Thread_I *thread_di_i;


char *life_speed_up_H;
char *life_speed_up_W;
char **fought;
char **mated;
*/
static void KILL_Tribe(unsigned int y, unsigned int x){
	//free(life[y][x]);
    //life[y][x] = NULL;
	life[y][x]->alive = 0;
	fought[y][x] = 0;
	mated[y][x] = 0;
}

void Allocate_Life_Array(size_t height, size_t width){
	size_t n1, n2;
	life = (struct Species ***)malloc(sizeof(struct Species **) * height);
	for(n1=0; n1<height; n1++){
		life[n1] = (struct Species **)malloc(sizeof(struct Species *) * width);
	//}
	//for(n1=0; n1<height; n1++){
		for(n2=0; n2<width; n2++){
			//allocate them all unless they'll always be water
			//if( ia->data[n1][n2] < 100)
			//	life[n1][n2] = NULL;
			//	continue;
			//}
			life[n1][n2] = (struct Species *)malloc(sizeof(struct Species));
			//life[n1][n2]->alive = 0;
			(void)memset( (void *)life[n1][n2], '\0', sizeof(struct Species) );
		}
	}
	//Make stats initialized to 0
	//(void)memset( (void *)&stats, '\0', sizeof(struct Stats) );
	life_speed_up_H = (char *)malloc(sizeof(char)*height);
	life_speed_up_W = (char *)malloc(sizeof(char)*width);
	(void)memset( (void *)life_speed_up_H, '\0', sizeof(char)*height );
	(void)memset( (void *)life_speed_up_W, '\0', sizeof(char)*width );
	return;
}

void Gen_Tribe_Color(struct Species *one, unsigned char *rgb){
	// 6751269 possibilities based on species/traits
	rgb[0] = one->intelligence; //floor(one->intelligence/2) + floor(one->temp_l/2); //+ floor(one->social_factor/3);
	rgb[1] = floor(one->strength/2) + floor(one->speed/2);//+ floor(one->temp_h/2); //+ floor(one->fight_flight_balance/4) + floor(one->interspecies_violence/4);
	rgb[2] = one->temp_l + one->temp_h + one->max_age;
	//floor(one->temp_l/2) + floor(one->temp_h/2) + floor(one->max_age/2); //+ floor(one->migration_factor/4);
	//one->intelligence
	//one->strength
	//one->speed

}

int Is_Same_Species(struct Species *one, struct Species *two){
	// "dna" determined by all variables, no one variable can deviate more than 4
	//better to implement steps instead ie: 0-3 4-7 8-11 etc.  4*(0->63)+(0->4)
	// y=mx+b   y range 0-255,  if x = x same species, b == subspecies deviation
	//must allow for subspecies deviation

	//unsigned char x = floor(num/4);
	//b = 255%4 * 4;
	//if(one == NULL || two == NULL)
	//	return 0;

	if( floor(one->intelligence/4) != floor(two->intelligence/4) )
		return 0;
	if( floor(one->strength/4) != floor(two->strength/4) )
		return 0;
	if( floor(one->speed/4) != floor(two->speed/4) )
		return 0;
	if( floor(one->temp_l/4) != floor(two->temp_l/4) )
		return 0;
	if( floor(one->temp_h/4) != floor(two->temp_h/4) )
		return 0;
	if( floor(one->max_age/4) != floor(two->max_age/4) )
		return 0;
	if( floor(one->reproductive_rate/4) != floor(two->reproductive_rate/4) )
		return 0;

	return 1;
}

void Add_First_Life(struct Species *one){
	one->alive = 1;
	one->intelligence = 16;
	one->strength = 16;
	one->speed = 16;
	one->imunity = 127;
	one->temp_l = 10;
	one->temp_h = 34;
	one->reproductive_rate = 1;

	one->fight_flight_balance = 31;
	one->interspecies_violence = 31;
	one->migration_factor = 63;
	one->social_factor = 127;

	one->max_age = 36;
	one->cur_age = 0;
	//one->fought = 0;
	//one->mated = 0;

}

float Location_Temp(uint32_t src_y, uint32_t src_x){
	//printf("1a\n");
	//return temperature at any given src_y src_x
	//int32_t global_mean = ia->cur_temp;
	float location_temp = (float)ia->cur_temp;
	float equator_dist = 0;

	//bordering water, degrees cooler
	//if(ia->data[src_y-1][src_x] < 1)
	//	offset = -1;
	//printf("cur_temp: %f\n", ia->cur_temp);
	//elevation effect
	if(ia->data[src_y][src_x] < 11001){
		location_temp += 6.49*((float)(ia->data[src_y][src_x]-ia->cur_sealevel)/1000);
		//printf("elevation effect: %f\n", 6.49*((float)ia->data[src_y][src_x]/1000) );
	}else{
		location_temp -= 56.5;
	}
	//printf("\tcur_temp: %f\n", location_temp);
	//dealing with 1/12th scale of 30 arc-second grid
	//1 arc minute = 1/60 of 1deg
	//30 arc-second = 1/30 of 1deg
	//1px = 12x 30 arc-second  = 2/5 of 1deg
	//1800px = 90-0-90  900px is equator

	//equatorial distance effect
	equator_dist = abs( (float)src_y - ((float)ia->height/2) ) * 2 / 5;  //degrees from equator
	//printf("equator_dist: %f\n", equator_dist);
	//45c different between eq and poles  .5C per 1deg  hmmmm
	location_temp -= equator_dist / 12;
	//printf("location temp: %f\n", location_temp);
	//printf("1b\n");
	return location_temp;
}

int Climate_Fatal(struct Species *one, uint32_t src_y, uint32_t src_x){
	//return 1 if climate would kill tribe at this location
	// 6.49C/1000m 
	// -56.5 °C above 11000m
	//unsigned char temp_h = one->temp_h;
	//unsigned char temp_l = one->temp_l;
	//int32_t cur_temp = ia->cur_temp;
	//int16_t elevation = ia->data[src_y][src_x];
	//printf("2a\n");

	//need to accound for intelligence and strength to withstand
	float location_temp = Location_Temp(src_y, src_x);

	if(location_temp > (float)one->temp_h){ //if temp is higher than tribe can withstand
		//2 parts intel 1 part strength
		// 127 * 3 = 381
		// 8 pt steps 
		// initial tribes will have +/-6 added to their range
		// 

		if( (one->temp_h + floor( ((float)one->intelligence*2+(float)one->strength) / 8) ) < location_temp ){ //if it's still higher
			//printf("%d %f\\n", one->temp_h, floor( ((float)one->intelligence*2+(float)one->strength) / 8));
			return 1;
		}
	}
	if(location_temp < (float)one->temp_l){ //if temp is lower than tribe can withstand
		if( (one->temp_l + floor( ((float)one->intelligence*2+(float)one->strength) / 8) ) > location_temp ){ //if it's still lower
			//printf("%d %f\n", one->temp_l, floor( ((float)one->intelligence*2+(float)one->strength) / 8)  );
			return 1;
		}
	}
	//printf("2d\n");
	return 0;
}

void Create_Life(struct Species *one, struct Species *two, struct Species *three){
	//mix sub species 1 and 2 to create 3 (average of 1 and 2) [ ~8.3% chance of (+/-1pt) species deviation ]
	//chance of new species:  ~1% 
	int rand1;
	int use_ceil = 0;
	double tmp;
	struct timeval cur;
	gettimeofday(&cur, NULL);
	uint64_t s = (unsigned int)cur.tv_usec * 3 + 3;
	//lrand(uint64_t *s)
	//srand ( (unsigned int)cur.tv_usec );
	rand1 = lrand(&s) % 100 + 1;
	if(rand1 > 50)
		use_ceil = 1;

	three->alive = 1;

	//genetic
	tmp = (one->intelligence + two->intelligence) / 2;
	three->intelligence = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	tmp = (one->strength + two->strength) / 2;
	three->strength = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	tmp = (one->speed + two->speed) / 2;
	three->speed = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	//keep within ranges
	tmp = (one->temp_l + two->temp_l) / 2;
	three->temp_l = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	tmp = (one->temp_h + two->temp_h) / 2;
	three->temp_h = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	//
	tmp = (one->max_age + two->max_age) / 2;
	three->max_age = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );


	//non-genetic
	tmp = (one->social_factor + two->social_factor) / 2;
	three->social_factor = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	tmp = (one->interspecies_violence + two->interspecies_violence) / 2;
	three->interspecies_violence = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	tmp = (one->fight_flight_balance + two->fight_flight_balance) / 2;
	three->fight_flight_balance = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );
	tmp = (one->migration_factor + two->migration_factor) / 2;
	three->migration_factor = (unsigned char)( use_ceil ? ceil(tmp) : floor(tmp) );

	//fixed to 1 for now
	three->reproductive_rate = 1;
	//three->reproductive_rate = (one->reproductive_rate+two->reproductive_rate)/2
	//starts at 0yrs old
	three->cur_age = 0;
	three->imunity = 127;
	//suseconds_t signed integer type capable of storing values at least in the range [-1, 1000000].
	//srand ( (unsigned int)cur.tv_usec );
	//gettimeofday(&cur, NULL);
	//srand ( (unsigned int)cur.tv_usec );

	//rand1 = lrand(&s) % 100;
	//
	//1/12 chance we do a deviation
	//if(rand1 > 49){
		//do deviation
		//int new_species = 0;
		char deviation = (char)lrand(&s) % 100;
		//+1 deviation, otherwise -1
		if(deviation > 49)
			deviation = 1;
		else
			deviation = -1;
		rand1 = lrand(&s) % 9; //which feild will be modified
		// 7/16 chance the selected feild is at an upper/lower limit
		// 7/32 chance deviation is the +1/-1 needed to create new species
		// 5/9 genetic deviation selected
		// ~ 1/1000 chance ultimately of new species (1/20 * 1/50)

		if(rand1 == 0){
			if(deviation){
				if(three->intelligence != 255)
					three->intelligence++;
			}else{
				if(three->intelligence != 0)
					three->intelligence--;
			}
		}else if(rand1 == 1){
			if(deviation){
				if(three->strength != 255)
					three->strength++;
			}else{
				if(three->strength != 0)
					three->strength--;
			}
		}else if(rand1 == 2){
			if(deviation){
				if(three->speed != 255)
					three->speed++;
			}else{
				if(three->speed != 0)
					three->speed--;
			}
		}else if(rand1 == 3){
			//stay within ranges
			if(deviation){
				if(three->temp_h < 39){
					three->temp_h++;
					three->temp_l++;
				}
			}else{
				if(three->temp_l > 4){
					three->temp_h--;
					three->temp_l--;
				}
			}
		}else if(rand1 == 4){
			//stays within range 30 - 128yrs
			if(deviation){
				 if(three->max_age != 100)
					three->max_age++;
			}else{
				if(three->max_age != 26)
					three->max_age--;
			}
		}else if(rand1 == 5){
			if(deviation){
				if(three->social_factor != 255)
					three->social_factor++;
			}else{
				if(three->social_factor != 1)
					three->social_factor--;
			}
		}else if(rand1 == 6){
			if(deviation){
				if(three->interspecies_violence != 255)
					three->interspecies_violence++;
			}else{
				if(three->interspecies_violence != 0)
					three->interspecies_violence--;
			}
		}else if(rand1 == 7){
			if(deviation){
				if(three->fight_flight_balance != 255)
					three->fight_flight_balance++;
			}else{
				if(three->fight_flight_balance != 0)
					three->fight_flight_balance--;
			}
		}else{
			if(deviation){
				if(three->migration_factor != 255)
					three->migration_factor++;
			}else{
				if(three->migration_factor != 0)
					three->migration_factor--;
			}
		}

		//was this a new species or just subspecies
		//1/96 overall chance any new life is a new species
		//if( !Is_Same_Species(one, three) ){
			//printf("New species created!\n");
		//	stats.new_species++;
		//}
	//}

}

static int Tribe_Migrate(unsigned int src_y, unsigned int src_x, unsigned int *dest){
	//return 1 if moved
	//put new location in 

	unsigned int n1, n2;
	unsigned int width = ia->width - 1;
	unsigned int height = ia->height - 1;
	struct Moves{unsigned int x; unsigned int y; unsigned int valid; int rating;}moves[4];
	float temp_preferred = 0;
	float temp_diff = 0;
	float temp_actual = 0;

	//if any of these are greater/less than height or width they need to be set to 0
	//same goes for all neighbors calculations

	//4 potential destination initialization
	if(src_x != 0)
		moves[0].x = src_x - 1;
	else
		moves[0].x = width;

	moves[0].y = src_y;
	moves[0].valid  = 1;
	moves[0].rating = 4;

	if(src_x != width)
		moves[1].x = src_x + 1;
	else
		moves[1].x = 0;

	moves[1].y = src_y;
	moves[1].valid  = 1;
	moves[1].rating = 4;
	moves[2].x = src_x;

	if(src_y != 0)
		moves[2].y = src_y-1;
	else
		moves[2].y = height;

	moves[2].valid  = 1;
	moves[2].rating = 4;
	moves[3].x = src_x;

	if(src_y != height)
		moves[3].y = src_y+1;
	else
		moves[3].y = 0;

	moves[3].valid  = 1;
	moves[3].rating = 4;

	//4 neighors of a move destination
	struct Neighbors{unsigned int x; unsigned int y;}neighbors[4];

	//to store candidate destination with highest rating
	struct Dest_Cand{int h_rating; unsigned int m_index;}dest_cand;
	int cand_ties[4];

    struct timeval cur;
    int rand1;
    gettimeofday(&cur, NULL);
	uint64_t s = (unsigned int)cur.tv_usec * 3 + 3;

	for(n1=0; n1<4; n1++){
		//rule out moving to water
		if(ia->cur_sealevel >= ia->data[moves[n1].y][moves[n1].x]){
			moves[n1].valid = 0;
			continue;
		}
		//rule out moving to occupied coordinates
		if(life[moves[n1].y][moves[n1].x]->alive){
			moves[n1].valid = 0;
			continue;
		}
		//rule out moving to fatal climates
		if( Climate_Fatal(life[src_y][src_x], moves[n1].y, moves[n1].x) )
			moves[n1].valid = 0;
	}
	for(n1=0; n1<4; n1++){
		//if all ruled out return 0;
		if(moves[n1].valid == 1)
			break;
		if(n1 == 3)
			return 0;
	}
	//calculate ratings for valid destinations
	for(n1=0; n1<4; n1++){
		if(!moves[n1].valid)
			continue;
		//initialize neighbors for this potential move
		if(moves[n1].x != 0)
			neighbors[0].x = moves[n1].x-1;
		else
			neighbors[0].x = width;
		neighbors[0].y = moves[n1].y;
		if(moves[n1].x != width)
			neighbors[1].x = moves[n1].x+1;
		else
			neighbors[1].x = 0;
		neighbors[1].y = moves[n1].y;
		neighbors[2].x = moves[n1].x;
		if(moves[n1].y != 0)
			neighbors[2].y = moves[n1].y-1;
		else
			neighbors[2].y = height;
		neighbors[3].x = moves[n1].x;
		if(moves[n1].y != height)
			neighbors[3].y = moves[n1].y+1;
		else
			neighbors[3].y = 0;
		//calculate rating for this move threat/reward
//		for(n2=0; n2<4; n2++){
//			if(neighbors[n2].y == src_y){  //if a neighbor is src_x/src_y don't count self
//				if(neighbors[n2].x == src_x)
//					continue;
//			}
			//if neighbor is empty terrain inc if climate is more favorable
			//ie: more toward the middle of temp_l - temp_h range than current position

/*
			if(!life[moves[n1].y][moves[n1].x]->alive){
				temp_actual = Location_Temp(src_y, src_x);
				temp_diff = Location_Temp(moves[n1].y, moves[n1].x) - temp_actual;
				temp_preferred = (float)(life[src_y][src_x]->temp_l + life[src_y][src_x]->temp_h)/2;

				if(temp_diff < 0){ //am in a higher temp area
					//if lower temp is better than current location
					if( temp_preferred < temp_actual ){
						moves[n1].rating++;
						//continue;
					}
					//if(life[src_y][src_x]->temp_h
					//	moves[n1].rating++;
				}
				if(temp_diff > 0){ //am in a lower temp area
					//if higher temp is better
					if( temp_preferred > temp_actual ){
						moves[n1].rating++;
						//continue;
					}
				}
				//moves[n1].rating++;
				//continue;
			}
*/
        for(n2=0; n2<4; n2++){
            if(neighbors[n2].y == src_y){  //if a neighbor is src_x/src_y don't count self
                if(neighbors[n2].x == src_x)
                    continue;
            }
			if(!life[neighbors[n2].y][neighbors[n2].x]->alive){
				moves[n1].rating++;
				continue;
			}
			//add action for for interspecies_violence maybe


			//if neighbor is different species dec rating
			if(!Is_Same_Species(life[src_y][src_x], life[neighbors[n2].y][neighbors[n2].x]) ){
				moves[n1].rating--;
				continue;
			}
			
			//if neighbor is same inc rating
			moves[n1].rating++;
		}
	}
	dest_cand.h_rating = -1;
	//find destination with highest rating
	for(n1=0; n1<4; n1++){
		if(!moves[n1].valid){
			moves[n1].rating = 0;
			continue;
		}
		if(	moves[n1].rating >= dest_cand.h_rating){
			dest_cand.h_rating = moves[n1].rating;
			dest_cand.m_index  = n1;
		} 

	}
	n2=0;
	//if rating tie should pick a random choice out of them
	//count rating ties
	for(n1=0; n1<4; n1++)
		cand_ties[n1] = 0;
	for(n1=0; n1<4; n1++){
		if(!moves[n1].valid)
			continue;
		if(dest_cand.h_rating == moves[n1].rating){
			cand_ties[n1] = 1;
			n2++;
		}//else{
		//	cand_ties[n1] = 0;
		//}
	}
	if(n2){ //was no tie
		dest[0] = moves[dest_cand.m_index].y;
		dest[1] = moves[dest_cand.m_index].x;
	}
	if(n2 > 1){ //was a tie
		//n2 can be  2  3  or 4
		//gettimeofday(&cur, NULL);
    	//srand ( (unsigned int)cur.tv_usec );
		rand1 = lrand(&s) %  n2 + 1; // 1 to 2, 1 to 3, or 1 to 4
		for(n1=0; n1<4; n1++){
			if(!cand_ties[n1])
				continue;
			//n2++;
			if(n2 == rand1){
				//moves[n1] is dest choice
				dest[0] = moves[n1].y;
				dest[1] = moves[n1].x;
				break;
			}
			n2++;
		}
	}

	if(ia->cur_sealevel < ia->data[dest[0]][dest[1]]){
		
		pthread_mutex_lock( &mutex1 );
		//update life_speed_up_H
		if(!life_speed_up_H[dest[0]])
			life_speed_up_H[dest[0]] = 1;
		//update life_speed_up_W
		if(!life_speed_up_W[dest[1]])
			life_speed_up_W[dest[1]] = 1;
		pthread_mutex_unlock( &mutex1 );
		

		//Move to destination
		life[dest[0]][dest[1]]->alive = 1;
		
		//life[dest[0]][dest[1]] = malloc(sizeof(struct Species));
		(void)memcpy((void *)life[dest[0]][dest[1]], (const void *)life[src_y][src_x], sizeof(struct Species));
		//free(life[src_y][src_x]);
		//life[src_y][src_x] = NULL;
		//migration increases immunity
		if(life[dest[0]][dest[1]]->imunity < 255)
			life[dest[0]][dest[1]]->imunity++;

		//clear old data
		KILL_Tribe(src_y, src_x);
		//printf("here !!\n");
		return 1;
	}
	return 0;
}

static int Fight_Tribe(struct Species *one, struct Species *two){
	//simulate outcome of a potential combat between these two tribes
	// return 1 *one won, 0 *one lost
	int rand1, rand2;
	struct timeval cur;
	//gettimeofday(&cur, NULL);
	//srand ( (unsigned int)cur.tv_usec );
    gettimeofday(&cur, NULL);
    uint64_t s = (unsigned int)cur.tv_usec * 3 + 2;

	//if(!one->alive || !two->alive)
	//	printf("Warning! Fight_Tribe called with non-alive tribe/s\n");

	//fight determined by  1 part strength, 1 part speed, 2 parts intelligence, and 1 part chance
	rand1 = lrand(&s) % 256;
	//gettimeofday(&cur, NULL);
	//srand ( (unsigned int)cur.tv_usec+rand1);
	rand2 = lrand(&s) % 256;
	unsigned int rating1 = one->intelligence*2 + one->strength + one->speed + rand1;
	unsigned int rating2 = two->intelligence*2 + two->strength + two->speed + rand2;
	//cur_age ?
	// 1 in 256 chance they are equal
	if(rating1 > rating2)
		return 1;
	if(rating2 > rating1)
		return 0;
	//equal
	while(rand1 == rand2){
		rand1 = lrand(&s) % 256;
		//gettimeofday(&cur, NULL);
		//srand ( (unsigned int)cur.tv_usec+rand1 );
		rand2 = lrand(&s) % 256;
	}
	return rand1>rand2 ? 1 : 0;
}

static void Tribe_Interactions(unsigned int src_y, unsigned int src_x, unsigned int tid){
	//evaluate all surrounding tribes for threat/reward take proper actions
	unsigned int n1, n2, n3;
	//int index;
	//char chosen[4];
	unsigned int rand1, rand2, rand3;
	int out_come;
	struct timeval cur;
	struct Neighbors{unsigned int y; unsigned int x; unsigned int occupied;}neighbors[4];
	struct Neighbors_T{unsigned int y; unsigned int x;}tmp[4];
	unsigned int width = ia->width - 1;
	unsigned int height = ia->height - 1;

	//if(!life[src_y][src_x]->alive)
	//	printf("Warning Tribe_Interactions: Called for dead tribe!\n");

	//gettimeofday(&cur, NULL);
	//srand ( (unsigned int)cur.tv_usec);
	//rand1 = rand() % 24;  // 0 to 23
    gettimeofday(&cur, NULL);
    uint64_t s = (unsigned int)cur.tv_usec * 3 + 2;

	//need to be randomly assigned, 24 possible permutations of the 4 structures ?
	//n×(n - 1)×(n - 2)×...×2×1


	//for map wrap

	tmp[0].y = src_y;
	if(src_x != 0)
		tmp[0].x = src_x - 1;
	else
		tmp[0].x = width;
	//tmp[0].occupied = 0;

	tmp[1].y = src_y;
	if(src_x != width)
		tmp[1].x = src_x + 1;
	else
		tmp[1].x = 0;
	//tmp[1].occupied = 0;

	if(src_y != 0)
		tmp[2].y = src_y - 1;
	else
		tmp[2].y = height;
	tmp[2].x = src_x;
	//tmp[2].occupied = 0;

	if(src_y != height)
		tmp[3].y = src_y + 1;
	else
		tmp[3].y = 0;
	tmp[3].x = src_x;
	//tmp[3].occupied = 0;

    //gettimeofday(&cur, NULL);
    //srand ( (unsigned int)cur.tv_usec+rand1 );

	//mix them randomly
	rand1 = lrand(&s) % 4;  //pick of any
    //gettimeofday(&cur, NULL);
    //srand ( (unsigned int)cur.tv_usec+rand1+rand1 );

	rand2 = lrand(&s) % 3;  //pick of remaining 3
    //gettimeofday(&cur, NULL);
    //srand ( (unsigned int)cur.tv_usec+rand1+rand2 );

	rand3 = lrand(&s) % 2;  //pick of remaining 2

	neighbors[0].y = tmp[rand1].y;
	neighbors[0].x = tmp[rand1].x;
	neighbors[0].occupied = 0;
	n2 = 0;
	for(n1=0; n1<4; n1++){ //pick second one randomly out of 3 remaining
		if(n1 != rand1){ //if not already taken
			if(n2 == rand2){
				neighbors[1].y = tmp[n1].y;
				neighbors[1].x = tmp[n1].x;
				neighbors[1].occupied = 0;
				break;
			}
			n2++;
		}
	}
	n3 = 0;
	for(n2=0; n2<4; n2++){ //pick third one
		if(n2 != rand1){
			if(n2 != n1){
				if(n3 == rand3){
					neighbors[2].y = tmp[n2].y;
					neighbors[2].x = tmp[n2].x;
					neighbors[2].occupied = 0;
					break;
				}
				n3++;
			}
		}
	}

	for(n3=0; n3<4; n3++){ //last one is the remaining 
		if(n3 != rand1){
			if(n3 != n1){
				if(n3 != n2){
					neighbors[3].y = tmp[n3].y;
					neighbors[3].x = tmp[n3].x;
					neighbors[3].occupied = 0;
					break;
				}
			}
		}
	}

	for(n1=0; n1<4; n1++){
		if(life[neighbors[n1].y][neighbors[n1].x]->alive){
			neighbors[n1].occupied = 1;
		}
	}

	for(n1=0; n1<4; n1++){
		if(neighbors[n1].occupied){
			if( Is_Same_Species(life[src_y][src_x], life[neighbors[n1].y][neighbors[n1].x]) ){
				//social_factor see if we'll mate/fight/nothing
				//rand1 = rand() % (life[src_y][src_x]->social_factor+1) + 1;
				//rand2 = rand() % (life[src_y][src_x]->social_factor+1) + 1;
				//1/1 chance of no mating if social_factor 0  1/256 if 255,  1 / 1*(IM+1)

				//check to see if we'll fight first would be better !
				if(!fought[src_y][src_x]){
					//rand1 = rand() % (life[src_y][src_x]->fight_flight_balance+1) + 1;
					//rand2 = rand() % (life[src_y][src_x]->fight_flight_balance+1) + 1;


				//if(rand1 == rand2){//no mating
				//	if(fought[src_y][src_x]) //no fighting if already fought
				//		continue;

					rand2 = lrand(&s) % 2048;  // 1/16 at 127
					//analyse fight_flight to see if we fight them
					//rand1 = lrand(&s) % (life[src_y][src_x]->interspecies_violence) + 1;
					//gettimeofday(&cur, NULL);
					//srand ( (unsigned int)cur.tv_usec+rand2 );
					//rand2 = lrand(&s) % (life[src_y][src_x]->interspecies_violence) + 1;
					// 1-127   0-255
					//interspecies_violence = 1 means  1/256 chance of violence
					// = 2  1/127
					//1/1 chance of attacking if fight_flight 0  1/256 if 255,  1 / 1*(IM+1)
					//0 = never attack  255 = 255/256 attack chance
					if(life[src_y][src_x]->interspecies_violence > rand2){//attacking
						fought[src_y][src_x] = 1;
						out_come = Fight_Tribe( life[src_y][src_x], life[neighbors[n1].y][neighbors[n1].x] );
						if(out_come){//if the fight was won
							//free(life[neighbors[n1].y][neighbors[n1].x]);
							//life[neighbors[n1].y][neighbors[n1].x] = NULL;
							KILL_Tribe(neighbors[n1].y, neighbors[n1].x);
							stats[tid].died_defending++;
							//printf("tribe attacked and killed!\n");
							if(life[src_y][src_x]->imunity < 255)
								life[src_y][src_x]->imunity++;
							continue;
						}
						if(!out_come){ //died
							KILL_Tribe(src_y, src_x);
							//free(life[src_y][src_x]);
							//life[src_y][src_x] = NULL;
							stats[tid].died_attacking++;
							//printf("tribe killed attacking!\n");
							if(life[neighbors[n1].y][neighbors[n1].x]->imunity < 255)
								life[neighbors[n1].y][neighbors[n1].x]->imunity++;
							return;
						}
					}
				}
				if(mated[src_y][src_x])
					continue;
				if(mated[neighbors[n1].y][neighbors[n1].x])
					continue;

				//rand1 = lrand(&s) % (life[src_y][src_x]->social_factor) + 1;
				//gettimeofday(&cur, NULL);
				//srand ( (unsigned int)cur.tv_usec+rand2 );
				rand2 = lrand(&s) % 256; // 1/2 at 127
				rand1 = lrand(&s) % 256;
				//rand2 = lrand(&s) % (life[src_y][src_x]->social_factor+1) + 1;
				if(life[src_y][src_x]->social_factor > rand2 || life[src_y][src_x]->social_factor > rand1){ //are mating
					//if(mated[src_y][src_x]){
					//	continue;
					//}
					//if(mated[neighbors[n1].y][neighbors[n1].x]){
					//	continue;
					//}
					//mating = 1;
					out_come = 0;
					//choose open space for offspring
					for(n2=0; n2<4; n2++){
						if(neighbors[n2].occupied == 0){
							if(ia->cur_sealevel < ia->data[neighbors[n2].y][neighbors[n2].x] ){
								out_come = 1;
								break;
							}
						}
						//if(n2 == 3)
						//	out_come = 0;
					}
					//choose random open space if multiple

					//


					//if space available create life
					if(out_come){
							
							pthread_mutex_lock( &mutex1 );
							//updated
							if(!life_speed_up_H[neighbors[n2].y])
								life_speed_up_H[neighbors[n2].y] = 1;
							if(!life_speed_up_W[neighbors[n2].x])
								life_speed_up_W[neighbors[n2].x] = 1;
							pthread_mutex_unlock( &mutex1 );
							
							mated[src_y][src_x] = 1;
							mated[neighbors[n1].y][neighbors[n1].x] = 1;
							mated[neighbors[n2].y][neighbors[n2].x] = 1; //to keep it from mating/fighting during it's first year of life
							fought[neighbors[n2].y][neighbors[n2].x] = 1;
							life[neighbors[n2].y][neighbors[n2].x]->alive = 1;
							//life[neighbors[n2].y][neighbors[n2].x] = malloc( sizeof(struct Species) );
							Create_Life(life[src_y][src_x], life[neighbors[n1].y][neighbors[n1].x], life[neighbors[n2].y][neighbors[n2].x]);
							//printf("Created new life!\n");
							stats[tid].new_life++;
							if( !Is_Same_Species(life[src_y][src_x], life[neighbors[n2].y][neighbors[n2].x]) )
								stats[tid].new_species++;
							if(life[src_y][src_x]->imunity < 255)
								life[src_y][src_x]->imunity++;
							if(life[neighbors[n1].y][neighbors[n1].x]->imunity < 255)
								life[neighbors[n1].y][neighbors[n1].x]->imunity++;
					}
				}
			}else{ 
				if(!fought[src_y][src_x]){ //havn't already fought
					//fight_flight_balance see if we'll fight(attack)
					//rand1 = lrand(&s) % (life[src_y][src_x]->fight_flight_balance) + 1;
					//gettimeofday(&cur, NULL);
					//srand ( (unsigned int)cur.tv_usec+rand2 );
					rand2 = lrand(&s) % 2048;  // 1/16 at 127
					//rand2 = lrand(&s) % (life[src_y][src_x]->fight_flight_balance+1) + 1;
					if(life[src_y][src_x]->fight_flight_balance > rand2){//attacking
						fought[src_y][src_x] = 1;
						out_come = Fight_Tribe( life[src_y][src_x], life[neighbors[n1].y][neighbors[n1].x] );
						if(out_come){//fight was won
							//free(life[neighbors[n1].y][neighbors[n1].x]);
							//life[neighbors[n1].y][neighbors[n1].x] = NULL;
							KILL_Tribe(neighbors[n1].y, neighbors[n1].x);
							stats[tid].died_defending++;
							//printf("tribe attacked and killed!\n");
							if(life[src_y][src_x]->imunity < 255)
								life[src_y][src_x]->imunity++;
						}
						if(!out_come){ //died
							//free(life[src_y][src_x]);
							//life[src_y][src_x] = NULL;
							KILL_Tribe(src_y, src_x);
							stats[tid].died_attacking++;
							//printf("tribe killed attacking!\n");
							if(life[neighbors[n1].y][neighbors[n1].x]->imunity < 255)
								life[neighbors[n1].y][neighbors[n1].x]->imunity++;
							return;
						}
					}
				}
				//if(life[src_y][src_x]->fought){
				//	if(life[src_y][src_x]->mated){
				//		return;
				//	}
			}
		}
		if(fought[src_y][src_x]){
			if(mated[src_y][src_x]){
				return;
			}
		}
	}
}



void FM_Alloc(unsigned int height, unsigned int width){
	unsigned int h;
	fought = (char **)malloc(sizeof(char *)*height);
	for(h=0; h<height; h++)
		fought[h] = (char *)malloc(sizeof(char)*width);
	mated = (char **)malloc(sizeof(char *)*height);
	for(h=0; h<height; h++)
		mated[h] = (char *)malloc(sizeof(char)*width);
}

void FM_Reset(unsigned int height, unsigned int width){
	unsigned int h;
	//unsigned int w;
	//for(h=0; h<height; h++){
	//	for(w=0; w<width; w++){
	//		//if(life[h][w] != NULL){
	//		fought[h][w] = 0;
	//		mated[h][w] = 0;
			//}
	//	}
	//}
	for(h=0; h<height; h++){
		(void)memset( (void *)fought[h], '\0', sizeof(char)*width);
		(void)memset( (void *)mated[h], '\0', sizeof(char)*width);
	}

	//free(fought);
	//free(mated);
	//FM_Alloc(height, width);
}


void *Tribe_Actions(void *tid){
	//initiate actions migrate/combat/desease/create_life/migrate/socialize
	unsigned int t = *(unsigned int *)tid;
	//printf("In %u ", t);
	unsigned int y;
	unsigned int x;
	unsigned int x_s = 0;
	unsigned int x_h = 0;
	int right_to_left = 0;
	int dec = 0;
	int stop = 0;
	int first_member = 0;
	//unsigned int height = ia->height;
	unsigned int width = ia->width;
	unsigned int dest[] = {0, 0}; //y x
	char did_move = 0;
	struct timeval cur;
    int rand1;
	int rand2;
	int cur_sealevel = ia->cur_sealevel;
    gettimeofday(&cur, NULL);
    uint64_t s = (unsigned int)cur.tv_usec * 3 + 3;

	//gettimeofday(&cur, NULL);
	//srand ( (unsigned int)cur.tv_usec );

	//printf("T: %u ", t);
	//sleep(1);
	//struct Thread_I *thread_i;
//	printf("s%u e%u\n", thread_i[t].start_h, thread_i[t].end_h);
	//sleep(1);

	//randomly choose to start from right or left of column ?

	//	if( (lrand(&s) % 512) > (lrand(&s) % 512) ){
	//		x = 0;
	//	x_h = width - 1;

	



	for(y=thread_i[t].start_h; y < thread_i[t].end_h+1; y++){
		if(!life_speed_up_H[y])
			continue;

		//randomly choose to start from right or left of row
		rand1 = lrand(&s) % 512;
		rand2 = lrand(&s) % 511;

		if( rand1 > rand2 ){
			right_to_left = 0;
			x_s = width - 1;
		}else{
			right_to_left = 1;
			x_s = 0;
		}
		stop = 0;
		first_member = 1;
		//	x = 0; //first
		//	x_h = width - 1; //last
		//	dec = 1;
		//	x_s = 0;
		//	right_to_left = 0;
		//}else{
		//	x = width - 1; // first to take
		//	x_h = 0;  //last to take
		//	dec = -1; //inc
		//	x_s = width - 1;
		//	right_to_left = 1;
		//}
		//printf("here %d: x%u x_h%u\n", t, x, x_h);
		//x_s = 1;
		while(1){
			if(stop)
				break;
			if(right_to_left){
				if(!first_member)
					x--;
				else
					first_member = 0;
			}else{
				if(!first_member)
					x++;
				else
					first_member = 0;
			}
			if(x == x_s)
				stop = 1;
		//for(x_s = 1; x != x_h; x+=dec){
			if(!life_speed_up_W[x])
				continue;
			if(life[y][x]->alive){ //if there is life at this location
				//get one year older
				life[y][x]->cur_age++;
				//die from old age?  // 1/36 chance for initial tribes
				if(life[y][x]->cur_age == life[y][x]->max_age ){
					//free(life[y][x]);
					//life[y][x] = NULL;
					KILL_Tribe(y, x);
					stats[t].old_age++;
					//printf("tribe died from old age!\n");
					continue;
				}
				//die from disease:  1/1 chance of death if imunity 0  1/256 if 255,  1 / 1*(IM+1)
				//rand1 = lrand(&s) % (life[y][x]->imunity+1) + 1;
				//gettimeofday(&cur, NULL);
				//srand ( (unsigned int)cur.tv_usec+rand1 );
				rand2 = lrand(&s) % 2048; // 1/16 at 127   1/32 at 255
				if(life[y][x]->imunity > rand2){
					//free(life[y][x]);
					//life[y][x] = NULL;
					KILL_Tribe(y, x);
					stats[t].disease++;
					//printf("tribe died from disease!\n");
					continue;
				}
				//die from climate ?
				//if( Climate_Fatal(life[y][x], y, x) ){
				//	KILL_Tribe(y, x);
				//	stats[t].exposure++;
				//}
				//migrate: 0 = never move  255 = move everychance
				//rand1 = lrand(&s) % (life[y][x]->migration_factor+1) + 1;
				//gettimeofday(&cur, NULL);
				//srand ( (unsigned int)cur.tv_usec+rand1 );
				rand2 = lrand(&s) % 512;  // 1/4 at 127 
				if(life[y][x]->migration_factor > rand2){  //tribe will attempt to migrate
					did_move = Tribe_Migrate(y, x, dest);
					//migrating should increase imunity ?
				}else{
					//this tribe won't/can't migrate regardless 
					if(cur_sealevel >= ia->data[y][x]){ //drown
						//free(life[y][x]);
						//life[y][x] = NULL;
						KILL_Tribe(y, x);
						stats[t].drown++;
						//printf("tribe drown!\n");
						continue;
					}
					did_move = 0; //didn't move lived
				}
				//}else{
					//this tribe will move, if it can.
					//analyse surrounding terrain/life (4 coordinates) of potential movements (5 coordinates)
//pthread_mutex_lock( &mutex1 );
					//did_move = Tribe_Migrate(y, x, dest);
//pthread_mutex_unlock( &mutex1 );
				//}
				//reset mated/fought vars
				//Reset_F_M(height, width);
				//FM_Reset(height, width);
//pthread_mutex_lock( &mutex2 );

				if(did_move){
					if( Climate_Fatal(life[dest[0]][dest[1]], dest[0], dest[1]) ){
						//printf("dm - t: %f r: %d-%d\n", Location_Temp(dest[0], dest[1]), life[dest[0]][dest[1]]->temp_l, life[dest[0]][dest[1]]->temp_h );
						KILL_Tribe(y, x);
						stats[t].exposure++;
						continue;
					}

					Tribe_Interactions(dest[0], dest[1], t);
					//shouldn't have moved onto water
				}else{
					if( Climate_Fatal(life[y][x], y, x) ){
						//printf("nm - t: %f r: %d-%d\n", Location_Temp(y, x), life[y][x]->temp_l, life[y][x]->temp_h);
						KILL_Tribe(y, x);
						stats[t].exposure++;
						continue;
					}
					//if(cur_sealevel > ia->data[y][x]){
						//free(life[y][x]);
						//life[y][x] = NULL;
					//	KILL_Tribe(y, x);
					//	stats.drown++;
						//printf("tribe drown!\n");
					//	continue;
					//}
					Tribe_Interactions(y, x, t);

				}
//pthread_mutex_unlock( &mutex2 );
				//FM_Reset(height, width);
			}//end of if life != NULL
//printf("here 2\n");
		}//while(x+=dec && x != x_h);
	}
	//printf("T: %u \n", t);
	//FM_Reset(height, width);
	pthread_exit(NULL);
}



void Drawl_Image(void){
	unsigned int n1, n2;
	unsigned int height = ia->height;
	unsigned int width  = ia->width;
	int sealevel = ia->cur_sealevel;
	unsigned char rgb[3];

	for(n1=0; n1<height; n1++){
		for(n2=0; n2<width; n2++){
			if(ia->data[n1][n2] > sealevel){
				if(!life[n1][n2]->alive){
					rgb[0] = 0;
					rgb[1] = 255;
					rgb[2] = 0;
					//continue;
				}else{
					Gen_Tribe_Color(life[n1][n2], rgb);
				}
			}else{
				rgb[0] = 0;
				rgb[1] = 0;
				rgb[2] = 255;
			}
			ia->image[n1*width*3+(n2*3)]   = rgb[0];
			ia->image[n1*width*3+(n2*3+1)] = rgb[1];
			ia->image[n1*width*3+(n2*3+2)] = rgb[2];
		}
	}
}

/*
void *Drawl_Image_PT(void *tid){
	//write out ia->image from all data
	unsigned int t = *(unsigned int *)tid;
	unsigned int n1, n2;
	//unsigned int height = ia->height;
	unsigned int width  = ia->width;
	int sealevel = ia->cur_sealevel;
	unsigned char rgb[3];

	//drawl land/water first
	for(n1=thread_di_i[t].start_h; n1<thread_di_i[t].end_h; n1++){
		for(n2=0; n2<width; n2++){
			if(ia->data[n1][n2] > sealevel){
				rgb[0] = 0;
				rgb[1] = 255;
				rgb[2] = 0;
			}else{
				rgb[0] = 0;
				rgb[1] = 0;
				rgb[2] = 255;
			}
			ia->image[n1*width*3+(n2*3)]   = rgb[0];
			ia->image[n1*width*3+(n2*3+1)] = rgb[1];
			ia->image[n1*width*3+(n2*3+2)] = rgb[2];
		}
	}
	//drawl tribes
	for(n1=thread_di_i[t].start_h; n1<thread_di_i[t].end_h; n1++){
		//if(!life_speed_up_H[n1])
			//continue;
		for(n2=0; n2<width; n2++){
			//if(!life_speed_up_W[n2])
				//continue;
			if(life[n1][n2]->alive){
				//need color generator function instead
				//rgb[0] = life[n1][n2]->intelligence;
				//rgb[1] = life[n1][n2]->strength;
				//rgb[2] = life[n1][n2]->speed;
				Gen_Tribe_Color(life[n1][n2], rgb);
				ia->image[n1*width*3+(n2*3)]   = rgb[0];
				ia->image[n1*width*3+(n2*3+1)] = rgb[1];
				ia->image[n1*width*3+(n2*3+2)] = rgb[2];
			}
		}
	}
	pthread_exit(NULL);
}
*/