if (typeof(TagVisualisation) == 'undefined') {
	TagVisualisation = {};
}

TagVisualisation = function(datasetName,visClasses) {
	this.datasetName = datasetName;
	this._buildRichTableView(visClasses);
	
};

TagVisualisation.prototype = {
	__class__: TagVisualisation,
	visualisations: []
};

TagVisualisation.prototype._buildRichTableView = function(visClasses) {
	var datasetName = this.datasetName;
	var md = MochiKit.DOM;
	var dataTable = $(datasetName);
	if (dataTable.getAttributeNS) {
		newColumn = parseInt(dataTable.getAttributeNS("http://penguins.mooh.org/music","tagcolumn"));
		this.tagColumn = newColumn ? newColumn : this._getTagColumn();
	} else {
		this.tagColumn = this._getTagColumn();
	}
	var dataTableContainer = dataTable.parentNode;
	var containingElement = null;

	// Place the Table element within a containing DIV
	// just in case it's not in one already
	// containingElement will then contain a sized div
	// which is the dataTableContainer. The dataTableContainer
	// contains the table itself.
	
	if (dataTableContainer.nodeName == "BODY") {
		containingElement = dataTableContainer;
		md.swapDOM(dataTable,md.DIV({})).appendChild(dataTable);
		dataTableContainer = dataTable.parentNode;
	} else {
		containingElement = dataTableContainer.parentNode;
	}

	this._dataTableContainer = dataTableContainer;

	var richDiv = this._buildRichTagInfoContainer(dataTableContainer);
	containingElement.insertBefore( richDiv, dataTableContainer);
	this._displayElement = richDiv;

	for (var i = 0; i < visClasses.length; i++ ) {
		this.addVisualisation(new visClasses[i](this));
	}
	// Hide away the existing table
	dataTable.style.display = "none";

};

TagVisualisation.prototype._getDisplayWidth = function(el) {
	var computedStyle;

	// If the default method of obtaining the
	// computed style works, use that
	if ( window.getComputedStyle != undefined ) {
		computedStyle = getComputedStyle(el,"");

	// We need to use a different method to get the computed style
	// from Safari
	} else if (document.defaultView.getComputedStyle != undefined) {
		computedStyle = document.defaultView.getComputedStyle(el,"");
	}

	// Use a default width just in case we can't find a computed style
	if (computedStyle != undefined) {
		return parseInt(computedStyle.getPropertyValue("width").replace(/px/, ""));	
	} else {
		return undefined;
	}
};

TagVisualisation.prototype._buildRichTagInfoContainer = function(currentElement) {
	var md = MochiKit.DOM;
	// Construct the replacement element for the table element in the flow
	// copy it's class.
	return md.DIV({
				"id" : "rich_"+this.datasetName,
			 	"class" : "rich_as_data "+currentElement.className,
			 	"style" : {
			 		"width"  : currentElement.style.width,
			 		"height" : currentElement.style.height,
			 		"display": currentElement.style.display,
			 		"position":currentElement.style.position
			 	}
			 });
};

TagVisualisation.prototype.getDisplayElement = function() {
	return this._displayElement;
}

TagVisualisation.prototype.addVisualisation = function(visObject) {
	this.getDisplayElement().appendChild(visObject.getDisplayElement());
	this.visualisations.push(visObject);
}

TagVisualisation.prototype.getAllTags = function() {
	dataTable = $(this.datasetName);
	tableRows = dataTable.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
	maxValue = 0;

	alltags = {};

	for (i = 0; i < tableRows.length ; i++ ) {
		tagname = tableRows[i].getElementsByTagName("td")[this.tagColumn].childNodes[0].data;
		alltags[tableRows[i].id] = tagname;
	}
	return alltags;
}

TagVisualisation.prototype._getTagColumn = function() {
	dataTable = $(this.datasetName);
	headers = dataTable.getElementsByTagName("thead")[0].getElementsByTagName("tr")[0].getElementsByTagName("th");
	for ( var i = 0; i < headers.length ; i++ ) {
		if ( headers[i].childNodes[0].data.toLowerCase() == "tag" ) {
			return i;
		}
	}
	return 1;
};
TagVisualisation.prototype._getColumnCount = function() {
	dataTable = $(this.datasetName);
	headers = dataTable.getElementsByTagName("thead")[0].getElementsByTagName("tr")[0].getElementsByTagName("th");
	return (headers.length - this._getTagColumn() - 1);
};


if (typeof(TagVisualisation.TagCloud) == 'undefined') {
	TagVisualisation.TagCloud = {};
}


TagVisualisation.TagCloud = function(tagVisualiser) {
	this._tagVisualiser = tagVisualiser;
	this._initElements();
};

TagVisualisation.TagCloud.prototype = {
	__class__: TagVisualisation.TagCloud
};

TagVisualisation.TagCloud.ELEMENT_CSS_CLASS = "rich_as_tagcloud";
TagVisualisation.TagCloud.ELEMENT_ID_PREFIX = "rich_as_tagcloud_";
TagVisualisation.TagCloud.TAG_ELEMENT_CSS_CLASS = "rich_as_tagcloud_tag";
TagVisualisation.TagCloud.TAG_ELEMENT_ID_PREFIX = "rich_as_tagcloud_tag_";

TagVisualisation.TagCloud.prototype._initElements = function() {
	var md = MochiKit.DOM;
	this._displayElement = md.DIV({"id" : TagVisualisation.TagCloud.ELEMENT_ID_PREFIX+this._tagVisualiser.datasetName,
				   "class" : TagVisualisation.TagCloud.ELEMENT_CSS_CLASS
								});
};

TagVisualisation.TagCloud.prototype.getDisplayElement = function() {
	return this._displayElement;
}

TagVisualisation.TagCloud.prototype.update = function(dataColumn) {
	var md = MochiKit.DOM;
	var container = this.getDisplayElement();

	dataTable = $(this._tagVisualiser.datasetName);
	values = {};
	tableRows = dataTable.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
	maxValue = 0;

	alltags = new Array();
	for (i = 0; i < tableRows.length ; i++ ) {
		value = parseFloat(tableRows[i].getElementsByTagName("td")[this._tagVisualiser.tagColumn+dataColumn].childNodes[0].data);
		tagname = tableRows[i].getElementsByTagName("td")[this._tagVisualiser.tagColumn].childNodes[0].data;
		values[tagname]	= value;
		maxValue = Math.max(maxValue,value);
		alltags[i] = tagname;
	}
	alltags.sort();
	for (i = 0; i < alltags.length; i++ )  {
		tag = alltags[i];
		tagId = tag.replace(/\s+/,"_");
		if ( $(TagVisualisation.TagCloud.TAG_ELEMENT_ID_PREFIX+tagId) == null ) {
			tagSpan = md.SPAN({ "id" : TagVisualisation.TagCloud.TAG_ELEMENT_ID_PREFIX+tagId }, tag);
			md.appendChildNodes(container, tagSpan);
		} else {
			tagSpan = $(TagVisualisation.TagCloud.TAG_ELEMENT_ID_PREFIX+tagId);
		}

		attribs = { "class" : TagVisualisation.TagCloud.TAG_ELEMENT_CSS_CLASS
				};
		fontsize = Math.floor(50 * values[tag] / maxValue);
		attribs['style'] = "font-size: "+fontsize+"px;";
		md.updateNodeAttributes(tagSpan, attribs);
	}
	if ( ! container.hasSpacer ) {
		container.appendChild(md.DIV({ "class" : "spacer"}));
		container.hasSpacer = true;
	}

};


TagVisualisation.TagCloud.prototype.registerController = function(controller) {
	controller.attachVisualisation(this);
	this.getDisplayElement().insertBefore(controller.getDisplayElement(),this.getDisplayElement().firstChild);
};


if (typeof(TagVisualisation.TagWeeklyPlot) == 'undefined') {
	TagVisualisation.TagWeeklyPlot = {};
}

TagVisualisation.TagWeeklyPlot = function(tagVisualiser) {
	this._tagVisualiser = tagVisualiser;
	this._initElements();
};

TagVisualisation.TagWeeklyPlot.prototype = {
	__class__: TagVisualisation.TagWeeklyPlot
};

TagVisualisation.TagWeeklyPlot.ELEMENT_CSS_CLASS = "rich_as_tagweeklyplot";
TagVisualisation.TagWeeklyPlot.ELEMENT_ID_PREFIX = "rich_as_tagweeklyplot_";
TagVisualisation.TagWeeklyPlot.WEEKLYPLOT_STYLESHEET_TITLE = "rich_as_tagweeklyplot_styles";
TagVisualisation.TagWeeklyPlot.CANVAS_CSS_CLASS = "rich_as_tagweeklyplot_canvas";
TagVisualisation.TagWeeklyPlot.CANVAS_ID_PREFIX = "rich_as_tagweeklyplot_canvas_";

TagVisualisation.TagWeeklyPlot.prototype._initElements = function() {
	var parentWidth = this._tagVisualiser._getDisplayWidth(
						this._tagVisualiser._dataTableContainer
					);
	var md = MochiKit.DOM;
	this._canvasWidthProportion = this._getCanvasWidthFromStylesheet();
	
	var graphDiv = md.DIV({"class" : TagVisualisation.TagWeeklyPlot.ELEMENT_CSS_CLASS,
							"id"   : TagVisualisation.TagWeeklyPlot.ELEMENT_ID_PREFIX+this._tagVisualiser.datasetName
						  });
	var targetCanvas = md.CANVAS({ "id" : TagVisualisation.TagWeeklyPlot.CANVAS_ID_PREFIX+this._tagVisualiser.datasetName,
					"class" : TagVisualisation.TagWeeklyPlot.CANVAS_CSS_CLASS,
					"width" : this._canvasWidth ? this._canvasWidth : Math.floor(parentWidth * this._canvasWidthProportion),
					"height": this._canvasHeight ? this._canvasHeight : "150"
				});
	graphDiv.appendChild( targetCanvas );
	if (true || CanvasGraph.isSupported(targetCanvas)) {
		this._canvasgraph = new CanvasGraph(targetCanvas);
		this._canvasgraph.originIsZero = false;
	}
	this._targetCanvas = targetCanvas;
	this._displayElement = graphDiv;
	return graphDiv;
};

TagVisualisation.TagWeeklyPlot.prototype.getDisplayElement = function() {
	return this._displayElement;
};


TagVisualisation.TagWeeklyPlot.prototype.update = function(tagsToPlot) {
	// setup the graph
	var parentWidth = this._tagVisualiser._getDisplayWidth(
						this._tagVisualiser._dataTableContainer
					);
//	this._targetCanvas.width = this._canvasWidth ? this._canvasWidth : Math.floor(parentWidth * this._canvasWidthProportion);

	this._canvasgraph.clear();
	
	dataTable = $(this._tagVisualiser.datasetName);

	tableRows = dataTable.getElementsByTagName("tbody")[0].getElementsByTagName("tr");
	maxValue = 100;

	colourArray = [ Color.blueColor(), Color.redColor(), Color.greenColor(), Color.blackColor() ];

	graphcolours = {}
	for (var i = 0; i < tagsToPlot.length ; i++ ) {
		var rowData = $(tagsToPlot[i]);
		dataArray = [];
		for (var j = 0; j < (rowData.getElementsByTagName("td").length - this._tagVisualiser.tagColumn - 2); j++ ) {
			value = parseFloat(rowData.getElementsByTagName("td")[j+this._tagVisualiser.tagColumn+1].childNodes[0].data);
			dataArray[j] = [j+1 , value ];
		}
		this._canvasgraph.setDataset(tagsToPlot[i], dataArray);
		graphcolours[tagsToPlot[i]] = colourArray[i];
	}
	this._canvasgraph.drawLinePlot(graphcolours);
};

TagVisualisation.TagWeeklyPlot.prototype.registerController = function(controller) {
	controller.attachVisualisation(this);
	this.getDisplayElement().appendChild(controller.getDisplayElement());
};

TagVisualisation.TagWeeklyPlot.prototype._getCanvasWidthFromStylesheet = function() {
	var mywidth = 1.0;
	for (var i = 0 ; i < document.styleSheets.length; i++ ) {
		if( ( document.styleSheets[i].href == undefined ) || 
			( document.styleSheets[i].title == TagVisualisation.TagWeeklyPlot.WEEKLYPLOT_STYLESHEET_TITLE) ){
			var therules = document.styleSheets[i].rules ?document.styleSheets[i].rules : document.styleSheets[i].cssRules;
			for (var j = 0 ; j < therules.length; j++) {
				if (therules[j].selectorText.toLowerCase().match("\."+TagVisualisation.TagWeeklyPlot.ELEMENT_CSS_CLASS) ||
					therules[j].selectorText.toLowerCase().match("#"+TagVisualisation.TagWeeklyPlot.ELEMENT_ID_PREFIX+this._tagVisualiser.datasetName) 
				) {
					if ( therules[j].style.cssText.match("\\s+width:\\s*?(\\d+)\%") ) {
						mywidth = parseFloat(RegExp.$1)/100;
					}
					if ( therules[j].style.cssText.match("\\s+width:\\s*?(\\d+)px;") ) {
						mywidth = 0;
						this._canvasWidth = parseInt(RegExp.$1);
					}
					if ( therules[j].style.cssText.match("\\s+height:\\s*(\\d+)px") ) {
						this._canvasHeight = parseInt(RegExp.$1);
					}
				}
			}

		}
	}
	return mywidth;
};

if (typeof(TagVisualisation.TagSelectorController) == 'undefined') {
	TagVisualisation.TagSelector = {};
}

TagVisualisation.TagSelectorController = function(tagVisualiser, numSelects) {
	this._tagVisualiser = tagVisualiser;
	this._initElements(numSelects);
};

TagVisualisation.TagSelectorController.prototype = {
	__class__: TagVisualisation.TagSelectorController,
	visualisations : []
};

TagVisualisation.TagSelectorController.ELEMENT_CSS_CLASS = "rich_as_tagselectorcontroller";
TagVisualisation.TagSelectorController.ELEMENT_ID_PREFIX = "rich_as_tagselectorcontroller_";
TagVisualisation.TagSelectorController.SELECT_CSS_CLASS = "rich_as_tagselectorcontroller_select";
TagVisualisation.TagSelectorController.SELECT_ID_PREFIX = "rich_as_tagselectorcontroller_select_";

TagVisualisation.TagSelectorController.prototype._initElements = function(maxSelects) {
	var md = MochiKit.DOM;
	alltags = this._tagVisualiser.getAllTags();
	sortedtags = new Array();
	for (var tagid in alltags) {
		sortedtags.push(tagid);
	}
	sortedtags.sort();
	var selectshome = md.DIV({
					"id" 	: TagVisualisation.TagSelectorController.ELEMENT_ID_PREFIX+this._tagVisualiser.datasetName,
					"class" : TagVisualisation.TagSelectorController.ELEMENT_CSS_CLASS
					});
	var selects = new Array();
	for ( var i = 0; i < maxSelects; i++ ) {
		var aselect = md.SELECT({
						"class"	: TagVisualisation.TagSelectorController.SELECT_CSS_CLASS,
						"id"    : TagVisualisation.TagSelectorController.SELECT_ID_PREFIX+this._tagVisualiser.datasetName+"_"+i
					   });
		for (var j = 0; j < sortedtags.length; j++) {
			var tagid = sortedtags[j];
			aselect.options[aselect.options.length] = new Option( alltags[tagid],tagid);
		}
		selects.push(aselect);
		selectshome.appendChild(aselect);
		var localthis = this;
		aselect.onchange = function(e) {
			for (var i = 0; i < localthis.visualisations.length; i++ ) {
				localthis.visualisations[i].update(localthis.getValue());
			}
		};

	}
	this._selects = selects;
	this._displayElement = selectshome;
	return selectshome;
}

TagVisualisation.TagSelectorController.prototype.getValue = function() {
	var values = new Array();
	for (var i = 0; i < this._selects.length; i++ ) {
	values.push( this._selects[i].options[this._selects[i].selectedIndex].value);
	}
	return values;
}

TagVisualisation.TagSelectorController.prototype.getDisplayElement = function() {
	return this._displayElement;
}

TagVisualisation.TagSelectorController.prototype.attachVisualisation = function(weeklyplot) {
	this.visualisations.push(weeklyplot);
	weeklyplot.update(this.getValue());
};

if (typeof(TagVisualisation.SliderController) == 'undefined') {
	TagVisualisation.SliderController = {};
}

TagVisualisation.SliderController = function(tagVisualiser) {
	this._tagVisualiser = tagVisualiser;
	this._initElements();
};

TagVisualisation.SliderController.prototype = {
	__class__: TagVisualisation.SliderController,
	visualisations : []
};

TagVisualisation.SliderController.ELEMENT_CSS_CLASS = "rich_as_slidercontroller";
TagVisualisation.SliderController.ELEMENT_ID_PREFIX = "rich_as_slidercontroller_";
TagVisualisation.SliderController.BAR_CSS_CLASS = "rich_as_slidercontroller_bar";
TagVisualisation.SliderController.BAR_ID_PREFIX = "rich_as_slidercontroller_bar_";


TagVisualisation.SliderController.prototype._initElements = function() {
	var md = MochiKit.DOM;
	var numberweeks = this._tagVisualiser._getColumnCount();
	
	var sliderhome = md.DIV({"class"   : TagVisualisation.SliderController.ELEMENT_CSS_CLASS + " slider ",
					 		 "id"      : TagVisualisation.SliderController.ELEMENT_ID_PREFIX+this._tagVisualiser.datasetName,
							 "x2:role" : "role:slider",
							"state:valuenow" : "1",
							"state:valuemin" : "1",
							"state:valuemax" : numberweeks
						  });
	var sliderbar = md.DIV({ "id" 	: TagVisualisation.SliderController.BAR_ID_PREFIX+this._tagVisualiser.datasetName,
							"class" : TagVisualisation.SliderController.BAR_CSS_CLASS + " slider-input "
				});
	sliderhome.appendChild( sliderbar );
	var slider = new Slider( sliderhome, sliderbar );
	slider.setMaximum(numberweeks);
	slider.setMinimum(1);
	this._slider = slider;
	var oThis = this;
	slider.onchange = function(e) {
		for (var i = 0; i < oThis.visualisations.length; i++ ) {
			oThis.visualisations[i].update(oThis.getValue());
		}
	};
	this._displayElement = sliderhome;
	return sliderhome;
};

TagVisualisation.SliderController.prototype.getDisplayElement = function() {
	return this._displayElement;
}

TagVisualisation.SliderController.prototype.attachVisualisation = function(weeklyplot) {
	this.visualisations.push(weeklyplot);
};

TagVisualisation.SliderController.prototype.getValue = function() {
	return this._slider.getValue();
};