(function($) {
	/**
	 * Converts a table into a dl list, along with optional functionality
	 *
	 * @option int toggleDurationMs specify the hide/show animate time (0 for no animation)
	 * @option bool|array|string closeByDefault indicate which nodes should be closed by default, accepts 
	 * @option string closeLabel
	 * @option int labelColumn the column of the table to use as the label
	 * @option 
	 * @option string bodyTemplate stores the html template used as the body
	 */
	$.fn.listConverter = function(options)
	{
		options = options || {};
		var o = $.extend({
			toggleDurationMs: 0,
			closeByDefault: false,
			closeLabel: 'close',
			openLabel: 'open',
			labelColumn: 0,
			bodyColumn: 1,
			bodyTemplate: false,
			labelTemplate: false
		}, options);
		var $this = this;
		
		// iterate through each object and 
		return $this.each(function() {
		
			var id = randomIdGenerator('list-converter-');

			// re-generate the content
			var html = generateHtmlForList($(this), id, o);
			$(this).replaceWith(html);

			// provide behaviour hooks
			var $id = $('#'+id);
			$('a.list-close-button', $id).click(function(e) {
				e.preventDefault();
				
				$(this).toggleClass('data-open').toggleClass('data-close');
				$(this).parent().next('dd').toggle(o.toggleDurationMs);
				$(this).text($(this).hasClass('data-open') ? o.closeLabel : o.openLabel);
				return false;
			});
			
			// define the initial open/close state
			if (o.closeByDefault !== false) {
				// select the required elements to be handled
				var $dd = $('dd', $id);
				var $closeButtons = $('.list-close-button', $id);
				
				if (typeof o.closeByDefault === 'object') {
					$dd = $dd.filter(arrayFilter);
					$closeButtons = $closeButtons.filter(arrayFilter);
				} else if (typeof o.closeByDefault === 'string') {
					$dd = $dd.filter(o.closeByDefault);
					$closeButtons = $closeButtons.filter(o.closeByDefault);
				}
				// perform actions on those elements
				$dd.hide();
				$closeButtons.text(o.openLabel).removeClass('data-open').addClass('data-close');
			}
		});
	}
	
	function randomIdGenerator(prefix)
	{
		prefix = prefix || '';
		return prefix+Math.round(Math.random()*100000);
	}
	
	/**
	 *
	 */
	function arrayFilter(i)
	{
		return o.closeByDefault.indexOf(i) > -1;
	}
	
	/**
	 * Generate a data list for the provided table
	 *
	 * @param jQuery $table table selector
	 * @param string id id attribute for list 
	 * @return string
	 */
	function generateHtmlForList($table, id, o)
	{
		var html = '<dl id="'+id+'" class="'+$table.attr('class')+'">';
		var body;
		var label;
		var regex = /\$(\d+)/;
		// loop through each role
		$('tr', $table).each(function() {
			if(o.bodyTemplate === false) {
				body = $('td:eq('+o.bodyColumn+')',this).html()
			} else {
				body = o.bodyTemplate;
				var matches;
				while(matches = regex.exec(body)) {
					body = body.replace(matches[0], $('td:eq('+matches[1]+')',this).html());
				}
				
			}
			if(o.labelTemplate === false) {
				label = $('td:eq('+o.labelColumn+')',this).html();
			} else {
				label = o.labelTemplate;
				var matches;
				while(matches = regex.exec(label)) {
					label = label.replace(matches[0], $('td:eq('+matches[1]+')',this).html());
				}
			}
			html += '<dt>'+label+'<a class="list-close-button data-open" href="">'+o.closeLabel+'</a></dt><dd>'+body+'</dd>';
		});
		html += '</dl>';
		return html;
	}

})(jQuery);
