/*
    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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include "OpenGL.h"
#include "Globals.h"
#include "Life.h"
#include "DEM.h"

void Usage(void){
	printf("%s (%s %s) Usage:\n", LR_NAME, LR_VERSION, LR_DATE);
	printf("lrstats [-g]\n");
	printf("\t[optional]\n");
	printf("\t-g for graphics display, default no\n");
	printf("\t-h this help menu\n");
}

extern char *filename_dem;
extern unsigned char **Alive;

static void Gen_Tribe_Color(struct Species *one, unsigned char *rgb){
    rgb[0] = one->intelligence;
    rgb[1] = (unsigned char)( ((uint16_t)one->strength + one->speed)/2 );
    //they'll all fit, Don't break later
    rgb[2] = one->temp_l + one->temp_h + one->max_age;
}

static int Is_Same_Species(struct Species *one, struct Species *two){
    // "dna" determined by all variables, no one variable can deviate more than 4
    // y=mx+b   y range 0-255,  if x = x same species, b == subspecies deviation ?
    //must allow for subspecies deviation

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

    return 1;
}


int main(int argc, char **argv){
	uint32_t w=0, h=0;
	uint32_t n1=0, n2=0, n3=0;
	char enable_graphics = 0;
	if(argc > 1){
		for(n1=1; n1<argc; n1++){
			if( strcmp( (const char *)argv[n1], "-g") == 0){
				enable_graphics = 1;
			}
			if( strcmp( (const char *)argv[n1], "-h") == 0){
				Usage();
				return 0;
			}
		}
	}
	uint32_t species_c = 1;
	size_t size_of_species_t = 1000;
	uint32_t ten_most[10];
	unsigned char rgb[3] = {0, 0, 0};
	const unsigned char rgb2[10][3] = {
		{255, 0, 0}, //red
		{170, 170, 38}, //puke
		{255, 255, 0}, //yellow
		{255, 127, 0}, //orange
		{127, 36, 185}, //purple
        {0, 206, 209}, //turqois
		{0, 255, 255}, //light blue
		{165, 42, 42}, //brown
		{127, 127, 127}, //grey
		{255, 255, 255} //white
	};
	struct Species *ten_s = malloc(sizeof(struct Species)*10);
	struct Species *species_t = malloc(sizeof(struct Species) * size_of_species_t);
	uint32_t *species_totals = malloc(sizeof(uint32_t) * size_of_species_t);
	size_t total_read = 0;
	uint32_t total_population = 0;

	No_Exit = 1;
	FILE *fp = fopen("BACKUP.lr", "rb");
	if(!fp){
		printf("error opening file!\n");
		return 0;
	}

	if(enable_graphics){
    	filename_dem = (char *)malloc(strlen("myout.test") + 1);
    	strcpy(filename_dem, "myout.test");
    	if( (int)Load_Terrain() ){
        	printf("Load Terrain Error!\n");
        	exit(1);
    	}
    	printf("read DEM!\n");
	}

	Allocate_Life_Array();
    Alive = (unsigned char **)malloc(sizeof(unsigned char *)*HEIGHT);
    for(h=0; h<HEIGHT; h++){
        Alive[h] = (unsigned char *)malloc(sizeof(unsigned char)*(size_t)ceil(WIDTH/8));
        (void)memset( (void *)Alive[h], '\0', sizeof(unsigned char)*(size_t)ceil(WIDTH/8) );
    }
    total_read += fread((void *)&stats_t, 1, sizeof(struct Stats_T), fp);
    for(h=0; h<HEIGHT; h++){
        total_read += fread((void *)Alive[h], 1, sizeof(unsigned char)*ceil(WIDTH/8), fp);
    }
    for(h=0; h<HEIGHT; h++){
        for(w=0; w<WIDTH; w++){
            total_read += fread((void *)life[h][w], 1, sizeof(struct Species), fp);
        }
    }
	printf("Total_read(bytes):%zu\n", total_read);
	species_totals[0] = 9;

	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			if(IS_SET(Alive, h, w) ){
				(void)memcpy((void *)&species_t[0], (const void *)life[h][w], sizeof(struct Species) );
				species_totals[0] = 0;
				break;
			}
		}
		if(species_totals[0] == 0)
			break;
	}
	for(h=0; h<HEIGHT; h++){
		for(w=0; w<WIDTH; w++){
			if(IS_SET(Alive, h, w) ){
				total_population++;
				for(n1=0; n1<species_c; n1++){
					if( Is_Same_Species(&species_t[n1], life[h][w]) ){
						species_totals[n1]++;
						goto Next_Tribe;
					}
				}
				species_c++;
				if(species_c > size_of_species_t){
					size_of_species_t += 500;
					species_t = (struct Species *)realloc(species_t, sizeof(struct Species) * size_of_species_t);
					species_totals = (uint32_t *)realloc(species_totals, sizeof(uint32_t) * size_of_species_t);
					//set all new species_totals = 0;
					for(n3=species_c; n3<size_of_species_t; n3++){
						(void)memset((void *)&species_t[n3], '\0', sizeof(struct Species) );
						species_totals[n3] = 0;
					}
				}
				species_totals[species_c-1] = 1;
				(void)memcpy((void *)&species_t[species_c-1], (const void *)life[h][w], sizeof(struct Species) );
			}
			Next_Tribe:
			;
		}
	}
	for(n1=0; n1<10; n1++)
		ten_most[n1] = 0;

	printf("%u total population\n", total_population);
	printf("%u unique species alive\n", species_c);
	uint32_t last_highest = 0;
	last_highest--;
	uint32_t highest = 0;

	for(n2=0; n2<10; n2++){
		for(n1=0; n1<species_c; n1++){
			if(species_totals[n1] < last_highest){
				if(species_totals[n1] > highest){
					highest = species_totals[n1];
					ten_most[n2] = highest;
					(void)memcpy((void *)&ten_s[n2], (const void *)&species_t[n1], sizeof(struct Species) );
				}
			}
		}
		last_highest = highest;
		highest = 0;
	}

	//sums up to 1658880000 maximum value
	float social_factor = 0;
	float migration_factor = 0;
	float fight_flight_balance = 0;
	float interspecies_violence = 0;
	float imunity = 0;
	float avg_age = 0;
	float intel_avg[10];
	(void)memset(intel_avg, '\0', sizeof(float)*10);

	n2 = species_c < 10 ? species_c : 10;

	printf("%u most populous:\n", n2);
	printf("black color for all others\n");

	printf("Species_Traits(0 to +3)\n\tSub_Species_Traits(avgs)\n\n");
	printf("num:\t%%Pop_t\tPop\trgb(stats)/(sim)\tintel\tstren\tspeed\ttemp_l\ttemp_h\tmax_age\n");
	printf("\tavg_intel\tsocial_factor\tmigration_f\tfight/flight\tinterspecies_violence\timunity\t\tavg_age\n");

	for(n1=0; n1<n2; n1++){
		Gen_Tribe_Color(&ten_s[n1], rgb);
		printf("%u:\t%.03lf%%\t%u\t%u,%u,%u/%u,%u,%u\t", n1+1, ( (double)ten_most[n1]/(double)total_population )*100, ten_most[n1], rgb2[n1][0], rgb2[n1][1], rgb2[n1][2], rgb[0], rgb[1], rgb[2]);
		ten_s[n1].intelligence = floor(ten_s[n1].intelligence/4)*4;
		ten_s[n1].strength = floor(ten_s[n1].strength/4)*4;
		ten_s[n1].speed = floor(ten_s[n1].speed/4)*4;
		ten_s[n1].temp_l = floor(ten_s[n1].temp_l/4)*4;
		ten_s[n1].temp_h = floor(ten_s[n1].temp_h/4)*4;
		ten_s[n1].max_age = floor(ten_s[n1].max_age/4)*4;
		printf("%u\t%u\t%u\t%u\t%u\t%u\n",ten_s[n1].intelligence, ten_s[n1].strength,
				ten_s[n1].speed, ten_s[n1].temp_l, ten_s[n1].temp_h, ten_s[n1].max_age);
		for(h=0; h<HEIGHT; h++){
			for(w=0; w<WIDTH; w++){
				if(IS_SET(Alive, h, w) ){
					if( Is_Same_Species(&ten_s[n1], life[h][w]) ){
						intel_avg[n1] += life[h][w]->intelligence;
						social_factor += life[h][w]->social_factor;
						migration_factor += life[h][w]->migration_factor;
						fight_flight_balance += life[h][w]->fight_flight_balance;
						interspecies_violence += life[h][w]->interspecies_violence;
						imunity += life[h][w]->imunity;
						avg_age += life[h][w]->cur_age;
					}
				}
			}
		}
		intel_avg[n1] /= ten_most[n1];
		social_factor /= ten_most[n1];
		migration_factor /= ten_most[n1];
		fight_flight_balance /= ten_most[n1];
		interspecies_violence /= ten_most[n1];
		imunity /= ten_most[n1];
		avg_age /= ten_most[n1];
		//printf("\tavg_intel\tsocial_factor\tmigration_f\tfight/flight\tinterspecies_violence\timunity\tavg_age\n");
		printf("\t%.02f\t\t%.02f\t\t%.02f\t\t%.02f\t\t%.02f\t\t\t%.02f\t\t%.02f\n",
			intel_avg[n1], social_factor, migration_factor, fight_flight_balance, interspecies_violence, imunity, avg_age);

		social_factor = 0;
		migration_factor = 0;
		fight_flight_balance = 0;
		interspecies_violence = 0;
		imunity = 0;
		avg_age = 0;
	}

	//remove all species from map that aren't in the top 10, and add better coloring
	if(enable_graphics){
		for(h=0; h<HEIGHT; h++){
			for(w=0; w<WIDTH; w++){
				if(ia->dem[h][w] > stats_t.cur_sealevel){
					if( !IS_SET(Alive, h, w) ){
						rgb[0] = 0;
						rgb[1] = 255;
						rgb[2] = 0;
					}else{
						for(n1=0; n1<n2; n1++){
							if( Is_Same_Species(&ten_s[n1], life[h][w]) ){
								rgb[0] = rgb2[n1][0];
								rgb[1] = rgb2[n1][1];
								rgb[2] = rgb2[n1][2];
								break;
							}
							rgb[0] = 0;
							rgb[1] = 0;
							rgb[2] = 0;
						}
					}
				}else{
					rgb[0] = 0;
					rgb[1] = 0;
					rgb[2] = 255;
				}
				ia->image[h*WIDTH*3+(w*3)]   = rgb[0];
				ia->image[h*WIDTH*3+(w*3+1)] = rgb[1];
				ia->image[h*WIDTH*3+(w*3+2)] = rgb[2];
			}
		}
		glutInit(&argc,argv);
		Run_GL();
		free(ia->image);
	}

	for(h=0; h<HEIGHT; h++){
		free(Alive[h]);
		for(w=0; w<WIDTH; w++){
			free(life[h][w]);
		}
		free(life[h]);
	}
	free(Alive);
	free(life);
	free(ten_s);
	free(species_t);
	free(species_totals);
	fclose(fp);

	return 0;
}