#!/usr/bin/env python

'''Convert a CSV table to an HTML table - with some benefits'''

import sys
#mport string

def usage(retval):
	'''Output a usage message and exit'''
	sys.stderr.write("Convert a whitespace (or arbitrarily) delimited\n")
	sys.stderr.write("ASCII table, one row per line, to an HTML table.\n\n")
	sys.stderr.write("Usage:\n")
	sys.stderr.write("   -d                use a delimiter of |\n")
	sys.stderr.write("   --delimiter ch    use a delimiter of ch\n")
	sys.stderr.write("   --help            this stuff\n")
	sys.stderr.write("   --suppressible    Output javascript code to allow suppressing unwanted rows and columns\n")
	sys.stderr.write("   --tooltips        Output CSS styling to allow row/column tooltips\n")
	sys.exit(retval)

def suppression_functions():
	'''Output javascript code needed for suppressing rows and columns'''
	return '''
<script type="text/javascript">
	function hide_row(row_name)
		{
		var row_element = document.getElementById(row_name);
		row_element.style.display = 'none';
		}

	function hide_colgroup(column_name)
		{
		// Sadly, it appears that columns are not children of their tables - instead, rows are children of the table,
		// and portions of a given column is a child of multiple rows.
		var table_element  = document.getElementById('table');
		td_elements = table_element.getElementsByTagName('td');
		for (td_elementno = 0; td_elementno < td_elements.length; td_elementno ++)
			{
			td_name = td_elements[td_elementno].getAttribute('name');
			// Check if the td name is the ColumnID and change display if needed.
			if (td_name == column_name)
				{
				td_elements[td_elementno].style.display = 'none';
				}
			}
		}
</script>
	'''

def tooltip_style():
	'''Output enough CSS that we can bring up tooltips for table elements, describing what row and column they correspond to'''
	return '''
<STYLE>
	.popup
	{
	COLOR: #9F141A;
	CURSOR: help;
	TEXT-DECORATION: none
	}
</STYLE>
'''

def id_equals_table(suppressible):
	'''If needed, output the id="table" stuff'''
	if suppressible:
		return 'id="table" '
	else:
		return ''

def form_tr_start(suppressible, rowno):
	'''Create a well-formed <tr>whatever</tr>'''

	return '<tr%s>' % id_equals_rowno(suppressible, rowno)

def form_tr_end():
	'''Output a close tr tag'''
	return '</tr>'

def id_equals_rowno(suppressible, rowno):
	'''Output an id for a <tr>'''

	if suppressible:
		return ' id="row-%d"' % (rowno + 1)
	else:
		return ''

def spanned(tooltips, rowno, colno, row_description, column_description, field):
	# pylint: disable=R0913
	# R0913: We need a few arguments
	'''Output tooltip stuff, if needed'''
	if tooltips and rowno != 0 and colno != 0:
		return '<SPAN title="row: %s, column: %s " class="popup">%s</SPAN>' % (row_description, column_description, field)
	else:
		return field

def full_td(field, row_description, column_description, rowno, colno, suppressible, tooltips):
	# pylint: disable=R0913
	# R0913: We need a few arguments
	'''Form a complete <td>whatever</td>'''

	return '<td%s%s</td>' % (
		td_name(field, rowno, colno, suppressible),
		spanned(tooltips, rowno, colno, row_description, column_description, field),
		)

def td_name(field, rowno, colno, suppressible):
	'''Output a suitable <td>'''

	if field is None:
		field = ''

	if suppressible:
		if rowno == 0 and colno != 0:
			return ' name="col-%d"><button onclick="hide_colgroup(\'col-%d\')">Hide column</button><br>' % (colno + 1, colno + 1)
		elif rowno != 0 and colno == 0:
			return ' name="row-%d"><button onclick="hide_row(\'row-%d\')">Hide row</button>' % (rowno + 1, rowno + 1)
		else:
			return ' name="col-%d">' % (colno + 1)
	else:
		return '>'

def table_start(suppressible):
	'''Return the beginning of table tag and attributes'''
	# Note that in my source material, id='table' was used, not id="table"
	return '<table %swidth="100%%" border="1">' % id_equals_table(suppressible)

class Options:
	# pylint: disable=R0903
	# R0903: We're a container; we don't need a bunch of public methods

	'''Just a container class, to hold a few variables whose values we get from command line options'''

	def __init__(self, delimiter=None, suppressible=False, tooltips=False):
		self.delimiter = delimiter
		self.suppressible = suppressible
		self.tooltips = tooltips

	def parse_options(self, argv):
		'''Parse command line options, modifying config variable values as we go'''
		while argv[1:]:
			if argv[1] == '-d':
				self.delimiter = '|'
			elif argv[1] == '--suppressible':
				self.suppressible = True
			elif argv[1] == '--tooltips':
				self.tooltips = True
			elif argv[1] == '--delimiter' and argv[2:]:
				self.delimiter = argv[2]
				del argv[1]
			elif argv[1] in [ '-h', '--help' ]:
				usage(0)
			else:
				sys.stderr.write("%s: Illegal argument: %s\n" % (argv[0], argv[1]))
				usage(1)
			del argv[1]
		
def form_comment(line):
	'''Output a comment containing the original CSV data - albeit converted to a list'''
	return '<!-- %s -->' % str(line)

def main():
	'''Main function'''
	options = Options()
	options.parse_options(sys.argv)

	maxfields = 0
	lines = []
	for line in sys.stdin:
		line = line.rstrip('\n')
		if options.delimiter == None:
			fields = line.split()
		else:
			fields = line.split(options.delimiter)
		if len(fields) > maxfields:
			maxfields = len(fields)
		lines.append(fields)

	if options.suppressible:
		print suppression_functions()

	if options.tooltips:
		print tooltip_style()

	print table_start(options.suppressible)

	top_row = lines[0]
	#print >> sys.stderr, "top_row is %s" % top_row

	for rowno, line in enumerate(lines):
		print '\t%s' % form_comment(line)

		print '\t%s' % form_tr_start(options.suppressible, rowno)

		for colno in range(maxfields):
			if line[colno:]:
				field = line[colno]
			else:
				field = None
			print '\t\t%s' % full_td(field, lines[rowno][0], top_row[colno], rowno, colno, options.suppressible, options.tooltips)
		print '\t%s' % form_tr_end()

	print '</table>'

main()