
#include <stdio.h>
#include <stdlib.h>

#include <vector>
#include <string>
#include <fstream>
#include <utility>
using namespace std;

int width=500;
int height=400;
string y_label="";

double y_range_bottom=0.0;
double y_range_step=0.1;
double y_range_top=1.0;

int bar_gap=5;
int plot_margin_top = 30;
int plot_margin_right = 30;

int plot_margin_left = 70;
int plot_margin_bottom = 50;

string font_family = "Verdana";
int font_size = 10;

int label_rotation = 0;

char *colors[] = {
	"purple","orange","green",
	"red","blue","magenta","#007F7F","black"
};
int color_count = 8;

vector< pair<string,double> > data;

void create_graph( string filename ) {
	FILE* f = fopen( filename.c_str(), "w" );
	if ( !f ) {
		fprintf( stderr, "unable to open %s for writing\n", filename.c_str() );
		exit(-1);
	}

	int bar_width = (int)(((width-(plot_margin_left+plot_margin_right))-bar_gap)/
	                      (data.size()))-bar_gap;

	// write the header
	fprintf( f, "<?xml version=\"1.0\" standalone=\"no\"?>\n" );
	fprintf( f, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"" );
	fprintf( f, " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" );
	fprintf( f, "<svg width=\"%dpx\" height=\"%dpx\"", width, height );
	fprintf( f, " xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n" );

	// draw the background
	fprintf( f, "  <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"", 0, 0, width, height );
	fprintf( f, " fill=\"none\" stroke=\"none\" stroke-width=\"0\" />\n" );

	// draw the left hash-marks
	for ( double current=y_range_bottom; current<=y_range_top; current+=y_range_step ) {
		int h = (int)(((height-(plot_margin_top+plot_margin_bottom))*current)/
		              (y_range_top-y_range_bottom));
		fprintf(
			f, "  <text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\"",
			plot_margin_left-2,
			(height-plot_margin_bottom)-h,
			font_family.c_str(),
			font_size
		);
		fprintf( f, " text-anchor=\"right\" fill=\"black\">\n" );
		fprintf( f, "%lg\n", current );
		fprintf( f, "  </text>\n" );

		fprintf(
			f, "  <line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" />\n",
			plot_margin_left-2,
			(height-plot_margin_bottom)-h,
			width-plot_margin_right,
			(height-plot_margin_bottom)-h
		);
	}

	// draw the bars
	int current_color = 0;
	for ( int i=0; i<data.size(); i++ ) {
		fprintf( f, "<!-- %s -->\n", data[i].first.c_str() );
		int x = i*(bar_width+bar_gap)+bar_gap+plot_margin_left;
		int y = plot_margin_bottom;
		int w = bar_width;
		int h = (int)(((height-(plot_margin_top+plot_margin_bottom))*data[i].second)/
		              (y_range_top-y_range_bottom));
		y = (height-y)-h;
		fprintf( f, "  <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"", x, y, w, h );

		char *color = colors[ current_color % color_count ];
		current_color++;
		if ( data[i].first == "" ) {
			current_color = 0;
//		} else {
//			if ( data[i].second == 0 ) {
//				current_color--;
//			}
		}
		fprintf( f, " fill=\"%s\" stroke=\"none\" stroke-width=\"0\" />\n", color );

		if ( label_rotation == 0 ) {
			fprintf(
				f, "  <text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\"",
				x+(bar_width/2),
				(height-plot_margin_bottom)+20,
				font_family.c_str(),
				font_size
			);
			fprintf( f, " text-anchor=\"middle\" fill=\"black\">\n" );
		} else {
			fprintf(
				f, "  <text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\"",
				x+(bar_width),
				(height-plot_margin_bottom)+10,
				font_family.c_str(),
				font_size
			);
			fprintf( f, " text-anchor=\"right\" fill=\"black\" rotate=\"%d\">\n", 360-label_rotation );
		}
		fprintf( f, "%s\n", data[i].first.c_str() );
		fprintf( f, "  </text>\n" );
	}

	// draw the border around the plot area
	fprintf(
		f, "  <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"",
		plot_margin_left,
		plot_margin_top,
		width-(plot_margin_left+plot_margin_right),
		height-(plot_margin_top+plot_margin_bottom)
	);
	fprintf( f, " fill=\"none\" stroke=\"black\" stroke-width=\"1\" />\n" );

	// draw the y-label
	fprintf(
		f, "  <text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\"",
		plot_margin_left-40,
		(height-plot_margin_bottom)-(height-(plot_margin_top+plot_margin_bottom))/2,
		font_family.c_str(),
		font_size+4
	);
	fprintf( f, " text-anchor=\"middle\" fill=\"black\" rotate=\"270\">\n" );
	fprintf( f, "%s\n", y_label.c_str() );
	fprintf( f, "  </text>\n" );

	// write the footer
	fprintf( f, "</svg>\n" );
	fclose(f);
}

void usage() {
	fprintf(stderr,"usage: foobar [options] <y label> <input file> <output file>\n");
	fprintf(stderr,"options:\n");
	fprintf(stderr,"    --rotate-labels\n");
	fprintf(stderr,"    --width <width>\n");
	fprintf(stderr,"    --height <width>\n");
	exit(-1);
}

int main(int argc, char** argv) {
	string filename = "";
	string output = "";
	for ( int i=1; i<argc; i++ ) {
		if (strcmp(argv[i],"--rotate-labels")==0) {
			label_rotation = 45;
			//plot_margin_bottom = 180;
		} else if (strcmp(argv[i],"--plot-margin-bottom")==0) {
			if (i==argc-1) {
				usage();
			} else {
				plot_margin_bottom = atoi(argv[++i]);
			}
		} else if (strcmp(argv[i],"--width")==0) {
			if (i==argc-1) {
				usage();
			} else {
				width = atoi(argv[++i]);
			}
		} else if (strcmp(argv[i],"--height")==0) {
			if (i==argc-1) {
				usage();
			} else {
				height = atoi(argv[++i]);
			}
		} else if (y_label == "") {
			y_label = argv[i];
		} else if (filename == "") {
			filename = argv[i];
		} else if (output == "") {
			output = argv[i];
		} else {
			usage();
		}
	}
	if ( output == "" ) {
		usage();
	}

	ifstream in(filename.c_str());
	if ( !in.good() ) {
		fprintf(stderr, "unable to open %s\n", filename.c_str());
		return -1;
	}

	int line_number = 0;
	string line = "";
	getline(in,line);
	while (in.good()) {
		line_number++;
		char* label = new char[line.length()+1];
		strcpy(label,line.c_str());

		char* space_delim = strrchr(label,' ');
		char* tab_delim = strchr(label,'\t');
		char* svalue = (space_delim > tab_delim ? space_delim : tab_delim);
		if ( svalue == NULL ) {
			fprintf(stderr, "bad format on line %d: %s\n", line_number, label);
			delete label;
			return -1;
		}	
		*(svalue++) = 0;
		double value = atof(svalue);

		data.push_back( pair<string,double>( label, value ) );

		delete[] label;
		line = "";
		getline(in,line);
	}

	create_graph(output);

	return 0;
}

