#!/usr/bin/env python
from cairo import *

border_width = 4	# Around edge of diagram
label_padding = 8	# Gap between bar and text
bar_width = 400		# Length of longest bar
title_font_size = 20	# Title font size
font_size = 14		# Label font size
gap_between_rows = 4	# Vertical gap between bars
bar_border_width = 1	# Outline stroke width for each bar

def plot(title, data):
	max_value = max(value for key, value in data)
	bar_scale_factor = float(bar_width) / max_value

	# Dummy surface for measuring...
	surface = ImageSurface(FORMAT_RGB24, 100, 100)
	cr = Context(surface)

	cr.set_font_size(title_font_size)
	title_font_ascent, title_font_descent, title_font_height, title_font_max_x_adv, title_font_max_y_adv = cr.font_extents()
	title_extents = cr.text_extents(title)
	title_left_start = title_extents[0]
	title_width = title_extents[2]
	title_height = title_extents[3] - title_extents[1]

	cr.set_font_size(font_size)
	ascent, descent, height, max_x_adv, max_y_adv = cr.font_extents()
	row_spacing = height + gap_between_rows

	class Bar:
		def __init__(self, (key, value)):
			self.key = key
			self.value = value
			self.length = max(1, value * bar_scale_factor)

			text_ext = cr.text_extents(self.key)
			self.key_width = text_ext[2]

			text_ext = cr.text_extents(str(self.value))
			self.value_label_width = text_ext[2]

	data = map(Bar, data)

	max_key_width = max(row.key_width for row in data)

	max_value_with_label_width = max(row.length + row.value_label_width for row in data) + label_padding

	# Real surface for drawing
	content_width = border_width * 2 + max(max_key_width + label_padding + max_value_with_label_width, title_width)
	surface = ImageSurface(FORMAT_RGB24,
				int(border_width * 2 + content_width),
				int(title_height + row_spacing * len(data) + border_width * 2))
	cr = Context(surface)

	# Set background colour
	cr.set_source_rgb(1, 1, 1)
	cr.paint()

	cr.translate(border_width, border_width)

	# Title
	title_x = (content_width - title_width) / 2
	#cr.rectangle(title_x, 0, title_width, title_height)
	#cr.set_source_rgb(1, 0, 0)
	#cr.stroke()

	cr.set_source_rgb(0, 0, 0)
	cr.set_font_size(title_font_size)
	cr.move_to(title_x, title_font_ascent)
	cr.show_text(title)

	cr.translate(0, title_height)

	cr.set_font_size(font_size)

	# Place (0, 0) at the top-left corner of the first bar
	cr.translate(max_key_width + label_padding, 0)
	for row in data:
		cr.set_source_rgb(0, 0, 0)

		cr.move_to(-row.key_width - label_padding, ascent)
		cr.show_text(row.key)

		cr.move_to(row.length + label_padding, ascent)
		cr.show_text(str(row.value))

		cr.rectangle(0, 0, row.length, height)
		cr.fill()

		if row.length > bar_border_width * 2:
			linear = LinearGradient(0, 0, bar_width, 0)
			linear.add_color_stop_rgb(0, 0, 0.3, 1)
			linear.add_color_stop_rgb(1, 1, 1, 1)
			cr.set_source(linear)
			cr.rectangle(bar_border_width, bar_border_width,
				     row.length - bar_border_width * 2,
				     height - bar_border_width * 2)
			cr.fill()

		cr.translate(0, row_spacing)

	return surface, max_key_width

if __name__ == '__main__':
	surface = plot('Test', [
		('Good', 5),
		('OK', 10),
		('Bad', 2),
		('Odd', 0),
	])
	surface.write_to_png('out.png')
