/*
    Living Realms is a primate evolution simulator.
    Copyright (C) 2011  Sterling Pickens

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "DEM.h"

void Adjust_Sea_Level(int load){
	static int sea_level_chng = 86;
	static int is_rising = 0;
	// 1m per 1K years
	if(load){
		sea_level_chng = stats_t.cur_sealevel;
		is_rising = stats_t.sea_rising;
		return;
	}
	if(is_rising){
		if(sea_level_chng == 86){
			is_rising = 0;
		}else{
			sea_level_chng++;
		}
	}else{
		if(sea_level_chng == -130){
			is_rising = 1;
		}else{
			sea_level_chng--;
		}
	}
	stats_t.cur_sealevel = sea_level_chng;
	stats_t.sea_rising = is_rising;
}

void Adjust_Climate(int load){
    static float temp_chng = 32; //starting at high temp
    static int is_rising = 0;
	//every 10K years you'll get a 2c temp change

    if(load){
        temp_chng = stats_t.cur_temp;
        is_rising = stats_t.temp_rising;
        return;
    }
	if(is_rising){
        if(temp_chng > 32){
             is_rising = 0;
         }else{
            temp_chng+=0.2;
         }
	}else{
       if(temp_chng < 28){
           is_rising = 1;
       }else{
           temp_chng-=0.2;
       }
	}
    stats_t.cur_temp = temp_chng;
    stats_t.temp_rising = is_rising;
}

int Load_Terrain(void){
	FILE *fp = fopen(filename_dem, "rb");
	if(!fp){
		printf("Error opening file: %s\n", filename_dem);
		return 1;
	}
	const int start_sealevel = 100;

	ia = malloc(sizeof(struct image_attr));
	ia->image = malloc(sizeof(unsigned char)*HEIGHT*WIDTH*3);
	stats_t.cur_sealevel = start_sealevel;
	stats_t.sea_rising = 0;
	stats_t.cur_temp = 32;
	stats_t.temp_rising = 0;

	char two_b[2];
	union{ char a[2]; int16_t b;}x;
	unsigned int count1, count2;
	unsigned char rgb[3];
	size_t total_read = 0;

	ia->dem = (int16_t **)malloc(sizeof(int16_t *)*HEIGHT);
	for(count1=0; count1<HEIGHT; count1++){
		ia->dem[count1] = (int16_t *)malloc(sizeof(int16_t)*WIDTH);
	}
	for(count1=0; count1<HEIGHT; count1++){
		for(count2=0; count2<WIDTH; count2++){
			total_read += fread(&two_b, 1, 2, fp);
			x.a[0] = two_b[0];
			x.a[1] = two_b[1];
			ia->dem[count1][count2] = x.b;
			if(x.b < start_sealevel){
				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];
		}
	}
	fclose(fp);
	if(total_read != 2*HEIGHT*WIDTH){
		printf("Error: fread sum does for '%s' not match with compile-time DEM dimensions!\n", filename_dem);
		printf("\tread %zu expected %u\n", total_read, 2*HEIGHT*WIDTH);
		for(count1=0; count1<HEIGHT; count1++){
			free(ia->dem[count1]);
		}
		free(ia->dem);
		free(ia->image);
		free(ia);
		return 1;
	}
	printf("Loaded DEM from '%s'\n", filename_dem);
	printf("\tread %zu bytes\n", total_read);

	return 0;
}

void Gen_Detailed_Counts(void){
	//printf 10 most numerous species info
	//and update stats_t
	uint32_t h;
	uint32_t chng = 0;
	for(h=0; h<Threads; h++){
            stats_t.disease += stats[h].disease;
            stats_t.drown += stats[h].drown;
			stats_t.exposure += stats[h].exposure;
            stats_t.old_age += stats[h].old_age;
            stats_t.died_attacking += stats[h].died_attacking;
            stats_t.died_defending += stats[h].died_defending;
            stats_t.new_life += stats[h].new_life;
            stats_t.new_species += stats[h].new_species;
	}
	stats_t.total_runtime += Backup_Freq_Runtime;
	printf("Year: %u\n", stats_t.year);
	if(stats_t.sea_rising){
		printf("Current: Sec/Year %.04lfs cur_sealevel %dm rising +1m/1Kyears", Backup_Freq_Runtime/1000, stats_t.cur_sealevel);
	}else{
		printf("Current: Sec/Year %.04lfs cur_sealevel %dm falling -1m/1Kyears", Backup_Freq_Runtime/1000, stats_t.cur_sealevel);
	}
	printf(" equatorial mean temp: %.02fc changing: %.02fc/1Kyears\n", stats_t.cur_temp, (stats_t.temp_rising ? 0.2 : -0.2) );
	printf("Total: Runtime %.02lf hrs Avg Sec/Year %lfs\n\n", (double)stats_t.total_runtime/3600, (double)stats_t.total_runtime/stats_t.year);

	for(h=0; h<Threads; h++){
		chng += stats[h].disease;
	}
	printf("\tdisease: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.disease, chng);

	chng=stats[0].drown;
	for(h=1; h<Threads; h++){
		chng += stats[h].drown;
	}
	printf("\tdrown: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.drown, chng);

    chng=stats[0].exposure;
	for(h=1; h<Threads; h++){
		chng += stats[h].exposure;
	}
	printf("\texposure: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.exposure, chng);

	chng=stats[0].old_age;
	for(h=1; h<Threads; h++){
		chng += stats[h].old_age;
	}
	printf("\told_age: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.old_age, chng);

	chng=stats[0].died_attacking;
	for(h=1; h<Threads; h++){
		chng += stats[h].died_attacking;
	}
	printf("\tdied_attacking: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.died_attacking, chng);

	chng=stats[0].died_defending;
	for(h=1; h<Threads; h++){
		chng += stats[h].died_defending;
	}
	printf("\tdied_defending: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.died_defending, chng);

	chng=stats[0].new_life;
	for(h=1; h<Threads; h++){
		chng += stats[h].new_life;
	}
	printf("\tnew_life: %"PRIu64"\n\t\tchng: %"PRIu32"\n", stats_t.new_life, chng);

	chng=stats[0].new_species;
	for(h=1; h<Threads; h++){
		chng += stats[h].new_species;
	}
	printf("\tnew_species: %"PRIu64"\n\t\tchng: %"PRIu32"\n\n", stats_t.new_species, chng);
	Backup_Freq_Runtime = 0;
	Year_Runtime = 0;
}

int Save_Current_State(void){
	FILE *fp = fopen(filename_backup_save, "wb");
    if(!fp){
        printf("Error opening file: %s\n", filename_backup_save);
        return 1;
    }
	uint32_t w = 0, h = 0;
	size_t bytes = 0;
	uint64_t total_living = 0;
	for(h=0; h<HEIGHT; h++){
		if(!life_speed_up_Y[h])
			continue;
		for(w=0; w<WIDTH; w++){
			if(!life_speed_up_X[w])
				continue;
			if( IS_SET(Alive, h, w) )
				total_living++;
		}
	}
	stats_t.total_living = total_living;
	bytes += fwrite((const void *)&stats_t, 1, sizeof(struct Stats_T), fp);
	for(h=0; h<HEIGHT; h++){
		bytes += fwrite((const void *)Alive[h], 1, sizeof(unsigned char)*(WIDTH>>3), fp);
	}
	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			bytes += fwrite((const void *)life[h][w], 1, sizeof(struct Species), fp);
		}
	}

	printf("Saved current state to '%s'!\n", filename_backup_save);
	printf("\tbytes wrote: %zu\n", bytes);
	printf("\tTotal_Population: %lu\n\n", total_living);
	fclose(fp);

	return 0;
}

int Load_State(void){
    FILE *fp = fopen(filename_backup_load, "rb");
    if(!fp){
        printf("Error opening file: %s\n", filename_backup_load);
        return 1;
    }
	uint32_t w = 0, h = 0;
	size_t bytes = 0;

	bytes += fread((void *)&stats_t, 1, sizeof(struct Stats_T), fp);
	//(void)fseek ( fp , 4, SEEK_CUR );
	for(h=0; h<HEIGHT; h++){
		bytes += fread((void *)Alive[h], 1, sizeof(unsigned char)*(WIDTH>>3), fp);
	}
	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			bytes += fread((void *)life[h][w], 1, sizeof(struct Species), fp);
		}
	}
	printf("Loaded state from '%s'\n", filename_backup_load);
	printf("\tbytes read: %zu\n", bytes);
	bytes = 0;
	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			if(IS_SET(Alive, h, w))
				bytes++;
		}
	}
	printf("\ttotal population: %zu\n", bytes);
	fclose(fp);

	return 0;
}