"""
 +-------------------------------------------------------------------+
 |                   H T M L - G R A P H S   (v4.10)                 |
 |                                                                   |
 | Copyright Gerd Tentler                www.gerd-tentler.de/tools   |
 | Created: Sep. 17, 2002                Last modified: Jan. 7, 2012 |
 +-------------------------------------------------------------------+
 | This program may be used and hosted free of charge by anyone for  |
 | personal purpose as long as this copyright notice remains intact. |
 |                                                                   |
 | Obtain permission before selling the code for this program or     |
 | hosting this software on a commercial website or redistributing   |
 | this software over the Internet or in any other medium. In all    |
 | cases copyright must remain intact.                               |
 +-------------------------------------------------------------------+

=====================================================================================================
 Example:

   import graphs
   graph = graphs.BarGraph('hBar')
   graph.values = [234, 125, 289, 147, 190]
   print graph.create()

 Returns HTML code
=====================================================================================================
"""

import re, math

class BarGraph:
	"""creates horizontal and vertical bar graphs, progress bars and faders"""
	def __init__(self, type = ''):
#----------------------------------------------------------------------------------------------------
# Configuration
#----------------------------------------------------------------------------------------------------
		self.type = type and type or 'hBar'       # graph type: "hBar", "vBar", "pBar", or "fader"
		self.values = []                          # graph data: list

		self.graphBGColor = ''                    # graph background color: string
		self.graphBorder = ''                     # graph border: string (CSS-spec: "size style color"; doesn't work with NN4)
		self.graphPadding = 0                     # graph padding: integer (pixels)

		self.titles = []                          # titles: array or string with comma-separated values
		self.titleColor = 'black'                 # title font color: string
		self.titleBGColor = '#C0E0FF'             # title background color: string
		self.titleBorder = '2px groove white'     # title border: string (CSS specification)
		self.titleFont = 'Arial, Helvetica'       # title font family: string (CSS specification)
		self.titleSize = 12                       # title font size: integer (pixels)
		self.titleAlign = 'center'                # title text align: "left", "center", or "right"
		self.titlePadding = 2                     # title padding: integer (pixels)

		self.labels = []                          # label names: list or string with comma-separated values
		self.labelColor = 'black'                 # label font color: string
		self.labelBGColor = '#C0E0FF'             # label background color: string
		self.labelBorder = '2px groove white'     # label border: string (CSS-spec: "size style color"; doesn't work with NN4)
		self.labelFont = 'Arial, Helvetica'       # label font family: string (CSS-spec)
		self.labelSize = 12                       # label font size: integer (pixels)
		self.labelAlign = 'center'                # label text align: "left", "center", or "right"
		self.labelSpace = 0                       # additional space between labels: integer (pixels)

		self.barWidth = 20                        # bar width: integer (pixels)
		self.barLength = 1.0                      # bar length ratio: float (from 0.1 to 2.9)
		self.barColors = []                       # bar colors OR bar images: list or string with comma-separated values
		self.barBGColor = ''                      # bar background color: string
		self.barBorder = '2px outset white'       # bar border: string (CSS-spec: "size style color"; doesn't work with NN4)
		self.barLevelColors = []                  # bar level colors: ascending list (bLevel, bColor[,...]); draw bars >= bLevel with bColor

		self.showValues = 0                       # show values: 0 = % only, 1 = abs. and %, 2 = abs. only, 3 = none
		self.baseValue = 0;                       # base value: integer or float (only hBar and vBar)

		self.absValuesColor = 'black'             # abs. values font color: string
		self.absValuesBGColor = '#C0E0FF'         # abs. values background color: string
		self.absValuesBorder = '2px groove white' # abs. values border: string (CSS-spec: "size style color"; doesn't work with NN4)
		self.absValuesFont = 'Arial, Helvetica'   # abs. values font family: string (CSS-spec)
		self.absValuesSize = 12                   # abs. values font size: integer (pixels)
		self.absValuesPrefix = ''                 # abs. values prefix: string (e.g. "$")
		self.absValuesSuffix = ''                 # abs. values suffix: string (e.g. " kg")

		self.percValuesColor = 'black'            # perc. values font color: string
		self.percValuesFont = 'Arial, Helvetica'  # perc. values font family: string (CSS-spec)
		self.percValuesSize = 12                  # perc. values font size: integer (pixels)
		self.percValuesDecimals = 0               # perc. values number of decimals: integer

		self.charts = 1                           # number of charts: integer

		# hBar/vBar only:
		self.legend = []                          # legend items: list or string with comma-separated values
		self.legendColor = 'black'                # legend font color: string
		self.legendBGColor = '#F0F0F0'            # legend background color: string
		self.legendBorder = '2px groove white'    # legend border: string (CSS-spec: "size style color"; doesn't work with NN4)
		self.legendFont = 'Arial, Helvetica'      # legend font family: string (CSS-spec)
		self.legendSize = 12                      # legend font size: integer (pixels)
		self.legendAlign = 'top'                  # legend vertical align: "top", "center", "bottom"
		self.legendAbsValues = 0	              # view abs. values in legend: 1 = yes, 0 = no

		# debug mode: 0 = off, 1 = on; just views some extra information
		self.debug = 0
#----------------------------------------------------------------------------------------------------

	# default bar colors; only used if barColors isn't set
	__colors = ('#0000FF', '#FF0000', '#00E000', '#A0A0FF', '#FFA0A0', '#00A000')

	# error messages
	__err_type = 'ERROR: Type must be "hBar", "vBar", "pBar", or "fader"'

	# CSS names (don't change)
	__cssGRAPH = ''
	__cssBAR = ''
	__cssBARBG = ''
	__cssTITLE = ''
	__cssLABEL = ''
	__cssLABELBG = ''
	__cssLEGEND = ''
	__cssLEGENDBG = ''
	__cssABSVALUES = ''
	__cssPERCVALUES = ''

	# search pattern for images
	__img_pattern = re.compile(r'\.(jpg|jpeg|jpe|gif|png)')

	def set_styles(self):
		"""set graph styles"""
		if self.graphBGColor: self.__cssGRAPH += 'background-color:' + self.graphBGColor + ';'
		if self.graphBorder: self.__cssGRAPH += 'border:' + self.graphBorder + ';'
		if self.barBorder: self.__cssBAR += 'border:' + self.barBorder + ';'
		if self.barBGColor: self.__cssBARBG += 'background-color:' + self.barBGColor + ';'
		if self.titleColor: self.__cssTITLE += 'color:' + self.titleColor + ';'
		if self.titleBGColor: self.__cssTITLE += 'background-color:' + self.titleBGColor + ';'
		if self.titleBorder: self.__cssTITLE += 'border:' + self.titleBorder + ';'
		if self.titleFont: self.__cssTITLE += 'font-family:' + self.titleFont + ';'
		if self.titleAlign: self.__cssTITLE += 'text-align:' + self.titleAlign + ';'
		if self.titleSize: self.__cssTITLE += 'font-size:' + str(self.titleSize) + 'px;'
		if self.titleBGColor: self.__cssTITLE += 'background-color:' + self.titleBGColor + ';'
		if self.titlePadding: self.__cssTITLE += 'padding:' + str(self.titlePadding) + 'px;'
		if self.labelColor: self.__cssLABEL += 'color:' + self.labelColor + ';'
		if self.labelBGColor: self.__cssLABEL += 'background-color:' + self.labelBGColor + ';'
		if self.labelBorder: self.__cssLABEL += 'border:' + self.labelBorder + ';'
		if self.labelFont: self.__cssLABEL += 'font-family:' + self.labelFont + ';'
		if self.labelSize: self.__cssLABEL += 'font-size:' + str(self.labelSize) + 'px;'
		if self.labelAlign: self.__cssLABEL += 'text-align:' + self.labelAlign + ';'
		if self.labelBGColor: self.__cssLABELBG += 'background-color:' + self.labelBGColor + ';'
		if self.legendColor: self.__cssLEGEND += 'color:' + self.legendColor + ';'
		if self.legendFont: self.__cssLEGEND += 'font-family:' + self.legendFont + ';'
		if self.legendSize: self.__cssLEGEND += 'font-size:' + str(self.legendSize) + 'px;'
		if self.legendBGColor: self.__cssLEGENDBG += 'background-color:' + self.legendBGColor + ';'
		if self.legendBorder: self.__cssLEGENDBG += 'border:' + self.legendBorder + ';'
		if self.absValuesColor: self.__cssABSVALUES += 'color:' + self.absValuesColor + ';'
		if self.absValuesBGColor: self.__cssABSVALUES += 'background-color:' + self.absValuesBGColor + ';'
		if self.absValuesBorder: self.__cssABSVALUES += 'border:' + self.absValuesBorder + ';'
		if self.absValuesFont: self.__cssABSVALUES += 'font-family:' + self.absValuesFont + ';'
		if self.absValuesSize: self.__cssABSVALUES += 'font-size:' + str(self.absValuesSize) + 'px;'
		if self.percValuesColor: self.__cssPERCVALUES += 'color:' + self.percValuesColor + ';'
		if self.percValuesFont: self.__cssPERCVALUES += 'font-family:' + self.percValuesFont + ';'
		if self.percValuesSize: self.__cssPERCVALUES += 'font-size:' + str(self.percValuesSize) + 'px;'

	def level_color(self, value, color):
		"""return bar color for each level"""
		if self.barLevelColors:
			for i in range(0, len(self.barLevelColors), 2):
				try:
					if (self.barLevelColors[i] > 0 and value >= self.barLevelColors[i]) or \
					   (self.barLevelColors[i] < 0 and value <= self.barLevelColors[i]):
						color = self.barLevelColors[i+1]
				except IndexError: pass
		return color

	def build_bar(self, value, width, height, color):
		"""return a single bar"""
		title = self.absValuesPrefix + str(value) + self.absValuesSuffix
		bg = self.__img_pattern.search(color) and 'background' or 'bgcolor'
		bar = '<table border=0 cellspacing=0 cellpadding=0><tr>'
		bar += '<td style="' + self.__cssBAR + '" ' + bg + '="' + color + '"'
		bar += (value != '') and ' title="' + title + '">' or '>'
		bar += '<div style="width:' + str(width) + 'px; height:' + str(height) + 'px;'
		bar += ' line-height:1px; font-size:1px;"></div>'
		bar += '</td></tr></table>'
		return bar

	def build_fader(self, value, width, height, x, color):
		"""return a single fader"""
		fader = '<table border=0 cellspacing=0 cellpadding=0><tr>'
		x -= int(round(width / 2))
		if x > 0: fader += '<td width=' + str(x) + '></td>'
		fader += '<td>' + self.build_bar(value, width, height, color) + '</td>'
		fader += '</tr></table>'
		return fader

	def build_value(self, val, max_dec, sum = 0, align = ''):
		"""return a single bar/fader value"""
		val = _number_format(val, max_dec)
		if sum: sum = _number_format(sum, max_dec)
		value = '<td style="' + self.__cssABSVALUES + '"'
		if align: value += ' align=' + align
		value += ' nowrap>'
		value += '&nbsp;' + self.absValuesPrefix + str(val) + self.absValuesSuffix
		if sum: value += ' / ' + self.absValuesPrefix + str(sum) + self.absValuesSuffix
		value += '&nbsp;</td>'
		return value

	def build_legend(self, barColors, barValues):
		"""return the legend"""
		if hasattr(self.legend, 'split'): self.legend = self.legend.split(',')
		legend = '<table border=0 cellspacing=0 cellpadding=0><tr>'
		legend += '<td style="' + self.__cssLEGENDBG + '">'
		legend += '<table border=0 cellspacing=4 cellpadding=0>'
		i = 0

		for color in barColors:
			if len(self.legend) >= i+1:
				text = hasattr(self.legend[i], 'strip') and self.legend[i].strip() or str(self.legend[i])
			else: text = ''
			legend += '<tr>'
			legend += '<td>' + self.build_bar('', self.barWidth, self.barWidth, color) + '</td>'
			legend += '<td style="' + self.__cssLEGEND + '" nowrap>' + text + '</td>'

			if self.legendAbsValues:
				sum = 0
				for charts in barValues:
					for labels in charts: sum += labels[i]
				legend += '<td style="' + self.__cssLEGEND + '" nowrap>(' + self.absValuesPrefix + str(sum) + self.absValuesSuffix + ')</td>'

			legend += '</tr>'
			i += 1

		legend += '</table></td></tr></table>'
		return legend

	def build_hTitle(self, titleLabel, titleValue, titleBar):
		"""return horizontal titles"""
		title = '<tr>'
		title += '<td style="' + self.__cssTITLE + '">' + titleLabel + '</td>'
		if titleValue != '': title += '<td style="' + self.__cssTITLE + '">' + titleValue + '</td>'
		title += '<td style="' + self.__cssTITLE + '">' + titleBar + '</td>'
		title += '</tr>'
		return title

	def create_hBar(self, value, percent, mPerc, mPerc_neg, max_neg, mul, valSpace, bColor, border, spacer, spacer_neg):
		"""return a single horizontal bar with label and values (abs./perc.)"""
		bar = '<table border=0 cellspacing=0 cellpadding=0 height=100%><tr>'

		if percent < 0:
			percent *= -1
			bar += '<td style="' + self.__cssLABELBG + '" height=' + str(self.barWidth) + ' width=' + str(int(round((mPerc_neg - percent) * mul + valSpace))) + ' align=right nowrap>'
			if self.showValues < 2: bar += '<span style="' + self.__cssPERCVALUES + '">' + str(_number_format(percent, self.percValuesDecimals)) + '%</span>'
			bar += '&nbsp;</td><td style="' + self.__cssLABELBG + '">'
			bar += self.build_bar(value, int(round(percent * mul)), self.barWidth, bColor)
			bar += '</td><td width=' + str(spacer) + '></td>'
		else:
			if max_neg:
				bar += '<td style="' + self.__cssLABELBG + '" width=' + str(spacer_neg) + '>'
				bar += '<table border=0 cellspacing=0 cellpadding=0><tr><td></td></tr></table></td>'
			if percent:
				bar += '<td>'
				bar += self.build_bar(value, int(round(percent * mul)), self.barWidth, bColor)
				bar += '</td>'
			else: bar += '<td width=1 height=' + str(self.barWidth + (border * 2)) + '></td>'
			bar += '<td style="' + self.__cssPERCVALUES + '" width=' + str(int(round((mPerc - percent) * mul + valSpace))) + ' align=left nowrap>'
			if self.showValues < 2: bar += '&nbsp;' + str(_number_format(percent, self.percValuesDecimals)) + '%'
			bar += '&nbsp;</td>'

		bar += '</tr></table>'
		return bar

	def create_vBar(self, value, percent, mPerc, mPerc_neg, max_neg, mul, valSpace, bColor, border, spacer, spacer_neg):
		"""return a single vertical bar with label and values (abs./perc.)"""
		bar = '<table border=0 cellspacing=0 cellpadding=0 width=100%><tr align=center>'

		if percent < 0:
			percent *= -1
			bar += '<td height=' + str(spacer) + '></td></tr><tr align=center valign=top><td style="' + self.__cssLABELBG + '">'
			bar += self.build_bar(value, self.barWidth, int(round(percent * mul)), bColor)
			bar += '</td></tr><tr align=center valign=top>'
			bar += '<td style="' + self.__cssLABELBG + '" height=' + str(int(round((mPerc_neg - percent) * mul + valSpace))) + ' nowrap>'
			bar += (self.showValues < 2) and '<span style="' + self.__cssPERCVALUES + '">' + str(_number_format(percent, self.percValuesDecimals)) + '%</span>' or '&nbsp;'
			bar += '</td>'
		else:
			bar += '<td style="' + self.__cssPERCVALUES + '" valign=bottom height=' + str(int(round((mPerc - percent) * mul + valSpace))) + ' nowrap>'
			if self.showValues < 2: bar += str(_number_format(percent, self.percValuesDecimals)) + '%'
			bar += '</td>'
			if percent:
				bar += '</tr><tr align=center valign=bottom><td>'
				bar += self.build_bar(value, self.barWidth, int(round(percent * mul)), bColor)
				bar += '</td>'
			else: bar += '</tr><tr><td width=' + str(self.barWidth + (border * 2)) + ' height=1></td>'
			if max_neg:
				bar += '</tr><tr><td style="' + self.__cssLABELBG + '" height=' + str(spacer_neg) + '>'
				bar += '<table border=0 cellspacing=0 cellpadding=0><tr><td></td></tr></table></td>'

		bar += '</tr></table>'
		return bar

	def create(self):
		"""create a complete bar graph (horizontal, vertical, progress, or fader)"""
		self.type = self.type.lower()
		d = self.values
		t = hasattr(self.titles, 'split') and self.titles.split(',') or self.titles
		r = hasattr(self.labels, 'split') and self.labels.split(',') or self.labels
		drc = hasattr(self.barColors, 'split') and self.barColors.split(',') or self.barColors
		val = []
		bc = []
		if self.barLength < 0.1: self.barLength = 0.1
		elif self.barLength > 2.9: self.barLength = 2.9
		labels = (len(d) > len(r)) and len(d) or len(r)

		if self.type == 'pbar' or self.type == 'fader':
			if not self.barBGColor: self.barBGColor = self.labelBGColor
			if self.labelBGColor == self.barBGColor and len(t) == 0:
				self.labelBGColor = ''
				self.labelBorder = ''

		self.set_styles()

		graph = '<table border=0 cellspacing=0 cellpadding=' + str(self.graphPadding) + '><tr>'
		graph += '<td' + (self.__cssGRAPH and ' style="' + self.__cssGRAPH + '"' or '') + '>'

		if self.legend and self.type != 'pbar' and self.type != 'fader':
			graph += '<table border=0 cellspacing=0 cellpadding=0><tr><td>'

		if self.charts > 1:
			divide = math.ceil(labels / self.charts)
			graph += '<table border=0 cellspacing=0 cellpadding=6><tr valign=top><td>'
		else: divide = 0

		sum = 0
		max = 0
		max_neg = 0
		max_dec = 0
		ccnt = 0
		lcnt = 0
		chart = 0

		for i in range(labels):
			if divide and i and not i % divide:
				lcnt = 0
				chart += 1

			try: drv = len(d[i]) and [e for e in d[i]] or [d[i]]
			except: drv = [d[i]]

			j = 0
			dec = 0
			if len(val) <= chart: val.append([])

			for v in drv:
				s = str(v)
				if s.find('.') != -1:
					dec = len(s[s.find('.') + 1:])
					if dec > max_dec: max_dec = dec

				if len(val[chart]) <= lcnt: val[chart].append([])
				val[chart][lcnt].append(v)

				if v != 0: v -= self.baseValue

				if self.type == 'hbar' or self.type == 'vbar' or j == 0:
					if v > max: max = v
					elif v < max_neg: max_neg = v

				if v < 0: v *= -1
				sum += v

				if len(bc) <= j:
					if ccnt >= len(self.__colors): ccnt = 0
					if len(drc) <= j or len(drc[j]) < 3:
						bc.append(self.__colors[ccnt])
						ccnt += 1
					else: bc.append(drc[j].strip())

				j += 1

			lcnt += 1

		if self.barLevelColors:
			for i in range(0, len(self.barLevelColors), 2):
				if self.barLevelColors[i] == 'MAX': self.barLevelColors[i] = max

		border = int(self.barBorder[0])
		mPerc = sum and int(round(max * 100.0 / sum)) or 0
		if self.type == 'pbar' or self.type == 'fader': mul = 2
		else: mul = mPerc and 100.0 / mPerc or 1
		mul *= self.barLength

		if self.showValues < 2:
			if self.type == 'hbar':
				valSpace = (self.percValuesDecimals * (self.percValuesSize / 1.6)) + (self.percValuesSize * 3.2)
			else: valSpace = self.percValuesSize * 1.2
		else: valSpace = self.percValuesSize
		spacer = maxSize = int(round(mPerc * mul + valSpace + border * 2))

		if max_neg:
			mPerc_neg = sum and int(round(-max_neg * 100.0 / sum)) or 0
			if mPerc_neg > mPerc and self.type != 'pbar' and self.type != 'fader':
				mul = 100.0 / mPerc_neg * self.barLength
			spacer_neg = int(round(mPerc_neg * mul + valSpace + border * 2))
			maxSize += spacer_neg
		else: mPerc_neg = spacer_neg = 0

		titleLabel = ''
		titleValue = ''
		titleBar = ''

		if len(t) > 0:
			titleLabel = (t[0] == '') and '&nbsp;' or t[0]

			if self.showValues == 1 or self.showValues == 2:
				titleValue = (t[1] == '') and '&nbsp;' or t[1]
				titleBar = (t[2] == '') and '&nbsp;' or t[2]
			else: titleBar = (t[1] == '') and '&nbsp;' or t[1]

		chart = 0
		lcnt = 0

		for v in val:
			graph += '<table border=0 cellspacing=2 cellpadding=0>'

			if self.type == 'hbar':
				if len(t) > 0: graph += self.build_hTitle(titleLabel, titleValue, titleBar)

				for i in range(len(v)):
					label = (lcnt < len(r)) and r[lcnt].strip() or str(lcnt + 1)
					rowspan = len(v[i])
					graph += '<tr><td style="' + self.__cssLABEL + '"' + ((rowspan > 1) and ' rowspan=' + str(rowspan) or '') + '>'
					graph += '&nbsp;' + label + '&nbsp;</td>'

					for j in range(len(v[i])):
						value = v[i][j] and v[i][j] - self.baseValue or 0
						percent = sum and value * 100.0 / sum or 0
						value = _number_format(v[i][j], max_dec)
						bColor = self.level_color(v[i][j], bc[j])

						if self.showValues == 1 or self.showValues == 2:
							graph += self.build_value(v[i][j], max_dec, 0, 'right')

						graph += '<td' + (self.__cssBARBG and ' style="' + self.__cssBARBG + '"' or '') + ' height=100% width=' + str(maxSize) + '>'
						graph += self.create_hBar(value, percent, mPerc, mPerc_neg, max_neg, mul, valSpace, bColor, border, spacer, spacer_neg)
						graph += '</td></tr>'
						if j < len(v[i]) - 1: graph += '<tr>'

					if self.labelSpace and i < len(v)-1: graph += '<tr><td colspan=3 height=' + str(self.labelSpace) + '></td></tr>'
					lcnt += 1

			elif self.type == 'vbar':
				graph += '<tr align=center valign=bottom>'

				if titleBar != '':
					titleBar = titleBar.replace('-', '-<br>')
					graph += '<td style="' + self.__cssTITLE + '" valign=middle>' + titleBar + '</td>'

				for i in range(len(v)):
					for j in range(len(v[i])):
						value = v[i][j] and v[i][j] - self.baseValue or 0
						percent = sum and value * 100.0 / sum or 0
						value = _number_format(v[i][j], max_dec)
						bColor = self.level_color(v[i][j], bc[j])

						graph += '<td' + (self.__cssBARBG and ' style="' + self.__cssBARBG + '"' or '') + '>'
						graph += self.create_vBar(value, percent, mPerc, mPerc_neg, max_neg, mul, valSpace, bColor, border, spacer, spacer_neg)
						graph += '</td>'

					if self.labelSpace: graph += '<td width=' + str(self.labelSpace) + '></td>'

				if self.showValues == 1 or self.showValues == 2:
					graph += '</tr><tr align=center>'
					if titleValue != '': graph += '<td style="' + self.__cssTITLE + '">' + titleValue + '</td>'

					for i in range(len(v)):
						for j in range(len(v[i])):
							graph += self.build_value(v[i][j], max_dec)
						if self.labelSpace: graph += '<td width=' + str(self.labelSpace) + '></td>'

				graph += '</tr><tr>'
				if titleLabel != '': graph += '<td style="' + self.__cssTITLE + '">' + titleLabel + '</td>'

				for i in range(len(v)):
					label = (lcnt < len(r)) and r[lcnt].strip() or str(lcnt + 1)
					colspan = len(v[i])
					graph += '<td style="' + self.__cssLABEL + '"' + ((colspan > 1) and ' colspan=' + str(colspan) or '') + '>'
					graph += '&nbsp;' + label + '&nbsp;</td>'
					if self.labelSpace: graph += '<td width=' + str(self.labelSpace) + '></td>'
					lcnt += 1

				graph += '</tr>'

			elif self.type == 'pbar' or self.type == 'fader':
				if len(t) > 0: graph += self.build_hTitle(titleLabel, titleValue, titleBar)

				for i in range(len(v)):
					try: m = (len(v[i]) > 1) and True or False
					except: m = False

					if m or not i:
						label = (lcnt < len(r)) and r[lcnt].strip() or str(i + 1)
						graph += '<tr>'

						if len(r):
							graph += '<td style="' + self.__cssLABEL + '">'
							graph += '&nbsp;' + label + '&nbsp;</td>'

						try: sum = v[i][1] and v[i][1] or v[-1][0]
						except: sum = v[-1][0]

						percent = sum and v[i][0] * 100.0 / sum or 0
						value = _number_format(v[i][0], max_dec)

						if self.showValues == 1 or self.showValues == 2:
							graph += self.build_value(v[i][0], max_dec, sum, 'right')

						graph += '<td' + (self.__cssBARBG and ' style="' + self.__cssBARBG + '"' or '') + '>'

						self.barColors = (len(drc) >= i+1) and drc[i].strip() or self.__colors[0]
						bColor = self.level_color(v[i][0], self.barColors)
						graph += '<table border=0 cellspacing=0 cellpadding=0><tr><td>'
						if self.type == 'fader':
							graph += self.build_fader(value, int(round(self.barWidth / 2)), self.barWidth, int(round(percent * mul)), bColor)
						else: graph += self.build_bar(value, int(round(percent * mul)), self.barWidth, bColor)
						graph += '</td><td width=' + str(int(round((100 - percent) * mul))) + '></td>'
						graph += '</tr></table></td>'
						if self.showValues < 2: graph += '<td style="' + self.__cssPERCVALUES + '" nowrap>&nbsp;' + str(_number_format(percent, self.percValuesDecimals)) + '%</td>'
						graph += '</tr>'
						if self.labelSpace and i < len(v)-1: graph += '<td colspan=3 height=' + str(self.labelSpace) + '></td>'
						lcnt += 1

			else: graph += '<tr><td>' + self.__err_type + '</td></tr>'

			graph += '</table>'

			if chart < self.charts - 1 and len(val[chart+1]):
				graph += '</td>'
				if self.type == 'vbar': graph += '</tr><tr valign=top>'
				graph += '<td>'

			chart += 1

		if self.charts > 1: graph += '</td></tr></table>'

		if self.legend and self.type != 'pbar' and self.type != 'fader':
			graph += '</td><td width=10>&nbsp;</td><td' + (self.legendAlign and ' valign=' + self.legendAlign or '') + '>'
			graph += self.build_legend(bc, val)
			graph += '</td></tr></table>'

		if self.debug:
			graph += "<br>sum=%s max=%s max_neg=%s max_dec=%s " % (sum, max, max_neg, max_dec)
			graph += "mPerc=%s mPerc_neg=%s mul=%s valSpace=%s" % (mPerc, mPerc_neg, mul, valSpace)

		graph += '</td></tr></table>'
		return graph

def _number_format(val, dec):
	"""return float with dec decimals; if dec is 0, return integer"""
	return dec and ('%.' + str(dec) + 'f') % val or int(round(val))

if __name__ == '__main__':
	print __doc__

