#include <stdio.h>
#include <stdlib.h>
#include <gd.h>
#include "gdfonts.h"
#include "gdfontt.h"
#include "gdfontl.h"
#include "gdfontl.h"
#include "gdfontmb.h"
#include <math.h>
#include <stdint.h>
#include <string.h>

#define ALGS 8
#define MAX_SIZE 32768


void Label_Suffix(char *labelstr, size_t num){
                if(num<1024){
                        (void)sprintf(labelstr, "%zu", num);
                }else if(num<1000000){
                        (void)sprintf(labelstr, "%zuK", num/1000);
                }else if(num<1000000000){
                        (void)sprintf(labelstr, "%zuM", num/1000000);
                }else{
                        (void)sprintf(labelstr, "%zuB", num/1000000000);
                }
}

int main(int argc, char **argv){
	gdImagePtr im;
	FILE *in;
	FILE *out;
	int width = 800;
	int height = 700;
	int box_h = 10;
	double x1, y1, x2, y2;
	int num1 = 1;
	int num2 = 0;
	int num3 = 0;

	int size_max = 64;
	//int size_step = 1;

	size_t cycle_max = 500;
	//double cycle_step = 25;
	double tmp1 = 0;

	int stagger = 0;
	int readprev = 0;
	int readcur = 0;
	int step_h = 0;
	//int step_v = 0;
	uint32_t read_buffer_size = 256;
	char *read_buffer = (char *)malloc(read_buffer_size + 1);
	(void)memset( (void *)read_buffer, '\0', read_buffer_size + 1);
	size_t data[ALGS][MAX_SIZE];

	//im = gdImageCreate(width, height);

	//byte_loop loop unrolled_loop rep_byte rep_4byte rep_8byte vector_loop libcall
	//int colors[8];

	int white, black, red, blue, green, yellow, orange, purple, brown, grey;
	int colors[8];
	int styleDashed[8];
	char labelstr[32];

        //read all data in up front
        for(num1=0; num1<ALGS; num1++){
#ifdef IS32BIT
		if(num1 == 5)
			continue;
#endif
                (void)sprintf(labelstr, "results/r%d.txt", num1+1);
                in = fopen(labelstr, "r");
                num2 = 0;
                (void)memset( (void *)read_buffer, '\0', read_buffer_size + 1);

                while( fgets(read_buffer, read_buffer_size, in) != NULL){
                        if(num2 == MAX_SIZE)
                                break;
                        data[num1][num2] = atoi(read_buffer);
			//printf("read %zu line %d\n", data[num1][num2], num2);
                        num2++;
                }
                fclose(in);
        }
	//printf("here 1\n");

	for(size_max = 0; size_max < MAX_SIZE; size_max+=64){


		im = gdImageCreate(width, height);

		white = gdImageColorAllocate(im, 255, 255, 255);
		black = gdImageColorAllocate(im, 0, 0, 0);
		red = gdImageColorAllocate(im, 255, 0, 0);
		blue = gdImageColorAllocate(im, 0, 0, 255);
		green = gdImageColorAllocate(im, 0, 255, 0);
		yellow = gdImageColorAllocate(im, 255, 255, 0);
		orange = gdImageColorAllocate(im, 255, 128, 0);
		purple = gdImageColorAllocate(im, 255, 0, 255);
		brown = gdImageColorAllocate(im, 128, 64, 0);
		grey = gdImageColorAllocate(im, 128, 128, 128);

		colors[0] = red;
		colors[1] = blue;
		colors[2] = green;
		colors[3] = yellow;
		colors[4] = orange;
		colors[5] = purple;
		colors[6] = brown;
		colors[7] = grey;

		styleDashed[0] = gdTransparent;
		styleDashed[1] = black;
		styleDashed[2] = gdTransparent;
		styleDashed[3] = black;
		styleDashed[4] = gdTransparent;
		styleDashed[5] = black;
		styleDashed[6] = gdTransparent;
		styleDashed[7] = black;

	        gdImageSetStyle(im, styleDashed, 8);

	        gdImageLine(im, 100, 100, 100, height-100, black);
	        gdImageLine(im, 100, height-100, width-100, height-100, black);
	        gdImageString(im, gdFontMediumBold, 5, 5, (unsigned char *)"cycles", black);
		gdImageString(im, gdFontMediumBold, width/2, height-25, (unsigned char *)"size", black);

		gdImageString(im, gdFontMediumBold, width-80, box_h, (unsigned char *)"byte_loop", black);
		gdImageFilledRectangle(im, width-100, box_h, width-90, box_h*2, red);
		gdImageString(im, gdFontMediumBold, width-80, box_h*3, (unsigned char *)"loop", black);
		gdImageFilledRectangle(im, width-100, box_h*3, width-90, box_h*4, blue);
		gdImageString(im, gdFontSmall, width-80, box_h*5, (unsigned char *)"unrolled_loop", black);
		gdImageFilledRectangle(im, width-100, box_h*5, width-90, box_h*6, green);
		gdImageString(im, gdFontMediumBold, width-80, box_h*7, (unsigned char *)"rep_byte", black);
		gdImageFilledRectangle(im, width-100, box_h*7, width-90, box_h*8, yellow);
		gdImageString(im, gdFontMediumBold, width-80, box_h*9, (unsigned char *)"rep_4byte", black);
		gdImageFilledRectangle(im, width-100, box_h*9, width-90, box_h*10, orange);
#ifndef IS32BIT
		gdImageString(im, gdFontMediumBold, width-80, box_h*11, (unsigned char *)"rep_8byte", black);
		gdImageFilledRectangle(im, width-100, box_h*11, width-90, box_h*12, purple);
#endif
		gdImageString(im, gdFontMediumBold, width-80, box_h*13, (unsigned char *)"vector_loop", black);
		gdImageFilledRectangle(im, width-100, box_h*13, width-90, box_h*14, brown);
		gdImageString(im, gdFontMediumBold, width-80, box_h*15, (unsigned char *)"libcall", black);
		gdImageFilledRectangle(im, width-100, box_h*15, width-90, box_h*16, grey);

		//horizontal labels
		num2 = (width-200)/64;
		num3 = 0;
		for(num1=size_max; num1<size_max+64; num1++){
			Label_Suffix(labelstr, num1+1);
			gdImageString(im, gdFontSmall, num2*(num3)+100, height-75+stagger, (unsigned char *)labelstr, black);
			gdImageLine(im, num2*(num3)+100, height-75+stagger, num2*(num3)+100, height-100, black);
			gdImageLine(im, num2*(num3)+100, height-100, num2*(num3)+100, 100, gdStyled);
			if(stagger == 25)
				stagger = 0;
			else
				stagger = 25;
			num3++;
		}

		//calculate cycle_max in cycles
		cycle_max = 0;
		//cycle_step = 0;
		for(num1=0; num1<8; num1++){
			for(num2=size_max; num2<size_max+64; num2++){
				if(data[num1][num2] > cycle_max)
					cycle_max = data[num1][num2];
			}
		}
		//cycle_step in pixels/cycle
		tmp1 = (height - 200);
		//cycle_step = tmp1/cycle_max/10;

		//vertical labels
		num2 = 0;
		num3 = (height - 200)/10;
		for(num1=cycle_max/10; num1<cycle_max; num1+=cycle_max/10){
			Label_Suffix(labelstr, num1);
			gdImageString(im, gdFontSmall, 50, height-100-num3*num2, (unsigned char *)labelstr, black);
			gdImageLine(im, 50, height-100-num3*num2, 100, height-100-num3*num2, black);
			gdImageLine(im, 100, height-100-num3*num2, width-100, height-100-num3*num2, gdStyled);
			num2++;
		}

		//plot data for 8 algs
		step_h = (int)ceil((width-200)/64);
		//step_v = (int)ceil((height-200)/10);
		for(num1=0; num1<ALGS; num1++){
#ifdef IS32BIT
			if(num1 == 5)
				continue;
#endif
			readprev = data[num1][size_max];
			num3 = 0;
			
			for(num2=size_max+1; num2<size_max+64; num2++){
				readcur = data[num1][num2];

				tmp1 = (double)num3*step_h;
				x1 = ceil(tmp1+100);

				//tmp1 = cycle_step*readprev;
				tmp1 = (double)readprev/cycle_max*(height-200);
				y1 = ceil(height-100-tmp1);

				tmp1 = (double)(num3+1)*step_h;
				x2 = ceil(tmp1+100);

				tmp1 = (double)readcur/cycle_max*(height-200);
				//tmp1 = cycle_step*readcur;
				y2 = ceil(height-100-tmp1);

				//gdImageLine(im, num3*step_h+100, height-100-readprev, (num3)*step_h+100, height-100-readcur, colors[num1-1]);
				gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, colors[num1]);

				readprev = readcur;
				num3++;
			}
		}

		if(size_max<10){
			(void)sprintf(labelstr, "graphs/graph-0000%d.png", size_max);
		}else if(size_max<100){
			(void)sprintf(labelstr, "graphs/graph-000%d.png", size_max);
		}else if(size_max<1000){
			(void)sprintf(labelstr, "graphs/graph-00%d.png", size_max);
		}else if(size_max<10000){
			(void)sprintf(labelstr, "graphs/graph-0%d.png", size_max);
		}else{
			(void)sprintf(labelstr, "graphs/graph-%d.png", size_max);
		}
		out = fopen(labelstr, "w");
		gdImageInterlace(im, 1);
		gdImagePng(im, out);
		fclose(out);
		gdImageDestroy(im);

	}


	free(read_buffer);

	return 0;
}
