/**
 * Javascript Chart Drawing Class 
 * parses an xml diagram definition and draws on an html canvas
 * 
 * copyright Maurizio Tidei & Jürgen Pospischil, 2009
 */
 
var chart = null;
var table = null;

var superglobalFilter = null;

var lastHash = null;
var emptyHashEquivalent = null;
var hashWasSet = false;

 
function Chart() {
	
	this.xAxisName;
	this.xAxisLabels;
	this.yAxisName;
	this.title;
	
	this.type;
	this.series;
	this.seriesNames;
	this.axis;
	this.xmlDoc;
	this.labelWidth;
	this.pixelsPerUnit;
	this.ctx;
	
	this.height = document.getElementById("canvas").height;
	this.width = document.getElementById("canvas").width;
	this.leftSpace;
	this.rightSpace;
	this.bottomSpace;
	this.topSpace;
	this.labelSpacing;
	this.colors = new Array("#007FE8", "#D8A715", "#15D819", "#00C9E7", "#D9E700", "#E70000", "#7700E7");
	
	this.rangeMax;
	this.rangeMin;
	
	this.font = "sans";
	this.fontsize = 8;
	
	this.debug = false;
	
	this.firstDraw = true;
	
	// scrolling horizontally
	this.xScaling = 1;
	this.xOffset = 0;
	
	this.mouseX = -1;
	this.mouseDown = false;
	
	this.dragging = false;
	this.drawing = false;
	
	this.isIE = navigator.userAgent.indexOf("MSIE") > -1;
	
	this.metalAvgPrice = 0;
	this.metalPriceTrend = "";
	this.metalName = "";
	this.metalPostfix = "";
	
	this.init = function() {
		this.leftSpace   = 40;
		this.rightSpace  = 10;
		this.bottomSpace = 28;
		this.topSpace  = 10;
		this.labelSpacing = 10;
	};
	
	this.parseXML = function(xml) {
		
		this.rangeMax = 0;
		this.rangeMin = 0;
		
		this.metalAvgPrice = 0;
		this.metalPriceTrend = "";
		this.metalName = "";
		
		this.xOffset = 0;
		this.xScaling = 1;
		
		if(typeof xml == "string") {
			this.xmlDoc = new XML().parseXML(xml);
		}
		else {
			this.xmlDoc = xml;
		}
		
		var rootNode = this.xmlDoc.getElementsByTagName("chart")[0];
		this.type = rootNode.attributes.getNamedItem("type").value;
		
		this.series = this.xmlDoc.getElementsByTagName("series");
		this.axis = this.xmlDoc.getElementsByTagName("axis");
		
		
		for(var i = 0; i < this.axis.length; i++) {
			var id = this.axis[i].attributes.getNamedItem("id").value;
			var name = this.axis[i].attributes.getNamedItem("name").value;
			var labels = this.axis[i].attributes.getNamedItem("labels");
			if(labels != null) {
				labels = labels.value;
			}
			if(id == "x") {
				this.xAxisLabels = labels.split(";");
				this.xAxisName = name;
			}
			else if(id == "y") {
				this.yAxisName = name;
			}
		}
		
		for(var i = 0; i < this.series.length; i++) {
			var currentSeries = this.series[i];
			var values = currentSeries.attributes.getNamedItem("values").value.split(";");
			
			for(var j in values) {
	        	var valueSet = values[j].split(",");
	        	for(var k = 0; k < valueSet.length; k++) {
	  				var value = parseInt(valueSet[k]);
	  				if(value > this.rangeMax) {
	  					this.rangeMax = value;
	  				}
	  				if(value < this.rangeMin) {
	  					this.rangeMin = value;
	  				}
				}
			}
		}
		
		var metalElement = this.xmlDoc.getElementsByTagName("metal");
		if(metalElement.length > 0) {
			this.metalName = metalElement[0].attributes.getNamedItem("name").value;
			if(metalElement[0].attributes.getNamedItem("average") != null) {
				this.metalAvgPrice = metalElement[0].attributes.getNamedItem("average").value;
			}
			if(metalElement[0].attributes.getNamedItem("values") != null) {
				this.metalPriceTrend = metalElement[0].attributes.getNamedItem("values").value;
			} 
			this.metalPostfix = metalElement[0].attributes.getNamedItem("postfix").value;
		}
	}
	

    this.drawMessage = function() {
    	var canvas = document.getElementById("canvas");
		this.ctx = canvas.getContext("2d");
		// this adds the text functions to the this.ctx
		CanvasTextFunctions.enable(this.ctx);
		
		this.ctx.drawTextRight("", 8, this.width/2, this.height/2, "Updating chart...");
    }

	this.draw = function(dragging) {
		
		this.drawing = true;
		
		this.dragging = dragging ? true : false;
		
		this.init();
		
		var canvas = document.getElementById("canvas");
		canvas.onmousemove = null;

        // check that canvas was initialized for IE, init otherwise
        if ((!canvas.getContext) && (typeof G_vmlCanvasManager != "undefined")) {
          canvas = G_vmlCanvasManager.initElement(canvas);
        }
		
		this.ctx = canvas.getContext("2d");
		this.ctx.clearRect(0,0,this.width,this.height);
		this.ctx.strokeStyle = "rgba(0,0,0,1)"
		
		// this adds the text functions to the context 2d
		CanvasTextFunctions.enable(this.ctx);
		
		if(this.series.length == 0) {
			
			this.ctx.drawText(this.font, 10, this.leftSpace+20, 20, "Keine Daten zu den aktuellen Auswahlkriterien vorhanden.");
		}
		else if(this.type == "bar") {
			this.drawBarChart();
		}
		else if(this.type == "line") {
			this.drawLineChart();
		}
		
		//IE bug workaround: last canvas command is ignored on first draw call...
		if(this.firstDraw && this.isIE) {
			this.ctx.stroke(); 
		}
		
		this.firstDraw = false;
		
		// enable dragging if graph is scaled
		if(this.xScaling > 1) {
		
			canvas.onmousedown = function(e) {
				chart.mouseDown = true;
				chart.mouseX = mouseCoords(e).x;
			}
			
			canvas.onmouseup = function(e) {
				chart.mouseDown = false;
				chart.draw(false);
			}
			
			canvas.onmouseout = function(e) {
				chart.mouseDown = false;
			}
						
			document.onmousemove = function(e) {
				if(chart.mouseDown && !chart.drawing) {
					var mousePos = mouseCoords(e);
					var incr = chart.mouseX - mousePos.x;
					chart.xOffset += incr;
					chart.mouseX = mousePos.x;
					chart.draw(true);
				}
			}
		
			canvas.style.cursor = "move";
		}
		else {
			canvas.onmousedown = null;
			canvas.onmouseup = null;
			canvas.onmouseout = null;
			document.onmousemove = null;
			canvas.style.cursor = null;
		}
		
		this.drawing = false;
	}
	
	this.drawCoordinateSystem = function() {
		
		this.ctx.lineWidth = 1;
		
		// compute width x axis label
		this.labelWidth = Math.floor((this.width-this.leftSpace-this.rightSpace) / this.xAxisLabels.length);
		if(this.labelWidth < 15) {
			this.xScaling = 15 / this.labelWidth;
		}
		this.labelWidth = this.labelWidth * this.xScaling;
		
		// chek if x axis labels have to be drawn diagonally or even vertically
		var drawLabelsDiagonally = false;
		var fontsize = this.fontsize;
		var rotDegree = 45;
		var alternate = false;
		while(this.labelWidth <= fontsize) {
			fontsize--;
		}
				
		if(fontsize <= 7) {
			fontsize++;
			rotDegree = 90; 
			alternate = true;
		}
		
		var maxTextWidth = 0;
		var averageTextWidth = 0;
		for(var i in this.xAxisLabels) {
			var textWidth = this.ctx.measureText(this.font, fontsize, this.xAxisLabels[i]);
			if(maxTextWidth <= textWidth) {
				maxTextWidth = textWidth;
			}
			averageTextWidth += textWidth;
		}
		averageTextWidth = Math.round(averageTextWidth/this.xAxisLabels.length);
		if(maxTextWidth >= this.labelWidth - 5) {
			drawLabelsDiagonally = true;
			if(alternate) {
				this.bottomSpace += Math.round(averageTextWidth + maxTextWidth);
			}
			else {
				this.bottomSpace += Math.round(maxTextWidth * 0.7);
			}
		}
		
		// x axis
		var yzero = this.height - this.bottomSpace - 0.5;
		this.ctx.beginPath();
		this.ctx.moveTo(this.leftSpace, yzero);
		this.ctx.lineTo(this.width-this.rightSpace, yzero);
		this.ctx.stroke();
		
		this.ctx.globalAlpha = 1;
		this.ctx.drawTextRight(this.font, this.fontsize, this.leftSpace-8, yzero, ""+0);
		
		// y axis
		this.ctx.beginPath();
		this.ctx.moveTo(this.leftSpace-0.5, this.height-this.bottomSpace);
		this.ctx.lineTo(this.leftSpace-0.5, this.topSpace);
		this.ctx.stroke();
		
		// compute height per unit
		this.pixelsPerUnit = ((this.height-this.bottomSpace-this.topSpace) / (this.rangeMax - this.rangeMin)) * 0.9;
		
		if(this.dragging && this.isIE) {
			return;
		}
		
		// draw horizontal lines with values
		var value = 0;
		var valueIncrement = Math.round((this.rangeMax - this.rangeMin)/10);
		if(valueIncrement == 0) {
			valueIncrement = 1;
		}
			
		do {
			value += valueIncrement;
			var y = yzero - Math.round(value*this.pixelsPerUnit);
			if(y < this.topSpace) {
				break;
			}
			this.ctx.globalAlpha = 0.15;
			this.ctx.beginPath();
			this.ctx.moveTo(this.leftSpace-5, y);
			this.ctx.lineTo(this.width-this.rightSpace, y);
			this.ctx.stroke();
			
			this.ctx.globalAlpha = 1;
			this.ctx.drawTextRight(this.font, this.fontsize, this.leftSpace-8, y, ""+value);
		}
		while(true);
		
	
		// draw x axis labels
		for(var i in this.xAxisLabels) {
			
			this.ctx.globalAlpha = 1;
			var x = this.labelWidth*i + this.labelWidth/2;
			x = x - this.xOffset;
			
			if(x < 0 || x > this.width) {
				continue;
			}
			
			x = x + this.leftSpace;
			
			if(drawLabelsDiagonally) {
				this.ctx.save();
				var alt = 0;
				if(alternate && i%2==1) {
					alt = averageTextWidth+2;
				}
				this.ctx.translate(x+fontsize/2, this.height-this.bottomSpace+fontsize/2+2+alt);
				this.ctx.rotate((360-rotDegree)*2*3.1416/360);
				this.ctx.drawTextRight(this.font, fontsize, 0, 0, this.xAxisLabels[i]);
				this.ctx.restore();
			}
			else {
				this.ctx.drawTextCenter(this.font, fontsize, x, this.height-this.bottomSpace+10, this.xAxisLabels[i]);
			}
			
			/*
			if(this.series.length > 1 && (i % 2) == 0 && true) { //TODO Parameter
				var x2 = this.leftSpace + this.labelWidth*i - 0.5;
				/*
				this.ctx.globalAlpha = 0.3;
				this.ctx.beginPath();
				this.ctx.moveTo(x2, this.topSpace);
				this.ctx.lineTo(x2, this.height - this.bottomSpace + 5);
				this.ctx.stroke();
				*-/
				/*
				this.ctx.globalAlpha = 0.1;
				this.ctx.fillRect(x2, this.topSpace, this.labelWidth, this.height-this.bottomSpace-this.topSpace);
				*-/
			}
			*/
			
		}
		
		this.ctx.globalAlpha = 0.7;
		// draw x axis name
		this.ctx.drawTextCenter(this.font, 9, this.leftSpace+(this.width-this.leftSpace-this.rightSpace)/2, this.height-5, this.xAxisName);
		
		// draw y axis name characterwise from top to down
		for(var i = 0; i < this.yAxisName.length; i++) {
			this.ctx.drawTextCenter(this.font, 9, 5, (this.height-this.bottomSpace)/2 - this.yAxisName.length/2*12 + i*12 + 12, this.yAxisName.charAt(i));
		}
		this.ctx.globalAlpha = 1;
		
		if(this.debug) {
			document.write(this.labelWidth + " " + this.pixelsPerUnit);
		}
	
	}
	
	this.drawLegend = function() {
		// if more than one series, draw legend
		if(this.series.length > 1 || this.series[0].attributes.getNamedItem("name").value != "sum") {
			
			var x = this.width - this.rightSpace - 40.5;
			var barWidth = 10;
			var barHeight = 10; 
				
			for(var i = 0; i < this.series.length; i++) {
				var name = this.series[i].attributes.getNamedItem("name").value;
				this.ctx.fillStyle = this.getColor(i);
				this.ctx.strokeStyle = this.getColor(i);
				
				var y = this.topSpace + (barHeight+3)*i + 10.5;
				
				this.ctx.globalAlpha = 0.2;
				this.ctx.fillRect(x, y, barWidth, barHeight);
				this.ctx.globalAlpha = 1;
				this.ctx.strokeRect(x, y, barWidth, barHeight);
				this.ctx.drawText(this.font, this.fontsize, x + 15, y + this.fontsize, name);
			}
		}
	}
	
	this.drawMetalRect = function(y) {
		this.ctx.globalAlpha = 0.6;
		this.ctx.strokeRect(this.width - this.rightSpace + 8.5, y - 19, this.rightSpace - 9, 38);
		
		var my_gradient = this.ctx.createLinearGradient(this.width - this.rightSpace + 8.5, y - 19, this.width - this.rightSpace + 8.5 + 20, y + 30);
		
		if(this.metalName.indexOf("Gold") != -1) {
			my_gradient.addColorStop(0, "#FFFFDD");
			my_gradient.addColorStop(0.7, "#FFE770");
			//my_gradient.addColorStop(0.8, "#D4AF37");
			my_gradient.addColorStop(1, "#CCB957");
		}
		else {
			my_gradient.addColorStop(0, "#FFFFFF");
			my_gradient.addColorStop(1, "#999999");
		}
		this.ctx.fillStyle = my_gradient;
		this.ctx.fillRect(this.width - this.rightSpace + 8.5, y - 19, this.rightSpace - 9, 38);
		
		
		this.ctx.globalAlpha = 1;
		if(this.metalAvgPrice != 0) {
			this.ctx.drawText(this.font, 8, this.width - this.rightSpace/2, y - 10, "O");
			this.ctx.drawText(this.font, 8, this.width - this.rightSpace/2, y - 10, "/");
			this.ctx.drawText(this.font, 8, this.width - this.rightSpace + 12, y + 14, this.metalAvgPrice + this.metalPostfix);
		}
		this.ctx.drawTextRight(this.font, 9, this.width - 2, y + 2, this.metalName);		
	}
	
	this.drawLineChart = function() {
		
		this.adjustRightSpace();
		this.drawCoordinateSystem();
		
		if(this.metalPriceTrend != "") {
			this.ctx.fillStyle = "#000000";
			this.ctx.strokeStyle = "#000000";
			var lastY = this.drawLineChartLine(this.metalPriceTrend.split(";"), true);
			this.drawMetalRect(lastY);
		}
		
		// draw lines
		for(var i = 0; i < this.series.length; i++) {
			var currentSeries = this.series[i];
			this.ctx.fillStyle = this.getColor(i);
			this.ctx.strokeStyle = this.getColor(i);
			var values = currentSeries.attributes.getNamedItem("values").value.split(";");
			
			this.drawLineChartLine(values);
		}
		
		this.drawLegend();
	}
	
	this.drawLineChartLine = function(values, light) {
		// draw single data points
		for(var j in values) {
			if(values[j] != "") {
				var valueSet = values[j].split(",");
				var value = valueSet[0];
				var minValue = valueSet[1];
				var maxValue = valueSet[2];
				
				var valuePixels = Math.round(value * this.pixelsPerUnit);
				
			    var x = this.leftSpace + 0.5 + Math.round((parseInt(j)+0.5)*this.labelWidth);
				var y = this.height-valuePixels-this.bottomSpace-0.5;
				
				if(!light) {
					this.ctx.globalAlpha = 0.2;
					this.ctx.fillRect(x-2, y-2, 4, 4);
					this.ctx.globalAlpha = 1;
					this.ctx.strokeRect(x-2, y-2, 4, 4);
				}
				else {
					this.ctx.fillStyle = "#DDDDDD";
					this.ctx.beginPath();
					this.ctx.arc(x, y, 2, 0, Math.PI*2, true)
					this.ctx.fill();
					this.ctx.strokeStyle = "#555555";
					this.ctx.beginPath();
					this.ctx.arc(x, y, 2, 0, Math.PI*2, true)
					this.ctx.stroke();
					//this.ctx.strokeRect(x-1, y-1, 2, 2);
				}
				
				// draw "range"
				if(minValue != null && maxValue != null) {
					this.ctx.globalAlpha = 0.3;
					var minValuePixels = Math.round(minValue * this.pixelsPerUnit);
					var maxValuePixels = Math.round(maxValue * this.pixelsPerUnit);
					var minValueY = this.height-minValuePixels-this.bottomSpace-0.5;
					var maxValueY = this.height-maxValuePixels-this.bottomSpace-0.5;
				
				    // vertical line
					this.ctx.beginPath();
					this.ctx.moveTo(x, minValueY);
					this.ctx.lineTo(x, maxValueY);
					this.ctx.stroke();
					
					// horizontal line at min
					this.ctx.beginPath();
					this.ctx.moveTo(x-3, minValueY);
					this.ctx.lineTo(x+3, minValueY);
					this.ctx.stroke();
					
					// horizontal line at max
					this.ctx.beginPath();
					this.ctx.moveTo(x-3, maxValueY);
					this.ctx.lineTo(x+3, maxValueY);
					this.ctx.stroke();
					this.ctx.globalAlpha = 1;
				}
			}
		}
		
		// draw lines connecting each single data point
		var firstPoint = true;
		this.ctx.beginPath();
		for(var j in values) {
			if(values[j] != "") {
				var valueSet = values[j].split(",");
				var value = valueSet[0];
				var pixelsOverXAxis = Math.round(value * this.pixelsPerUnit);
				
				var x = this.leftSpace + 0.5 + Math.round((parseInt(j)+0.5)*this.labelWidth);
				var y = this.height-pixelsOverXAxis-this.bottomSpace-0.5;
				
				this.ctx.globalAlpha = 0.8;
				if(firstPoint) {
					this.ctx.moveTo(x, y);
					firstPoint = false;
				}
				else {
					this.ctx.lineTo(x, y);
				}
			}
		}
		this.ctx.stroke();
		
		if(light) {
			this.ctx.strokeStyle = "#333333";
			this.drawHorizontalDottedLine(x, y, this.width - this.rightSpace + 8.5)
		}
		
		return y;
	}
	
	this.drawBarChart = function() {
		
		this.adjustRightSpace();
		
		this.drawCoordinateSystem();
		
		if(this.metalAvgPrice != 0) {
			// draw line for average metal price
			var metalAvgPricePixels = Math.round(this.metalAvgPrice * this.pixelsPerUnit);
			var metalAvgPriceY = this.height-metalAvgPricePixels-this.bottomSpace-0.5;
			
			//this.ctx.strokeStyle = this.colors[0];
			this.ctx.globalAlpha = 1;
			
			//this.ctx.beginPath();
			//this.ctx.moveTo(this.leftSpace, metalAvgPriceY);
			//this.ctx.lineTo(this.width - this.rightSpace + 9, metalAvgPriceY);
			//this.ctx.stroke();
			
			this.drawHorizontalDottedLine(this.leftSpace, metalAvgPriceY, this.width - this.rightSpace + 9)
			
			this.drawMetalRect(metalAvgPriceY);
		}
		
		
		
		this.labelSpacing = Math.round(this.labelWidth/6);
		var barWidth = Math.round((this.labelWidth-this.labelSpacing)/this.series.length)-2;
		barWidth = barWidth;
		
		// draw bars
		for(var i = 0; i < this.series.length; i++) {
			var currentSeries = this.series[i];
			//this.ctx.fillStyle = "rgba(0,143,210,0.2)";
			this.ctx.fillStyle = this.getColor(i);
			this.ctx.strokeStyle = this.getColor(i);
			var values = currentSeries.attributes.getNamedItem("values").value.split(";");
			for(var j in values) {
				var barHeight = Math.round(values[j] * this.pixelsPerUnit);
				
				var x = j*this.labelWidth + i*(barWidth+2) + Math.round(this.labelSpacing/2);
				x = x - this.xOffset;
				if(x < 0 || x > (this.width)) {
					continue;
				}
				x = x + this.leftSpace + 0.5;
				var y = this.height-barHeight-this.bottomSpace-0.5;
				
				this.ctx.globalAlpha = 0.25;
				this.ctx.fillRect(x, y, barWidth, barHeight);
				
				this.ctx.globalAlpha = 1;
				this.ctx.strokeRect(x, y, barWidth, barHeight);
			}
		}
		
		this.drawLegend();
	};
	
	this.drawHorizontalDottedLine = function(x, y, endY) {
		var toggle = true;
		for(var x1 = x + 3; x1 < endY; x1 += 3) {
				if(toggle) {
					this.ctx.beginPath();
					this.ctx.moveTo(x1 - 3, y);
					this.ctx.lineTo(x1, y);
					this.ctx.stroke();
				}
				toggle = !toggle;
			}
	}
	
	this.getColor = function(seriesIndex) {
		if(this.colors.length > seriesIndex) {
			return this.colors[seriesIndex];
		}
		else {
			grayValue = seriesIndex - this.colors.length;
			grayValue = grayValue.toString(16);

			
			return "#" + grayValue + grayValue + grayValue + grayValue + grayValue + grayValue;
		}
	};
	
	this.adjustRightSpace = function() {
		if(this.metalName != "") {
			this.rightSpace += this.ctx.measureText(this.font, 9, this.metalName) + 3;
		}
	}
	
	this.main = function() {
		// bar tests
		/*
		this.parseXML("<chart type=\"bar\">" +
		"<axis id=\"x\" name=\"Euro\" labels=\"30-31;31-32;32-33;33-34;34-35\"/>" +
		"<axis id=\"y\" name=\"Anzahl\"/>" +
		"<series name=\"Serie1\" values=\"10;15;20;14;12\"/>" +
		"<series name=\"Serie2\" values=\"11;14;18;15;13\"/>" +
		"<series name=\"Serie3\" values=\"12;13;19;16;9\"/>" +
		"</chart>"
		);
		*/
		
		
		// line tests
		/*
		this.parseXML("<chart type=\"line\">" +
		"<axis id=\"x\" name=\"Date\" labels=\"01.09;02.09;03.09;04.09;05.09\"/>" +
		"<axis id=\"y\" name=\"Preis\"/>" +
		"<series name=\"Serie1\" values=\"10;15;20;14;12\"/>" +
		"<series name=\"Serie2\" values=\"11;14;18;15;13\"/>" +
		"<series name=\"Serie3\" values=\"12;13;19;16;9\"/>" +
		"</chart>"
		);
		*/
		 
		this.parseXML("<result><chart type=\"line\">" +
		"<axis id=\"x\" name=\"Date\" labels=\"01.2009;02.2009;03.2009;04.2009;05.2009;06.2009;07.2009;08.2009;09.2009;10.2009\"/>" +
		"<axis id=\"y\" name=\"Preis\"/>" +
		"<series name=\"Serie1\" values=\"10,8,11;;20,19,21;14,13,15;12,9,16;;;;;15\"/>" +
		"</chart>" +
		"<table>" +
		"<tr><td>test</td><td>test2</td></tr>" +
		"</table>" +
		"</result>"
		);
		
		/* 
		this.parseXML("<chart type=\"line\">" +
		"<axis id=\"x\" name=\"Date\" labels=\"01.2009;02.2009;03.2009;04.2009;05.2009;06.2009;07.2009;08.2009;09.2009\"/>" +
		"<axis id=\"y\" name=\"Preis\"/>" +
		"<series name=\"Serie1\" values=\"10,8,11;;20,19,21;14,13,15;12,9,16;;;;15\"/>" +
		"</chart>"
		);
		*/ 
		

		this.draw();
	};
}

function Table() {
	
	this.xmlDoc;
	this.tableXml;
	
	this.filters;
	this.ids;
	this.rowTexts;
	
	this.sort;
	this.buttons;
	
	this.commonFieldsNames;
	this.commonFieldsValues;
	
	this.count;
	
	this.lastXML;
	this.currentXML;
	
	this.parseXML = function(xml) {
		
		this.lastXML = this.currentXML;
		this.currentXML = xml;
		
		this.commonFieldsNames = null;
		this.commonFieldsValues = null;
		
		if(typeof xml == "string") {
			this.xmlDoc = new XML().parseXML(xml);
		}
		else {
			this.xmlDoc = xml;
		}
		
		this.tableXml = this.xmlDoc.getElementsByTagName("table")[0];
		
		var optionsXml = this.xmlDoc.getElementsByTagName("options")[0];
		this.sort = optionsXml.getAttribute("sort");
		this.buttons = optionsXml.getAttribute("buttons");
		
		var commonFieldsXml = this.xmlDoc.getElementsByTagName("title")[0];
		if(commonFieldsXml != null) {
			this.commonFieldsNames = new Array();
			this.commonFieldsValues = new Array();
			this.count = commonFieldsXml.getAttribute("count");
			commonFieldsXml = commonFieldsXml.getElementsByTagName("field");
			for(var i = 0; i < commonFieldsXml.length; i++) {
				this.commonFieldsNames[i] = commonFieldsXml[i].getAttribute("name");
				this.commonFieldsValues[i] = commonFieldsXml[i].getAttribute("value");
			}
		}
	}
	
	this.create = function() {
		
		this.filters = new Array();
		this.ids = new Array();
		this.rowTexts = new Array();

        var table = document.createElement("table");
        var attr = document.createAttribute("class");
		attr.nodeValue = "tablesorter";
		table.setAttributeNode(attr);
		
		attr = document.createAttribute("cellspacing");
		attr.nodeValue = "1";
		table.setAttributeNode(attr);	
        
        // add the table head
        var tableHead = document.createElement("thead");
        table.appendChild(tableHead);
        
        var tableHeadRow = document.createElement("tr");
        tableHead.appendChild(tableHeadRow);
                
        var tableHeadXml = this.tableXml.getElementsByTagName("thead")[0];
        var tableHeadColsXml = tableHeadXml.getElementsByTagName("th");
        for(var i = 0; i < tableHeadColsXml.length; i++) {
        	var tableHeadColumn = document.createElement("th");
        	var tableHeadColumnText = document.createTextNode(tableHeadColsXml[i].childNodes[0].nodeValue);
        	tableHeadColumn.appendChild(tableHeadColumnText);
        	tableHeadRow.appendChild(tableHeadColumn);   
        	
        	/*if(i == tableHeadColsXml.length-1) {
        		var tableHeadColumn = document.createElement("th");
        		attr = document.createAttribute("class");
				attr.nodeValue = "{sorter:false}";
				tableHeadColumn.setAttributeNode(attr);
        		//var tableHeadColumnText = document.createTextNode(tableHeadColsXml[i].childNodes[0].nodeValue);
        		//tableHeadColumn.appendChild(tableHeadColumnText);
        		tableHeadRow.appendChild(tableHeadColumn);
        	}*/     	
        }
        
        // add the table body
        var tableBody = document.createElement("tbody");
        table.appendChild(tableBody);
                
        var tableBodyXml = this.tableXml.getElementsByTagName("tbody")[0];
        var tableBodyRowsXml = tableBodyXml.getElementsByTagName("tr");
        
        for(var row = 0; row < tableBodyRowsXml.length; row++) {
	        var tableBodyRow = document.createElement("tr");
	        tableBody.appendChild(tableBodyRow);
	        
	        var tableBodyRowColumnXml = tableBodyRowsXml[row].getElementsByTagName("td");
	        var filterXml = tableBodyRowsXml[row].getAttribute("filter");
	        var idXml = tableBodyRowsXml[row].getAttribute("id");
	        if(filterXml != null) {
		        filterXml = filterXml.replace(/greater-than-equal/g, ">=");
		        filterXml = filterXml.replace(/less-than/g, "<");
	        }
	        this.filters[row] = filterXml;
	        this.ids[row] = idXml;
	        
	        for(var i = 0; i < tableBodyRowColumnXml.length; i++) {
	        	var tableBodyColumn = document.createElement("td");
	        	var tableBodyColumnPlainText = tableBodyRowColumnXml[i].childNodes[0].nodeValue;
	        	var tableBodyColumnText = document.createTextNode(" " + tableBodyColumnPlainText);
	        	
	        	if(i == 0 && this.buttons != null) {
		        	var span = document.createElement("span");
		        	span.setAttribute("style", "float:left;");
		        	span.setAttribute("id", "tbfc");
		        	span.appendChild(tableBodyColumnText);
	        	}
	        	        	
	        	tableBodyRow.appendChild(tableBodyColumn);   
	        	
	        	if(i == 0 && this.buttons != null) {
	        		tableBodyColumn.appendChild(span);
	        		this.rowTexts[row] = tableBodyColumnPlainText;
	        		this.addButtons(tableBodyColumn, row);
	        	}     	
	        	else {
	        		tableBodyColumn.appendChild(tableBodyColumnText);
	        	}
	        }
	        
	        
        }
        
        $("#table").empty();
		$("#tabletitle").empty();
		if(this.commonFieldsNames != null) {
			var common = "";
			if(this.commonFieldsNames.length > 0) {
				for(var i = 0; i < this.commonFieldsNames.length; i++) {
					common += this.commonFieldsNames[i] + ":" + this.commonFieldsValues[i];
					if(i < this.commonFieldsNames.length-1) {
						common += " | ";
					}
				}
				
			}
			if(common != "") {
				common = "<br>" + common + "<br>" + this.count + " Datensätze"
			}
			$("#tabletitle").html("<input type='button' onclick='reloadLastTable()' value='< Zurück'/ title='Zurück'>" + common);
		}
		$("#table").append(table);
		//$.tablesorter.defaults.widgets = ['zebra'];
		$.tablesorter.defaults.sortList = eval(this.sort);
		$(table).tablesorter();
	}
	
	this.addButtons = function(tableBodyColumn, row) {
		//var tableBodyColumn = document.createElement("td");
		
		var splittedButtons = this.buttons.split("|");
		for(var i = splittedButtons.length-1; i >= 0; i--) {
			var buttonType = splittedButtons[i];
			var link = document.createElement("a");
			var img = document.createElement("img");
			var marginRight = "0px;";
			if(i == 0 && splittedButtons.length > 1) {
				marginRight = "7px;";
			}
			img.setAttribute("style", "border:0 none;float:right;margin-right:" + marginRight+ ";");
			img.setAttribute("id", "tbimg");
			link.appendChild(img);	
			tableBodyColumn.appendChild(link);

			if(buttonType == "detail") {
				link.setAttribute("href", "javascript:getRecords(" + row + ")");
				link.setAttribute("title", "Einzelne Datensätze anzeigen");
				img.setAttribute("src", "/images/gui/view.png");
			}
			else if(buttonType == "ebay") {
				//link.setAttribute("href", "http://www.goldbarren-silberbarren.de/program/ebay-weiterleitung.php?http://partners.webmasterplan.com/click.asp?ref=490673&site=1382&type=text&tnb=1&diurl=http://cgi.ebay.de/ws/eBayISAPI.dll?ViewItem&item=" + this.getId(row));
				link.setAttribute("href", "http://www.goldbarren-silberbarren.de/program/ebay-weiterleitung.php?http://rover.ebay.com/rover/1/707-53477-19255-0/1?icep_ff3=2&pub=5574857915&toolid=10001&campid=5336399667&customid=Textlink&ipn=psmain&icep_vectorid=229487&kwid=902099&mtid=824&kw=lg&icep_item=" + this.getId(row));
				link.setAttribute("title", "Artikel bei eBay in einem neuen Fenster öffnen");
				link.setAttribute("target","_blank");
				link.setAttribute("rel","nofollow");
				img.setAttribute("src", "/images/gui/ebay.png");
			}
			else if(buttonType == "notify") {
				link.setAttribute("href", "http://www.goldbarren-silberbarren.de/eintrag.php?ID=" + this.getId(row) + "&DESC=" + encodeURIComponent(this.getRowText(row)));
				link.setAttribute("title", "Fragwürdigen Eintrag zur Überprüfung melden");
				img.setAttribute("src", "/images/gui/notify.png");
			}
			
		}
		
		//tableBodyRow.appendChild(tableBodyColumn);
	}
	
	this.getFilter = function(nb) {
		return this.filters[nb];
	}
	
	this.getId = function(nb) {
		return this.ids[nb];
	}
	
	this.getRowText = function(nb) {
		return this.rowTexts[nb];
	}
	
	this.reloadLastTable = function() {
		this.parseXML(this.lastXML);
		this.create();
	}
	
	this.main = function() {
		
		this.parseXML("<result><chart type=\"line\">" +
		"<axis id=\"x\" name=\"Date\" labels=\"01.2009;02.2009;03.2009;04.2009;05.2009;06.2009;07.2009;08.2009;09.2009;10.2009\"/>" +
		"<axis id=\"y\" name=\"Preis\"/>" +
		"<series name=\"Serie1\" values=\"10,8,11;;20,19,21;14,13,15;12,9,16;;;;;15\"/>" +
		"</chart>" +
		"<table>" +
		"<thead><tr><th>Titel1</th><th>Titel2</th></tr></thead>" +
		"<tbody><tr><td>test3</td><td>test4</td></tr><tr><td>test5</td><td>test6</td></tr></tbody>" +
		"</table>" +
		"</result>"
		);
		

		this.create();
	}
}

/**
 * Mouse events
 */

function mouseCoords(ev){
	ev = ev || window.event;
	if(ev.pageX || ev.pageY){
		return {x:ev.pageX, y:ev.pageY};
	}
	return {
		x:ev.clientX,// + document.body.scrollLeft - document.body.clientLeft,
		y:ev.clientY// + document.body.scrollTop  - document.body.clientTop
	};
}

function getHash() {
	var hash = location.hash;
	if(hash.indexOf("#") == -1) {
		hash = "#" + hash;
	}
	return hash;
}
 

/**
 * AJAX
 */
var request = false;

// Request senden
function setRequest(chart, filter, series, period, mode) {
	
	showAjaxLoading(true);
	
	//var chart = new Chart();
	//chart.drawMessage();
	//var canvas = document.getElementById("canvas");
	//var width = canvas.getAttribute("width");
	//var height = canvas.getAttribute("height");
	if(request != false) {
		request.abort();
	}
	
	// Request erzeugen
	if (window.XMLHttpRequest) {
		request = new XMLHttpRequest(); // Mozilla, Safari, Opera
	} else if (window.ActiveXObject) {
		try {
			request = new ActiveXObject('Msxml2.XMLHTTP'); // IE 5
		} catch (e) {
			try {
				request = new ActiveXObject('Microsoft.XMLHTTP'); // IE 6
			} catch (e) {}
		}
	}

	// überprüfen, ob Request erzeugt wurde
	if (!request) {
		alert("Kann keine XMLHTTP-Instanz erzeugen");
		return false;
	} 
	else {
		var url = "http://www.goldbarren-silberbarren.de/charts.php";
		if(document.location.href.indexOf("goldbarren-silberbarren") == -1) {
			url = "http://localhost/PHP-DB/tools/charts.php";
		}
		
		// Request öffnen
		request.open('post', url, true);
		request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		var parameters = 'chart='+chart+'&filter='+encodeURIComponent(filter);
		if(series != null) {
			parameters += '&series='+series;
		}
		if(period != null) {
			parameters += '&period='+period;
		}
		if(mode != null) {
			parameters += '&mode='+mode;
		}  
		request.send(parameters);
		request.onreadystatechange = interpretRequest;
	}
}

function getChart(chart, globalFilter, filter, comparison, period, mode) {
	setRequest(chart, globalFilter + filter, comparison, period, mode);
}

function loadChart(globalFilter, userAction) {
		
	 // if a new hash exists in the url, set selects and tab as defined first
	 var hash = getHash().substring(1);
	 var hashParsed = false;
	 var hashIsEmpty = false;
	 
	 if(hash.length == 0 && emptyHashEquivalent != null && hashWasSet) {
	 	hash = emptyHashEquivalent;
	 	hashIsEmpty = true;
	 }
	 
     if(hash.length > 0 && (lastHash == null || unescape(hash) != unescape(lastHash))) {
     	var valuePairs = hash.split(";");
     	for(var i in valuePairs) {
     		var valuePairString = valuePairs[i];
     		if(valuePairString.indexOf("=") != -1) {
		     	var valuePair = valuePairString.split("=");
		     	var field = valuePair[0];
		     	var value = unescape(valuePair[1]);
		     	if(value.indexOf("|") != -1) {
		     		value = value.split("|");
		     	}
		     	if(field == "__chart") {
		     		var tabs = $('#tabs').tabs();
     				var index = tabs.tabs('option', 'selected');
     				if(index != value) {
     					setTimeout('$("#tabs").tabs("select",'+value+')', 10);
     					return;
     				}
		     	}
		     	else if(field == "mode") {
		     		//TODO
		     	}
		     	else {
			     	var select = $("select[name="+field+"]", $("#tabs"));
			     	if(select != null) {
			     		select.val(value);
			     	}
		     	}
     		}
     	}
     	//lastHash = hash;
     	hashParsed = true;
     }	
	
	 //$("#debug").text($(ui.tab).attr("id"));
	 var tabs = $('#tabs').tabs();
     var index = tabs.tabs('option', 'selected');
     var chartType = $("#chartType > :eq(" + index + ")").attr("id");
     var filter = "";
     var newHash = "__chart=" + index + ";";
     var series = null;
     var period = null;
     var mode = null;
     
     $("select", $("#tabs")).each(function () {
        var field = $(this).attr("name");
        var values = $(this).val();
        if(field == "series") {
            if(values != "*") { 
       	    	series = values;
            }
            newHash += "series=" + values + ";";
        }
        else if(field == "period") {
        	period = values;
        	newHash += "period=" + values + ";";
        }
        else {
           if(values.constructor == Array && values.join(" ").indexOf("*") == -1) {
             	filter += " and " + field + " IN ('" + values.join("','") + "')";
            }
            newHash += field + "=" + values.join('|') + ";";
        }
     });
     
     if($("#cmpToMetal").is(':checked')) {
     	mode = "cmpToMetal"; 
     }
     
     
     if(globalFilter.indexOf(" ") == -1) {
     	globalFilter = 'Beschreibung LIKE \'' + globalFilter + '\'';
     }
     
     superglobalFilter = globalFilter;
     /*
     if(!hashParsed) {
     	if(lastHash != null) {
     		location.hash = newHash;
     	}
     	lastHash = newHash;
     }
     */
     
     if(!hashParsed && hash.length == 0 && emptyHashEquivalent == null) {
     	emptyHashEquivalent = newHash;
     	hashIsEmpty = true;
     } 
     
     // set hash if not parsed
     if(!hashParsed && lastHash != null && !hashIsEmpty) {
	     
	     if(getHash().substring(1) != newHash) {
	     	location.hash = newHash;
	     	//document.title = newHash;
	     	hashWasSet = true;
	     	
	     	if(window.ActiveXObject) {
	     		window.frames["loader"].window.location.search = "?" + newHash;
	     	}
	     }
     }
          
     lastHash = newHash;
     
     if(hashIsEmpty) {
     	lastHash = "";
     }
     
     // google analytics event tracking
     if(userAction == "refresh") {
     	var filterCompressed = filter.substr(4);
     	filterCompressed = filterCompressed.replace("Beschreibung", "");
     	filterCompressed = filterCompressed.replace("Material", "");
     	filterCompressed = filterCompressed.replace("Groesse", "");
     	filterCompressed = filterCompressed.replace("Land", "");
     	filterCompressed = filterCompressed.replace("Reinheit", "");
     	filterCompressed = filterCompressed.replace("Glanz", "");
     	filterCompressed = filterCompressed.replace("Anstalt", "A:");
     	
     	filterCompressed = filterCompressed.replace(/ IN /g, "");
     	filterCompressed = filterCompressed.replace(/ and /g, "");
     	
     	var seriesMod = series == null ? "-" : series;
     	if(typeof(pageTracker) != "undefined") {
     		pageTracker._trackEvent('Charts','Refresh', chartType.substr(5,3) + " | " + globalFilter.substr(18) + " | " + filterCompressed + " |s:" + seriesMod + " |p:" + period);
     	}
     }
     
     getChart(chartType, globalFilter, filter, series, period, mode);
}

function getRecords(id) {
	
	var filter = table.getFilter(id);
	
	var series = null;
	var period = null;
    $("select", $("#tabs")).each(function () {
       var field = $(this).attr("name");
       var values = $(this).val();
       if(field == "series") {
       	   if(values != "*") { 
      	    	series = values; 
           }
       }
       else if(field == "period") {
           period = values;
       }
       else {
           if(values.constructor == Array && values.join(" ").indexOf("*") == -1) {
             	filter += " and " + field + " IN ('" + values.join("','") + "')";
           }
       }
    });
         
	setRequest("singleRecords", superglobalFilter + " AND " + filter, null, period);
}

function reloadLastTable() {
	table.reloadLastTable();
}

// Request auswerten
function interpretRequest() {
	switch (request.readyState) {
		// wenn der readyState 4 und der request.status 200 ist, dann ist alles korrekt gelaufen
		case 4:
			if (request.status != 200) {
				//alert("Der Request wurde abgeschlossen, ist aber nicht OK\nFehler:"+request.status);
			} else {
				//var content = request.responseText;
				// den Inhalt des Requests in das <div> schreiben
				//document.getElementById('content').innerHTML = content;
				
				showAjaxLoading(false);
				
				// Antwort des Servers -> als XML-Dokument
			    var xmlDoc	= request.responseXML;
			    if(xmlDoc.getElementsByTagName("chart").length > 0) {
					if(chart == null) {
						chart = new Chart();
					}
					chart.parseXML(xmlDoc);
					chart.draw();
			    }
			    if(xmlDoc.getElementsByTagName("table").length > 0) {
			    	if(table == null) {
			    		table = new Table();
			    	}
			    	table.parseXML(xmlDoc);
			    	table.create();
			    }
			}
			break;
		default:
			break;
	}
}
 
function showAjaxLoading(show) {
	if(show) {
		var position = $("#canvas").offset();
		//var height = $("#canvas").height();
		var width = $("#canvas").width();
		position.left += width/2 - 50;
		position.top += 70;
		$("#tabs").append("<div class='ajax_loader' style='position:absolute; left:" + position.left + "px; top:" + position.top + "px;background-image: url(/images/gui/transp50.png);padding:15px;border:1px solid #DDDDDD;'><img src='/images/gui/ajax-loader.gif'> loading ...</div>");
	}
	else {
		$(".ajax_loader").each(function (i) {$(this).remove();});
	}
}

// Workaround for browser navigation
window.setInterval(
	function() {
			var hash = getHash().substring(1);
			//alert(unescape(hash) + "~~~\n" + unescape(lastHash));
			//quick fix, TODO!
			if(lastHash != null && unescape(hash) != unescape(lastHash) && hash != "__chart=0;period=6") {
				showChart();
			}
	},300); 



/**
 * Start of XML methods
 */
function XML() {
	this.newDocument = function(rootTagName, namespaceURL) {
	    if (!rootTagName) rootTagName = "";
	    if (!namespaceURL) namespaceURL = "";
	
	    if (document.implementation != null && document.implementation.createDocument != null) {
	        // This is the W3C standard way to do it
	        return document.implementation.createDocument(namespaceURL, 
	                       rootTagName, null);
	    }
	    else { // This is the IE way to do it
	        // Create an empty document as an ActiveX object
	        // If there is no root element, this is all we have to do
	        var doc = new ActiveXObject("MSXML2.DOMDocument");
	
	        // If there is a root tag, initialize the document
	        if (rootTagName) {
	            // Look for a namespace prefix
	            var prefix = "";
	            var tagname = rootTagName;
	            var p = rootTagName.indexOf(':');
	            if (p != -1) {
	                prefix = rootTagName.substring(0, p);
	                tagname = rootTagName.substring(p+1);
	            }
	
	            // If we have a namespace, we must have a namespace prefix
	            // If we don't have a namespace, we discard any prefix
	            if (namespaceURL) {
	                if (!prefix) prefix = "a0"; // What Firefox uses
	            }
	            else prefix = "";
	
	            // Create the root element (with optional namespace) as a
	            // string of text
	            var text = "<" + (prefix?(prefix+":"):"") + tagname +
	                (namespaceURL
	                 ?(" xmlns:" + prefix + '="' + namespaceURL +'"')
	                 :"") +
	                "/>";
	            // And parse that text into the empty document
	            doc.loadXML(text);
	        }
	        return doc;
	    }
	};
	
	this.parseXML = function(text) {
	    if (typeof DOMParser != "undefined") {
	    	// Mozilla, Firefox, and related browsers
	        return (new DOMParser()).parseFromString(text, "application/xml");
	    }
	    else if (typeof ActiveXObject != "undefined") {
	    	// Internet Explorer.
	        var doc = new XML().newDocument( );   // Create an empty document
	        doc.loadXML(text);              //  Parse text into it
	        return doc;                     // Return it
	    }
	    else {
			// As a last resort, try loading the document from a data: URL
	        // This is supposed to work in Safari. Thanks to Manos Batsis and
	        // his Sarissa library (sarissa.sourceforge.net) for this technique.
	        var url = "data:text/xml;charset=utf-8," + encodeURIComponent(text);
	        var request = new XMLHttpRequest();
	        request.open("GET", url, false);
	        request.send(null);
	        return request.responseXML;
	    }
	};
}
