#include <stdio.h>
#include <stdlib.h>
#include <gd.h>
#include "gdfonts.h"
#include "gdfontmb.h"
#include <math.h>
#include "dates.h"

void usage(void){
	printf("\n");
	printf("balance <input_file> <output_file> <starting_balance> [pixels per day] [pixel spacing per day]\n");
	printf("\tmust provide input_file, output_file, and starting_balance\n");
	printf("\tpixels per day and pixel spacing default to 1 if not specified\n");
	printf("\n");
}

int main(int argc, char **argv){



	gdImagePtr im;
	FILE *out;
	int width               = 0;
	int height              = 0;
	int pixels_per_day      = 1;
	int pixels_whitespace   = 1;
	double starting_balance = 0;
	struct Transactions *transactions;
	char buf[1024];
	char current_transaction[25];
	char *input_file;
	char *output_file;


	if(argc < 4){
		printf("Error: Too few arguments!\n");
		usage();
		exit( 1 );
	}
	//grab input_file
	input_file = malloc(strlen(argv[1])+1);
	strcpy(input_file, argv[1]);
	printf("input_file: %s\n", input_file);

	//grab output_file
	output_file = malloc(strlen(argv[2])+1);
	strcpy(output_file, argv[2]);
	printf("output_file: %s\n", output_file);

	//grab starting_balance
	strcpy(current_transaction, argv[3]);
	starting_balance = atof((const char *)current_transaction);
	printf("starting_balance: %lf\n", starting_balance);

	if(argc > 4){
		//grab pixels_per_day
		strcpy(current_transaction, argv[4]);
		pixels_per_day = atoi((const char *)current_transaction);
		printf("pixels_per_day: %d\n", pixels_per_day);
	}
	if(argc == 6){
		//grab pixels_whitespace
		strcpy(current_transaction, argv[5]);
		pixels_whitespace = atoi((const char *)current_transaction);
		printf("pixels_whitespace: %d\n", pixels_whitespace);
	}

	//return 0;

/*
    int white = gdImageColorAllocate(im, 255, 255, 255);
	int black = gdImageColorAllocate(im, 0,   0,   0);
	int red   = gdImageColorAllocate(im, 255, 0,   0);
	int blue  = gdImageColorAllocate(im, 0,   0,   255);
	int green = gdImageColorAllocate(im, 0,   255, 0);
*/

	FILE *in;
	int line_num                    = 0;
	unsigned int total_days         = 0;
	unsigned int total_transactions = 0;
	unsigned int money_count        = 0;
	double max_balance              = 0;
	double min_balance              = 1000000000;
	//char buf[1024];
	char tmp_y[5];
	char tmp_m[5];
	char tmp_d[5];
	struct Date date_start;
	struct Date date_end;
	struct Date date_tmp;
	//double starting_balance = 22209.89;
	//double starting_balance = 282.39;
	double current_balance  = 0;
	//char current_transaction[25];
	unsigned int t_count = 0;
	unsigned int between_days;
	unsigned int bd_count;
	int no_match = 1;

	//open statement, get start/end dates
	if( ( in = fopen( input_file, "r" ) ) == NULL ) {
		fprintf( stderr, "Error opening input file: %s !\n", input_file );
		exit( 1 );
	}
	while( fgets(buf, sizeof(buf), in) != NULL){
		if(buf[0] == '"'){
			//"09/29/2010"
			tmp_m[0] = buf[1];
			tmp_m[1] = buf[2];
			tmp_m[2] = '\0';
			//date_end.month = atoi(tmp_m);
			tmp_d[0] = buf[4];
			tmp_d[1] = buf[5];
			tmp_d[2] = '\0';
			//date_end.day = atoi(tmp_d);
			tmp_y[0] = buf[7];
			tmp_y[1] = buf[8];
			tmp_y[2] = buf[9];
			tmp_y[3] = buf[10];
			tmp_y[4] = '\0';
			//date_end.year = atoi(tmp_y);
			if(line_num == 0){
				//you've got the end date, parse it
				date_end.month = atoi((const char*)tmp_m);
				date_end.day = atoi((const char*)tmp_d);
				date_end.year = atoi((const char*)tmp_y);
			}
			line_num++;
		}
	}
	fclose( in );
	//done reading file, last contents of tmp's will be start date
	date_start.month = atoi((const char*)tmp_m);
	date_start.day = atoi((const char*)tmp_d);
	date_start.year = atoi((const char*)tmp_y);

	total_transactions = line_num;

	printf("Read %u lines from statement (transactions)\n", total_transactions);
	printf("start - d: %u m: %u y: %u\n", date_start.day, date_start.month, date_start.year);
	printf("end - d: %u m: %u y: %u\n", date_end.day, date_end.month, date_end.year);

	//call dates function to get needed image/structure size
	total_days = Total_Days(&date_start, &date_end) + 1;
	
	printf("%u total days covered in statement\n", total_days);

	//allocate
	transactions = malloc( sizeof(struct Transactions) * total_days);

	//initialize
	memcpy(&date_tmp, &date_start, sizeof(struct Date) );
	for(t_count=0; t_count<total_days; t_count++){
		transactions[t_count].date.day   = date_tmp.day;
		transactions[t_count].date.month = date_tmp.month;
		transactions[t_count].date.year  = date_tmp.year;
		transactions[t_count].balance    = 0;
		transactions[t_count].change     = 0;
		//printf("%d: %d/%d/%d\n", t_count, transactions[t_count].date.month, transactions[t_count].date.day, transactions[t_count].date.year);
		//printf("%d: %lf %lf\n", t_count, transactions[t_count].change, transactions[t_count].balance );
		Increment_Date(&date_tmp, 1);
	}

	//open file again and populate transactions structure
	if( ( in = fopen( input_file, "r" ) ) == NULL ) {
		fprintf( stderr, "Error opening input file: %s !\n", input_file );
		exit( 1 );
	}

	t_count = 0;
	line_num = total_days-1;
	while( fgets(buf, sizeof(buf), in) != NULL){
		if(buf[0] == '"'){
			tmp_m[0] = buf[1];
            tmp_m[1] = buf[2];
            tmp_m[2] = '\0';
            //date_end.month = atoi(tmp_m);
            tmp_d[0] = buf[4];
            tmp_d[1] = buf[5];
            tmp_d[2] = '\0';
            //date_end.day = atoi(tmp_d);
            tmp_y[0] = buf[7];
            tmp_y[1] = buf[8];
            tmp_y[2] = buf[9];
            tmp_y[3] = buf[10];
            tmp_y[4] = '\0';

			date_tmp.day = atoi((const char*)tmp_d);
			date_tmp.month = atoi((const char*)tmp_m);
			date_tmp.year = atoi((const char*)tmp_y);

			for(money_count = 14; buf[money_count] != '"'; money_count++){
				current_transaction[money_count-14] = buf[money_count];
			}
			current_transaction[money_count-14] = '\0';

			no_match = 1;
			for(t_count=0; t_count<total_days; t_count++){
				//if(memcmp(&date_tmp, &transactions[t_count].date, sizeof(struct Date)) == 0){
				if(date_tmp.day == transactions[t_count].date.day){
					if(date_tmp.month == transactions[t_count].date.month){
						if(date_tmp.year == transactions[t_count].date.year){
							transactions[t_count].change += atof((const char*)current_transaction);
							//printf("chg: %d %d/%d/%d %lf\n", t_count, date_tmp.month, date_tmp.day, date_tmp.year, transactions[t_count].change );
							no_match = 0;
							break;
						}
					}
				}
			}
			if(no_match){
				printf("Error: date out of range!\n");
				//printf("line_num: %u\n", t_count);
				//printf("buf: %s\n", buf);
				//exit( 1 );
			}
			//transactions[line_num].change = atof((const char*)current_transaction);
			
		}
			//if( 0 == memcmp(&date_tmp, &transactions[line_num].date, sizeof(struct Date)) ){
			//	transactions[line_num].change = atof((const char*)current_transaction);
			//}

			/*
			//not the first line ie: something with an entry more recent available
			if(line_num != total_days-1){
				between_days = Total_Days(&date_tmp, &transactions[line_num+1].date);
			}else{
				between_days = 1;
			}
			for(bd_count=0; bd_count<between_days; bd_count++){
				//transactions are ordered backwards in file!, recent first
				//transactions[line_num].date.day = atoi(date_tmp.day);
				//transactions[line_num].date.month = atoi(date_tmp.month);
				//transactions[line_num].date.year = atoi(date_tmp.year);

				if(bd_count == between_days-1){
					//"09/29/2010","-19.11"
					for(t_count = 14; buf[t_count] != '"'; t_count++){
						current_transaction[t_count-14] = buf[t_count];
					}
					current_transaction[t_count-14] = '\0';
					//printf("trans: %s\n", current_transaction);
					transactions[line_num].change = atof((const char*)current_transaction);
					//printf("trans: %lf\n", transactions[line_num].change);
					transactions[line_num].date.day = date_tmp.day;
					transactions[line_num].date.month = date_tmp.month;
					transactions[line_num].date.year = date_tmp.year;
					//line_num--;
				}else{
					transactions[line_num].change = 0;
					transactions[line_num].date.day = date_tmp.day;
					transactions[line_num].date.month = date_tmp.month;
					transactions[line_num].date.year = date_tmp.year;
					Decrement_Date(&date_tmp, 1);
            		//line_num--;
				}
				line_num--;
			}
        }
		*/
    }
    fclose( in );

	transactions[0].balance = starting_balance;
	current_balance = starting_balance;
	//determin max_balance
	for(t_count = 1; t_count < total_days; t_count++){
		current_balance += transactions[t_count].change;
		transactions[t_count].balance = current_balance;
		//printf("chng: %lf bal: %lf\n", transactions[t_count].change, current_balance);
		if(current_balance > max_balance)
			max_balance = current_balance;
		if(current_balance < min_balance)
			min_balance = current_balance;
	}
	printf("max_balance: %lf\n", max_balance);
	printf("min_balance: %lf\n", min_balance);
	//create image
	width = total_days * (pixels_per_day+pixels_whitespace) + 200;

	//height = ceil(max_balance) + 60;
	height = 1200;
	im = gdImageCreate(width,height);

    int white = gdImageColorAllocate(im, 255, 255, 255);
    int black = gdImageColorAllocate(im, 0,   0,   0);
    int red   = gdImageColorAllocate(im, 255, 0,   0);
    int blue  = gdImageColorAllocate(im, 0,   0,   255);
    int green = gdImageColorAllocate(im, 0,   255, 0);
	int styleDashed[9];
	styleDashed[0] = blue;
	styleDashed[1] = blue;
	styleDashed[2] = blue;
	styleDashed[3] = green;
	styleDashed[4] = green;
	styleDashed[5] = green;
	styleDashed[6] = red;
	styleDashed[7] = red;
	styleDashed[8] = red;
	gdImageSetStyle(im, styleDashed, 9);
	char chart_label_a[12];

	double balance_tenth = ceil(max_balance) / 10;
	double height_tenth = (height-200)/10;

	int emptyvarstr;
	int downnum = height-100;

	//draw chart boundaries/labels on image
	gdImageLine(im, 100, 10, 100, height-100, black);
	gdImageLine(im, 100, height-100, width-100, height-100, black);
	gdImageString(im, gdFontMediumBold,   width-85   ,   height-85        , "Days" , black);
	gdImageString(im, gdFontMediumBold,   0   ,   10        , "Balance" , black);
	current_balance = 0;
	for(line_num=0; line_num<11; line_num++){
		gdImageLine(im, 50, downnum, width-85, downnum, gdStyled);
		emptyvarstr = sprintf(chart_label_a, "$%.02lf", current_balance);
		gdImageString(im, gdFontMediumBold, 5, downnum, chart_label_a , black);
		downnum -= height_tenth;
		current_balance += balance_tenth;
	}


	//plot data from transactions/days on image
	unsigned int day_count;
	unsigned int days_cur_month;
	unsigned int start_pixel_month;
	unsigned int end_pixel_month;
	unsigned int start_pixel_year;
	unsigned int end_pixel_year;
	int x1, y1, x2, y2;
	unsigned int days_from_start;
	//date_start
	char months[] = "JFMAMJJASOND";
	char tmp_char[2];
	//char *months[]={"J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"};
	unsigned int last_year = 0;
	unsigned int last_month = 0;
	unsigned int last_m_X = 100;

	y1 = height - 100;
	for(day_count=0; day_count<total_days; day_count++){
		date_tmp.day    = transactions[day_count].date.day;

		date_tmp.month  = transactions[day_count].date.month;

		date_tmp.year   = transactions[day_count].date.year;
		days_from_start = Total_Days(&date_start, &date_tmp);
		x1 = 100 + days_from_start * (pixels_per_day+pixels_whitespace);
		x2 = x1 - pixels_per_day;
		y2 = y1 - (height-200)*transactions[day_count].balance/max_balance;

		gdImageFilledRectangle(im, x1, y1, x2, y2, green);
		if(last_month != date_tmp.month){
			gdImageLine(im, x1, y1, x1, height-75, red);
			last_month = date_tmp.month;
			tmp_char[0] = months[last_month-1];
			tmp_char[1] = '\0';
			gdImageString(im, gdFontMediumBold,   x1,   height-75, tmp_char, red);
		}
		if(last_year != date_tmp.year){
			gdImageLine(im, x1, height-75, x1, height-50, blue);
			last_year = date_tmp.year;
			emptyvarstr = sprintf(chart_label_a, "%d", last_year);
			gdImageString(im, gdFontMediumBold,   x1,   height-50, chart_label_a, blue);
		}
	}

/*

	days_cur_month = Days_In_Month(&date_start) - date_start.date.day;
	for(day_count=0; day_count<days_cur_month; day_count++){

		//allocate labels on chart for each month/year

		//plot each day on chart


	for(day_count=0; day_count<total_days; day_count++){
		days

	}
*/

	//write out image
	out = fopen(output_file, "w");
	gdImageInterlace(im, 1);
	gdImagePng(im, out);
	fclose(out); 
	gdImageDestroy(im);
	free(input_file);
	free(output_file);
	free(transactions);

	return 0;
}