#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

#define POINTS 15

float clocks[POINTS] = {2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3.0, 3.1, 3.2, 3.3, 3.4};
float volts[POINTS] = {0.975, 1.0, 1.0, 1.05, 1.075, 1.1, 1.125, 1.15, 1.175, 1.20, 1.25, 1.30, 1.375, 1.40, 1.45};
float watts[POINTS] = {57, 60, 60, 65, 68, 72, 75, 78, 82, 85, 92, 102, 117, 127, 139};
double mem[POINTS] = {14548.878339, 14629.324888, 14745.623395, 14645.957649, 14683.957625, 14456.247082, 14731.107902, 14459.412829, 14622.037190, 14757.781995, 14605.772540, 
14600.250611, 14637.173208, 14656.446130, 14623.221351};
double gflops[POINTS] = {31.876831, 33.485756, 35.085455, 36.691478, 38.259850, 39.870095, 41.459898, 43.045371, 44.632822, 46.228606, 
47.829982, 49.436488, 51.001210, 52.649156, 54.221639};
double pattern[POINTS] = {1064.941097, 1118.545341, 1168.850432, 1223.952547, 1271.680896, 1324.620590, 1378.946602, 1432.341524, 
1479.941475, 1536.416845, 1586.177046, 1639.257994, 1692.645593, 1744.360335, 1794.568899};
double sim[POINTS] = {0.153801, 0.147140, 0.143981, 0.138006, 0.130507, 0.127306, 0.125000, 0.119022, 0.114609, 0.113887, 
0.111085, 0.107928, 0.103426, 0.102573, 0.100293};

/*
clock     set_v     load_v   peak_w     benchmarks
2.0       0.975v    0.98v    57W
2.1       1.0v      1.025v   60W
2.2       1.0v      1.025v   60W
2.3       1.05v     1.075v   65W
2.4       1.075v    1.1v     68W
2.5       1.1v      1.125v   72W
2.6       1.125v    1.16v    75W
2.7       1.15v     1.18v    78W
2.8       1.175v    1.20v    82W
2.9       1.20v     1.20v    85W
3.0       1.25v     1.27v    92W
3.1       1.30v     1.32v    102W
3.2       1.375v    1.40v    117W
3.3       1.40v     1.45v    127W
3.4       1.45v     1.49v
*/



/*
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 = 950;
	int height = 950;
//	int box_h = 10;
	double step;
	float x1, y1, x2, y2;
	int num1 = 1;
	int num2 = 0;
	int num3 = 0;
	double biggest, smallest;

//	int size_max = 64;
//	size_t cycle_max = 500;
	float tmp1 = 0;

	int stagger = 0;
//	int readprev = 0;
//	int readcur = 0;
//	int step_h = 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];

	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);
	gdImageLine(im, width-100, 100, width-100, height-100, black);

        gdImageString(im, gdFontMediumBold, 5, 5, (unsigned char *)"gflops", blue);
	gdImageString(im, gdFontMediumBold, 5, 15, (unsigned char *)"memory", green);
	gdImageString(im, gdFontMediumBold, 5, 25, (unsigned char *)"pattern", orange);
	gdImageString(im, gdFontMediumBold, 5, 35, (unsigned char *)"sim", brown);

	gdImageString(im, gdFontMediumBold, width/2, height-25, (unsigned char *)"clock", black);
	gdImageString(im, gdFontMediumBold, width-80, 5, (unsigned char *)"watts", red);

	//horizontal labels
	num2 = (width-200)/POINTS;
	num3 = 0;
	for(num1=0; num1<POINTS; num1++){
		(void)sprintf(labelstr, "%.03fGHz", clocks[num1]);
		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++;
	}

/*
	//left vertical labels for voltage
	num2 = 0;
	num3 = (height - 200)/22;
	tmp1 = volts[0];
	for(num1=0; num1<22; num1++){
		(void)sprintf(labelstr, "%.03fV", tmp1);
		gdImageString(im, gdFontSmall, 50, height-100-num3*num2, (unsigned char *)labelstr, green);
		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++;
		tmp1 += 0.025;
	}
*/



	//right vertical labels for watts
	num2 = 0;
	num3 = (height - 200)/22;
biggest = 0;
smallest = 100000000;
for(num1=0; num1<POINTS; num1++){
if(watts[num1] > biggest)
biggest = watts[num1];
if(watts[num1] < smallest)
smallest = watts[num1];
}
step = biggest - smallest;
step /= 22;
	tmp1 = smallest;
	for(num1=0; num1<22; num1++){
		(void)sprintf(labelstr, "%.03fW", tmp1);
		gdImageString(im, gdFontSmall, width-80, height-100-num3*num2, (unsigned char *)labelstr, red);
		gdImageLine(im, width-80, height-100-num3*num2, width-100, height-100-num3*num2, black);
		//gdImageLine(im, 100, height-100-num3*num2, width-100, height-100-num3*num2, gdStyled);
		num2++;
		tmp1 += step;
	}
/*
	//draw voltage line
	num2 = (width-200)/POINTS;
	num3 = (height - 200)/22;
	x1 = 100;
	y1 = height-100;
	for(num1=1; num1<POINTS; num1++){
		tmp1 = volts[num1] - volts[0];
		tmp1 /= 0.025;
		y2 = height-100;
		y2 -= tmp1*num3;
		x2 = x1+num2;
		gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, green);
		x1 = x2;
		y1 = y2;
	}

*/
	//draw gflops
num2 = (width-200)/POINTS;
num3 = (height - 200)/22;
x1 = 100;
y1 = height-100;

biggest = 0;
smallest = 100000000;
for(num1=0; num1<POINTS; num1++){
if(gflops[num1] > biggest)
biggest = gflops[num1];
if(gflops[num1] < smallest)
smallest = gflops[num1];
}
step = biggest - smallest;
//step = gflops[POINTS-1] - gflops[0];
step /= 22;

for(num1=1; num1<POINTS; num1++){
tmp1 = gflops[num1] - smallest;
tmp1 /= (float)step;
y2 = height-100;
y2 -= tmp1*num3;
x2 = x1+num2;
gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, blue);
x1 = x2;
y1 = y2;
}


        //draw mem
num2 = (width-200)/POINTS;
num3 = (height - 200)/22;
x1 = 100;
y1 = height-100;

biggest = 0;
smallest = 100000000;
for(num1=0; num1<POINTS; num1++){
if(mem[num1] > biggest)
biggest = mem[num1];
if(mem[num1] < smallest)
smallest = mem[num1];
}
step = biggest - smallest;

//step = mem[POINTS-1] - mem[0];
step /= 22;

for(num1=1; num1<POINTS; num1++){
tmp1 = mem[num1] - smallest;
tmp1 /= (float)step;
y2 = height-100;
y2 -= tmp1*num3;
x2 = x1+num2;
gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, green);
x1 = x2;
y1 = y2;
}


        //draw pattern
num2 = (width-200)/POINTS;
num3 = (height - 200)/22;
x1 = 100;
y1 = height-100;
biggest = 0;
smallest = 100000000;
for(num1=0; num1<POINTS; num1++){
if(pattern[num1] > biggest)
biggest = pattern[num1];
if(pattern[num1] < smallest)
smallest = pattern[num1];
}
step = biggest - smallest;
//step = pattern[POINTS-1] - pattern[0];
step /= 22;

for(num1=1; num1<POINTS; num1++){
tmp1 = pattern[num1] - smallest;
tmp1 /= (float)step;
y2 = height-100;
y2 -= tmp1*num3;
x2 = x1+num2;
gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, orange);
x1 = x2;
y1 = y2;
}

        //draw sim
num2 = (width-200)/POINTS;
num3 = (height - 200)/22;
x1 = 100;
y1 = height-100;
biggest = 0;
smallest = 100000000;
for(num1=0; num1<POINTS; num1++){
if(sim[num1] > biggest)
biggest = sim[num1];
if(sim[num1] < smallest)
smallest = sim[num1];
}
step = biggest - smallest;
//step = sim[POINTS-1] - sim[0];
step /= 22;

for(num1=1; num1<POINTS; num1++){
tmp1 = biggest - sim[num1];
tmp1 /= (float)step;
y2 = height-100;
y2 -= tmp1*num3;
x2 = x1+num2;
gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, brown);
x1 = x2;
y1 = y2;
}



	//draw wattage line
	num2 = (width-200)/POINTS;
	num3 = (height - 200)/22;
	x1 = 100;
	y1 = height-100;
biggest = 0;
smallest = 100000000;
for(num1=0; num1<POINTS; num1++){
if(watts[num1] > biggest)
biggest = watts[num1];
if(watts[num1] < smallest)
smallest = watts[num1];
}
step = biggest - smallest;
step /= 22;
	for(num1=1; num1<POINTS; num1++){
		tmp1 = watts[num1] - smallest;
		tmp1 /= (float)step;
		y2 = height-100;
		y2 -= tmp1*num3;
		x2 = x1+num2;
		gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, red);
		x1 = x2;
		y1 = y2;
	}




//	gdImageLine(im, (int)x1, (int)y1, (int)x2, (int)y2, colors[num1]);

	out = fopen("perfwatt.png", "w");
	gdImageInterlace(im, 1);
	gdImagePng(im, out);
	fclose(out);
	gdImageDestroy(im);
//	free(read_buffer);

	return 0;
}
