#include "DEM.h"

struct Thread_I *thread_i;
struct Thread_I *thread_di_i;
//pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int Image_Locked;

static void Adjust_Sea_Level(void){
	//unsigned int height = ia->height;
	//unsigned int width  = ia->width;
	//unsigned int count1, count2;
	//unsigned char rgb[3];
	static int sea_level_chng = 100;
	static int is_rising = 0;
	//if(change){
		if(is_rising){
			if(sea_level_chng == 100){
				is_rising = 0;
			}else{
				sea_level_chng++;
			}
		}else{
			if(sea_level_chng == -100){
				is_rising = 1;
			}else{
				sea_level_chng--;
			}
		}
	//}
	ia->cur_sealevel = sea_level_chng;

		/*
		for(count1=0; count1<height; count1++){
			for(count2=0; count2<width; count2++){
				if(ia->data[count1][count2]<sea_level_chng){
					rgb[0] = 0;
					rgb[1] = 0;
					rgb[2] = 255;
				}else{
					rgb[0] = 0;
					rgb[1] = 255;
					rgb[2] = 0;
				}
				ia->image[count1*width*3+(count2*3)] = rgb[0];
				ia->image[count1*width*3+(count2*3+1)] = rgb[1];
				ia->image[count1*width*3+(count2*3+2)] = rgb[2];
			}
		}
		//sleep(1);
	//}
	*/
	//return sea_level_chng;
}

int Load_Terrain(char *filename){
	FILE *fp = fopen(filename, "rb");
	if(!fp){
		printf("Error opening file: %s\n", filename);
		return 1;
	}
printf("here 1\n");
	//NROWS         6000
	//NCOLS         4800
	//unsigned int height = 41600;
	//unsigned int width = 43200;
	const int start_sealevel = 100;
	unsigned int height = 1800; //40
	unsigned int width  = 3600; //27

	ia = malloc(sizeof(struct image_attr));
	ia->image = malloc(sizeof(unsigned char)*height*width*3);
    ia->width = width;
    ia->height = height;
	ia->cur_sealevel = start_sealevel;

	//printf("here 2\n");
	//ia->data = (int16_t **)malloc(sizeof(int16_t *)*height);

	//double temp[27][40];
	//unsigned int temp_x = 0;
	//unsigned int temp_y = 0;

	char two_b[2];
	//u_int16_t
	union{ char a[2]; int16_t b;}x;
	unsigned int count1, count2;
	//int result = 0;
	unsigned char rgb[3];
	//unsigned int data_pnt_x = 0;
	//unsigned int data_pnt_y = 0;
	//unsigned int data_sum = 0;

	ia->data = (int16_t **)malloc(sizeof(int16_t *)*height);
	for(count1=0; count1<height; count1++){
		ia->data[count1] = (int16_t *)malloc(sizeof(int16_t)*width);
	}
	for(count1=0; count1<height; count1++){
		//if(temp_y == 39)
		//	temp_y = 0;
		//for(temp_y=0; temp_y<40; temp_y++;
		/*
		temp_y++;
		if(temp_y!=40){
			for(count2=0; count2<src_width; count2++){
				fread(&two_b, 1, 2, fp);
			}
		}
		if(temp_y==40){
			temp_y = 0;
		*/
			for(count2=0; count2<width; count2++){

				fread(&two_b, 1, 2, fp);
				x.a[0] = two_b[0];
				x.a[1] = two_b[1];
				ia->data[count1][count2] = x.b;
				//temp_x++;
				//if(temp_x==27){
				//	temp_x=0;

					//data_sum += x.b;
					//data_pnt++;
					//if(x.b > 0){
					//	result = 
					//if(count1 < 20 && count2 < 20)
					//	printf("%d\n", x.b);
					//if(x.b != 12)
					//	printf("hmm\b");
					//1 -9999 5825 -2347.6 4873.5
					//the band number, minimum value, maximum value, mean value, and standard deviation of the values in the raster

					//if(data_pnt == src_width){
					//	x.b = ceil(data_sum/src_width);
					//	data_pnt = 0;
//						if(x.b < -9999)
//							printf("low !\n");
//						if(x.b > 5825)
//							printf("high !\n");

/*						if(x.b<-5000){
							rgb[0] = 0;
							rgb[1] = 0;
							rgb[2] = 0; //ceil(255-(x.b/-13000)*255);
						}else if(x.b<-2500){
							rgb[0] = 0;
							rgb[1] = 0; //ceil(255-(x.b/-2500)*255);
							rgb[2] = 255;
						}else if(x.b<-1000){
							rgb[0] = 0;
							rgb[1] = 0;
							rgb[2] = 128; //ceil(255-(x.b/-1000)*255);
						}else if(x.b<-500){
							rgb[0] = 0; //ceil((x.b/-500)*255);
							rgb[1] = 128;
							rgb[2] = 128;

						}else*/ if(x.b < start_sealevel){
							rgb[0] = 0;
							rgb[1] = 0; //ceil(255-(x.b/-50)*255);
							rgb[2] = 255;
						}else{
							rgb[0] = 0;
							rgb[1] = 255;
							rgb[2] = 0;
						}
/*						
						black -13000
						blue -4000
						turquise 0
						green 3000
						yellow 6000
						red 9000
						-13000
						-6000
						0
						4000
						9000
						*/
						ia->image[count1*width*3+(count2*3)] = rgb[0];
						ia->image[count1*width*3+(count2*3+1)] = rgb[1];
						ia->image[count1*width*3+(count2*3+2)] = rgb[2];
					
			
			
		}
	}

	

	fclose(fp);
	return 0;
}


void World_Thread(void){
	uint64_t year = 1;
	uint64_t turn_death_total;
	double turn_life_total;
	size_t height = ia->height;
	size_t width = ia->width;
	struct timeval starttime,endtime;
	//struct timeval teststart,testend;
	double time1 = 0;
	unsigned char rgb[3];
	//int cur_sealevel = 0;
	const int w = 2200;
	const int h = 900;
	unsigned int n1 = 0;
	unsigned int n2 = 0;
	unsigned int n3 = 0;
	unsigned int Tcount = 0;
	unsigned int regions = Threads*2; //evens and odds
	unsigned int thread_step = 0;
	pthread_t *threads_p = (pthread_t *)malloc(sizeof(pthread_t) * Threads*2+1);
	unsigned int *t_ids = (unsigned int *)malloc(sizeof(unsigned int) * regions+1);
	pthread_t *threads_di_p = (pthread_t *)malloc(sizeof(pthread_t) * Threads);
	unsigned int *t_di_ids = (unsigned int *)malloc(sizeof(unsigned int) * Threads);

	//if(thread_step % regions != 0){
	thread_step = floor(height/regions);
	//}
	printf("Threads: %u thread_step: %u regions: %u\n", Threads, thread_step, regions);

	//thread_step 
	// height/3 / Threads*2 : must have all threads active in center of dataset to be efficient early (needs to be sufficiently small)
	//thread_step must be whole number
	//
	thread_di_i = (struct Thread_I *)malloc( sizeof(struct Thread_I)*Threads);
	for(n1=0; n1<Threads; n1++){
		thread_di_i[n1].start_h = n2;
		thread_di_i[n1].end_h   = (n1+1 != Threads) ? (n1+1)*floor(height/Threads) : height;
		t_di_ids[n1] = n1;
		n2 += floor(height/Threads);
	}
	n2 = 0;
	thread_i = (struct Thread_I *)malloc( sizeof(struct Thread_I)*regions);
	for(n1=0; n1<regions; n1++){
		thread_i[n1].start_h = n2;
		thread_i[n1].end_h   = (n1+1 != regions) ? (n1+1)*thread_step - 1: height - 1;
		n2 += thread_step;
		printf("start_h: %u end_h: %u\n", thread_i[n1].start_h, thread_i[n1].end_h);
		t_ids[n1] = n1;
	}

	//initialize empty life array
	Allocate_Life_Array(height, width);
	printf("Allocated Life array\n");
	//"plant" first primate tribe [somewhere in africa :)]
	//H 1000 W 2500

	for(n1=w-5; n1<w+5; n1++){
		for(n2=h-5; n2<h+5; n2++){
			//need to check terrain for water
			if(ia->data[n2][n1] > ia->cur_sealevel){
				life[n2][n1] = (struct Species *)malloc( sizeof(struct Species) );
				Add_First_Life( life[n2][n1] );
				//if(n1==-5)
				Gen_Tribe_Color(life[n2][n1], rgb);
				ia->image[width*n2*3 + n1*3]     = rgb[0];
				ia->image[width*n2*3 + n1*3 + 1] = rgb[1];
				ia->image[width*n2*3 + n1*3 + 2] = rgb[2];
				n3++;
				life_speed_up_H[n2] = 1;
				life_speed_up_W[n1] = 1;
			}
		}
	}
	printf("Added %d initial tribes!\n", n3);

	FM_Alloc(height, width);
	FM_Reset(height, width);


	//launch OpenGL thread
	Image_Locked = 0;
        if (pthread_create(&threads_p[regions], NULL, Run_GL, &t_ids[regions]) != 0){
            printf("Error: pthread_create failed for thread: opengl !\n");
            exit(1);
        }

	sleep(1);

	gettimeofday(&starttime, NULL);
	while(1){
		//start calculating years
		//raise sea level if right multiple (going by 1m per 1000yrs) based on data from past 140yrs for now ...
		//drawls terrain/land into image
		if(year%1000 == 0){ // 1000yrs = 1meter
			Adjust_Sea_Level();
		}

	//gettimeofday(&teststart, NULL);
	//printf("here 4\n");
	//launch odd steps
	for(Tcount = 0; Tcount < regions; Tcount+=2){
		if (pthread_create(&threads_p[Tcount], NULL, Tribe_Actions, &t_ids[Tcount]) != 0){
			printf("Error: pthread_create failed for thread: %d !\n", Tcount);
			exit(1);
		}
	}
	for(Tcount=0; Tcount < regions; Tcount+=2){
		if (pthread_join(threads_p[Tcount], NULL) != 0){
			printf("Error: pthread_join failed for thread: %d !\n", Tcount);
			exit(1);
		}
	}

	//launch even steps
	for(Tcount = 1; Tcount < regions; Tcount+=2){
		if (pthread_create(&threads_p[Tcount], NULL, Tribe_Actions, &t_ids[Tcount]) != 0){
			printf("Error: pthread_create failed for thread: %d !\n", Tcount);
			exit(1);
		}
	}
	for(Tcount=0; Tcount < regions; Tcount+=2){
		if (pthread_join(threads_p[Tcount], NULL) != 0){
			printf("Error: pthread_join failed for thread: %d !\n", Tcount);
			exit(1);
		}
	}
//printf("here 5\n");
	FM_Reset(height, width);
//printf("here 6\n");
		//gettimeofday(&teststart, NULL);
		//Tribe_Actions(ia);
		//gettimeofday(&testend, NULL);
		//time1 = ((double)(testend.tv_sec*1000000-teststart.tv_sec*1000000+testend.tv_usec-teststart.tv_usec))/1000000;
		//printf("Tribe Actions: %lf\n", time1);

		// ^^ initiate actions combat/desease/create_life/migrate/socialize

		//gettimeofday(&teststart, NULL);
		//parse life array and drawl tribes into image



	//gettimeofday(&teststart, NULL);
		//Drawl_Image();

	if(year % 5 == 0){
		Image_Locked = 1;
		for(Tcount = 0; Tcount < Threads; Tcount++){
			if(pthread_create(&threads_di_p[Tcount], NULL, Drawl_Image, &t_di_ids[Tcount]) != 0){
				printf("Error: pthread_create failed for thread: %d (Drawl_Image) !\n", Tcount);
				exit(1);
			}
		}
		for(Tcount=0; Tcount < Threads; Tcount++){
			if(pthread_join(threads_di_p[Tcount], NULL) != 0){
				printf("Error: pthread_join failed for thread: %d (Drawl_Image) !\n", Tcount);
				exit(1);
			}
		}
		Image_Locked = 0;
	}
	//gettimeofday(&testend, NULL);
	//time1 = ((double)(testend.tv_sec*1000000-teststart.tv_sec*1000000+testend.tv_usec-teststart.tv_usec))/1000000;
	//printf("Drawl_Image: %lf\n", time1);





		//printf("drew image\n");
		//gettimeofday(&testend, NULL);
		//printf("Drawl_Image(: %lf\n", time1);


		//gettimeofday(&teststart, NULL);
		//increment year
		year++;
		//print seconds/year every 10yrs 
		if(year%1000 == 0){
			gettimeofday(&endtime, NULL);
			time1 = ((double)(endtime.tv_sec*1000000-starttime.tv_sec*1000000+endtime.tv_usec-starttime.tv_usec))/1000000;
			printf("\nYear: %lu Sec/Year: %lf\n", year, time1/1000);
			printf("sealevel: %u\n", ia->cur_sealevel);
			gettimeofday(&starttime, NULL);
			//process stats
			printf("deaths\n");
			printf("disease: %u drown: %u old_age: %u died_attacking: %u died_defending: %u\n",  stats.disease, stats.drown, stats.old_age, stats.died_attacking, stats.died_defending);
			turn_death_total = stats.disease + stats.drown + stats.old_age + stats.died_attacking + stats.died_defending;
			printf("\tsubtotal: %lu\n", turn_death_total);
			printf("life\n");
			printf("new_life: %u new_species: %u\n", stats.new_life, stats.new_species);
			turn_life_total = stats.new_life - turn_death_total;
			printf("\tnet subtotal: %.00lf\n", turn_life_total);

			printf("Totals:\n");
			stats.t_disease += stats.disease;
			stats.t_drown += stats.drown;
			stats.t_old_age += stats.old_age;
			stats.t_died_attacking += stats.died_attacking;
			stats.t_died_defending += stats.died_defending;
			stats.t_new_life += stats.new_life;
			stats.t_new_species += stats.new_species;
			//t_species_extinct;
			printf("\tdisease: %lu\n", stats.t_disease);
			printf("\tdrown: %lu\n", stats.t_drown);
			printf("\told_age: %lu\n", stats.t_old_age);
			printf("\tdied_attacking: %lu\n", stats.t_died_attacking);
			printf("\tdied_defending: %lu\n", stats.t_died_defending);
			printf("\tnew_life: %lu\n", stats.t_new_life);
			printf("\tnew_species: %lu\n", stats.t_new_species);

			stats.disease = 0;
			stats.drown = 0;
			stats.old_age = 0;
			stats.died_attacking = 0;
			stats.died_defending = 0;
			stats.new_life = 0;
			stats.new_species = 0;

		}
	}
	//if(year == 5)
	//	exit(1);
}