//-------------------------------------------------------some chart utilities--------------------------

	function debugOut(msg){
		var el = document.getElementById('debug');
		if(el)
			el.innerHTML = msg;
	}

	var kc_XMLReq; //use globally
	var kc_currentChart; 

	/**
	  OK, we have to fake some threading management here since the HTTP stuff runs asynchronously.  We need to make
	  sure the current chart in process (kc_currentChart) has completed before we start processing another one.
	  This is because the HTTP management can't be pushed into an object cleanly, and we need to keep track of which
	  chart is in process to get the MAP and the IMG content into the correct IDs.

	  So what we do is set "kc_currentChart" to the chart in process, and then call a "run" method. Run processes
	  the currentChart, then replaces it with the next chart in the queue when currentChart has been set to null
	  by the HTTP process finalization.  A setTimeout in run manages this thread simulation

	  Bah.
	  **/
	function kc_builderQueue_run(){
		//note: we're using kc_builderQueue instead of this, because the object gets lost in setTimeout
		kc_builderQueue.isRunning = true;
		if(kc_currentChart==null&&kc_builderQueue.counter>0){
			var chart = kc_builderQueue.pop();
			chart.loadMapXML(chart.generator + '?' + chart.args);
		}else if(kc_builderQueue.counter>0){
			setTimeout(kc_builderQueue.run, 100); //try again in a tenth of a sec
		}
		kc_builderQueue.isRunning = false;
	}

	function kc_addToQueue(chart){
		this.charts[this.counter] = chart;
		this.counter++;
		if(this.counter==this.charts.length){
			var newCharts = new Array(this.charts.length*2);
			for(var i=0;i<this.counter;i++){
				newCharts[i] = this.charts[i];
			}
			this.charts = newKeys;
		}
		if(!this.isRunning)
			this.run();
	}
	function kc_getFromQueue(){
		var chart = this.charts[0];
		for(var i=0;i<this.counter;i++){
			this.charts[i] = this.charts[i+1];
		}
		this.charts[this.counter] = null;
		this.counter--;
		return chart;
	}

	function kc_builderQueue_init(){
		this.charts = new Array(20);
		this.counter = 0;
		this.push = kc_addToQueue;
		this.pop = kc_getFromQueue;
		this.run = kc_builderQueue_run;
		this.isRunning = false;
	}

	function kc_BuilderQueue(){
	}

	var kc_builderQueue = new kc_BuilderQueue();
	kc_BuilderQueue.prototype.init = kc_builderQueue_init;
	kc_builderQueue.init();

	function kc_loadMapXML(url) {

		kc_currentChart = this;
    		if (window.XMLHttpRequest) {
        		kc_XMLReq = new XMLHttpRequest();
        		kc_XMLReq.onreadystatechange = kc_processXMLMap;
        		kc_XMLReq.open("GET", url, true);
        		kc_XMLReq.send(null);
    		} else if (window.ActiveXObject) {
        		kc_XMLReq = new ActiveXObject('Microsoft.XMLHTTP');
        		if (kc_XMLReq) {
            			kc_XMLReq.onreadystatechange = kc_processXMLMap;
            			kc_XMLReq.open('GET', url, true);
            			kc_XMLReq.send();
        		}
    		}
	}

	function kc_processXMLMap() {
		if(!kc_currentChart)
			return;
    		if (kc_XMLReq.readyState == 4) {
       		// only if "OK"
		try{
			var response = kc_XMLReq.responseText;
			response = response.substring(response.indexOf('>') + 1);
			response = response.substring(0, response.indexOf('</MAP>'));
			var map = kc_currentChart.linkmap;
			response = kc_translateLinkMap(response);
			if(map)
				map.innerHTML = response;
			if(kc_currentChart.image){
				var args = kc_currentChart.args + 'XXX';
				kc_currentChart.image.src = kc_currentChart.generator + '?' + args;
			}
			kc_currentChart = null; //important for the queue activity
		} catch(e) {
               		var msg = (typeof e == "string") ? e : ((e.message) ? e.message : "Unknown Error");
               		alert("Unable to get XML data:\n" + msg);
			kc_currentChart = null;
               		return;
          		}
		}
	}

	function properties_getProperty(key){
		for(var i=0;i<this.keys.length;i++){
			if(key == this.keys[i])
				return this.values[i];
		}
	}

	function properties_setProperty(key, value){
		this.keys[this.counter] = key;
		this.values[this.counter] = value;
		this.counter++;
		if(this.counter==this.keys.length){
			var newKeys = new Array(this.keys.length*2);
			var newValues = new Array(this.keys.length*2);
			for(var i=0;i<this.counter;i++){
				newKeys[i] = this.keys[i];
				newValues[i] = this.values[i];
			}
			this.keys = newKeys;
			this.values = newValues;
		}
	}

	function properties_init(){
		this.keys = new Array(20);
		this.values = new Array(20);
		this.counter = 0;
		this.getProperty = properties_getProperty;
		this.setProperty = properties_setProperty;
	}

	function kc_Properties(){
	}
	new kc_Properties();
	kc_Properties.prototype.init = properties_init;

	function kc_setProperty(key, value){
		this.props.setProperty(key, value);
	}

	function kc_getProperty(key){
		return this.props.getProperty(key);
	}

	function kc_generate(){
		try{
		window.status = 'drawing chart...';
		}catch(ignored){}
		var args = '';
		var d = new Date();
		args += 't=' + d.getTime();
		for(var i=0;i<this.props.keys.length;i++){
			if(!this.props.keys[i])
				break;
			args += this.props.keys[i];
			args += '=';
			args += escape(this.props.values[i]);
			args += '&';
		}
		if(this.useToolTips){
			args += 'im=t';
			this.args = args;
			kc_builderQueue.push(this);
		}else if(this.image){
			this.image.src = this.generator + '?' + args;
		}else
			return this.generator + '?' + args;
		try{
		window.status = ''
		}catch(ignored){}
	}

	function kc_accumulateProperty(key, value){
		for(var i=0;i<this.props.keys.length;i++){
			if(this.props.keys[i]==key){
				this.props.values[i] += ',' + value;
				return;
			}
		}
		this.setProperty(key, value);
	}

	function kc_setDataProvider(response){
 		var datasets = response.responseXML.getElementsByTagName("dataset");
		if(!datasets)
			return;
    		for (var i = 0; i < datasets.length; i++) {
	    		var name = datasets[i].getAttribute('name'); 
			if(name)
				this.setProperty('dataset' + i + 'name', name);
	    		var dataItems = datasets[i].getElementsByTagName('datum'); 
	    		for(var j=0;j<dataItems.length;j++){
		    		var y = dataItems[j].getAttribute('y');
		    		var lab = dataItems[j].getAttribute('label');
		    		var x = dataItems[j].getAttribute('x');
		    		this.accumulateProperty('dataset' + i + 'yValues', y);
				if(x)
		    			this.accumulateProperty('dataset' + i + 'xValues', x);
		    		this.accumulateProperty('dataset' + i + 'Labels', lab);
	    		}
    		}
	}

	function kc_init(){
		this.generator = '/servlet/AjaxChartStream';
		this.props = new kc_Properties();
		this.props.init();
		this.setProperty = kc_setProperty;
		this.getProperty = kc_getProperty;
		this.accumulateProperty = kc_accumulateProperty;
		this.generate = kc_generate;
		this.loadMapXML = kc_loadMapXML;
		this.image = null;
		this.linkmap = null;
		this.setDataProvider = kc_setDataProvider;
	}

	function Chart(){
	}

	new Chart();
	Chart.prototype.init = kc_init;


	function kc_translateLinkMap(inStr){
		var arr = inStr.split('alt');
		var newStr = '';
		for(var i=0;i<arr.length-1;i++){
			newStr += arr[i];
			var tooltipStr = kc_getTooltipStr(arr[i+1]);
			newStr += tooltipStr + ' x';
		}
		newStr += arr[arr.length-1];

		var arr = newStr.split('title');
		newStr = '';
		for(var i=0;i<arr.length-1;i++){
			newStr += arr[i];
			newStr += 'nothing';
		}
		newStr += arr[arr.length-1];

		return newStr;
	}

	function kc_getTooltipStr(inStr){
		var s = inStr.substring(2);
		s = s.substring(0, s.indexOf('"'));
		var arr = s.split('\n');
		s = '';
		for(var i=0;i<arr.length-1;i++){
			s += arr[i];
			s += '<br>';
		}
		s += arr[arr.length-1];

		return 'onMouseout="kc_clearTooltip()" onMousemove="kc_tooltip(\'' + s + '\', event)"';
	}

	function kc_clearTooltip(){
		var el = document.getElementById('kc_tooltip');
		if(el)
			el.style.visibility = 'hidden';
	}

	function kc_tooltip(s, evt){
		var el = document.getElementById('kc_tooltip');
		if(el){
			if(el.style.visibility == 'hidden'){
				el.innerHTML = s;
				el.style.zIndex = '10000';
				el.style.position = 'absolute';
				el.style.border = 'solid 1px #000000';
				el.style.padding = '3px';
				el.style.backgroundColor = '#ccccff';
				el.style.visibility = 'visible';
				el.style.fontSize = '10pt';
			}
			var posX = 0;
			var posY = 0;
			var e = evt ? evt : window.event;
			if(e.pageX||e.pageY){
				posX = e.pageX;
				posY = e.pageY;
			}else if(e.clientX || e.clientY){
				posX = e.clientX + document.body.scrollLeft;
				posY = e.clientY + document.body.scrollTop;
			}
			if(window.event){
				var scrollTop = 0;
				if(document.documentElement)
					scrollTop = document.documentElement.scrollTop;
				else
					scrollTop = document.body.scrollTop;
				el.style.posTop = posY  + scrollTop - (el.clientHeight + 10);
				el.style.posLeft = posX - (el.clientWidth + 10);

			}else{
				el.style.top = posY - (el.clientHeight + 10) + 'px';
				el.style.left = posX - (el.clientWidth + 10) + 'px';
			}
		}
	}

//-------------------------------------------------------------------------------------------------------------
