function dspChart_GetChartHtml(oSetting, sWPQ) {
	var oParam = new Object;
	oParam.UseImg = (document.location.protocol.substr(0,4) == "http");
	oParam.SerieLegend = new Object;
	switch (oSetting.SerieLegendPosition) {
		case 1: oParam.SerieLegend.HtmlObject = document.all("oDSP" + sWPQ + "LegendTop"); break;
		case 2: oParam.SerieLegend.HtmlObject = document.all("oDSP" + sWPQ + "LegendRight"); break;
		case 3: oParam.SerieLegend.HtmlObject = document.all("oDSP" + sWPQ + "LegendBottom"); break;
		default: oParam.SerieLegend.HtmlObject = null; break;
	}
	with (oSetting) {
		oParam.MasterTextDiv = dspUtil_CreatedivTextWidth(sWPQ + "divMasterText", "dsp-chartlegend-x");
		oParam.XAxisFont = new dspChart_Text("x", oParam.MasterTextDiv, "A", 0, 0);
		oParam.YAxisFont = new dspChart_Text("y", oParam.MasterTextDiv, "A", 0, 0);
		oParam.SAxisFont = new dspChart_Text("s", oParam.MasterTextDiv, "A", 0, 0);
		oParam.XItems = RowHeader;
		oParam.SerieItems = ColHeader;
		oParam.Values = ((ChartType == 7)?dspChart_CopyValueArray(Values):Values);
		oParam.MinValue = (YAxisScaleMin=='null')?null:YAxisScaleMin;
		oParam.MaxValue = (YAxisScaleMax=='null')?null:YAxisScaleMax;
		oParam.YAxisUnits = (YAxisUnits=='null')?null:YAxisUnits;
		oParam.YAxisNumFormat = FormatString;
		oParam.WebPartWidth = WebPartWidth;
		oParam.WebPartHeight = WebPartHeight;
		oParam.SerieColor = SerieColor;
		oParam.FillOpacity = FillOpacity;
		oParam.LineOpacity = LineOpacity;
		oParam.ChartType = ChartType;
		oParam.DisplayLegend = ((DispAxisValueSerie)?1:0) + ((DispAxisValueCategory)?2:0) + ((SerieLegendPosition!=0)?4:0);
		oParam.SerieLegend.Position = SerieLegendPosition;
		oParam.DrawPoint = DrawPoint;
		oParam.LineWidth = LineWeight;
		oParam.XLegendOrientation = XLegendOrientation;
		oParam.XLegendPosition = XLegendPosition;
		oParam.XLegendCutMode = XLegendCutMode;
		oParam.XLegendCntMode = XLegendCntMode;
		oParam.XLegendWordWrap = XLegendWordWrap;
		oParam.DisplaySerieLegendCount = DisplaySerieLegendCount;
		oParam.PointerColor = PointerColor;
		oParam.BorderColor = BorderColor;
		oParam.BarSerieCount = CombChartColCount;
		oParam.Action = new dspChart_InitActionProps(oSetting);
	}
	var s= "";
	if (oParam.ChartType == 6 || oParam.ChartType == 7) {
		var oSelector = document.all("oDSP" + sWPQ + "SerieSelector")
		var iSerieIndex = oSelector.CurrentIndex * oSelector.SerieSelectorStep;
	}
	switch (oParam.ChartType) {
	case 6:
		s = dspChart_BuildPieChart(oParam, iSerieIndex);
		break;
	case 7:
		if (oSetting.LayoutVersion == 400)
			s = "<span>This Gauge needs to be reconfigured, please read the help for information how to configure the Gauge.</span>"; 
		else
			s = dspChart_DrawGauge(oParam, iSerieIndex);
		break;
	default:
		s = dspChart_BuildChart(oParam);
		break;
	}
	return s;
}

function dspChart_BuildChart(oParam) {
	var strLineDot = "", iBarCount=0, iLineCount=0, iBarIndex=0;
	var iXCount = oParam.XItems.length;
	var iYCount = oParam.SerieItems.length;

	if (oParam.ChartType == 1) {iBarCount=iYCount;}
	if (oParam.ChartType == 2) {iLineCount=iYCount;}
	if (oParam.ChartType == 3) {iBarCount=Math.max(1, Math.min(iYCount, oParam.BarSerieCount));iLineCount=iYCount;}
	if (oParam.ChartType == 4) {iLineCount=iYCount;}
	if (oParam.ChartType == 5) {iBarCount=iYCount;}

	var oGraph = new dspChart_GraphProperties(oParam, iYCount, iXCount, iBarCount);
	var strOut = dspChart_DrawGraphArea(oParam.WebPartWidth, oParam.WebPartHeight);

	if(oGraph.ChartType != 4)
		strOut += dspChart_DrawAxes(oGraph, oParam.BorderColor);

	if (oGraph.Max != 0) {
		if (iBarCount>0) {
			for (var i=0; i < iXCount; i++) {
				for (var j=0;j<iBarCount;j++) {
					oBar = new dspChart_BarProperties(oGraph, oParam.Values[j][i], oParam.SerieColor, oParam.SerieItems, oParam.XItems[i], i, j, iBarCount, iBarIndex++, iXCount, oParam.BorderColor, oParam.FillOpacity);
					strOut += dspChart_DrawBar(oBar);
				}
			}
			oGraph.LastBarPos = 0;
			oGraph.LastBarNeg = 0;
			oGraph.LastUsedBar = 0;
			if ((oParam.DisplayLegend & 2) > 0)
				strOut += dspChart_DrawXLegend(oGraph, oBar, j, oParam.XItems, iXCount); 
			oGraph.LastBarLeft = 0;
		}
		if (iLineCount > 0) {
			for (var i=iBarCount;i<iLineCount;i++) {
				var oLine = new dspChart_LineProperties(oGraph, oParam.Values, oParam.SerieColor, oParam.SerieItems[i], oParam.XItems, i, oParam.ChartType, oParam.LineWidth, oParam.LineOpacity, oParam.BorderColor, oParam.FillOpacity);
				if (oGraph.ChartType == 3 || oGraph.ChartType == 2)
					strOut += dspChart_DrawLine(oLine, iXCount);
				else
					strOut += dspChart_DrawArea(oLine, iXCount);
				strLineDot += dspChart_DrawPoint(oGraph, oLine, iXCount, oParam.DrawPoint);
			}
			if (((oParam.DisplayLegend & 2) > 0) && oGraph.ChartType != 3)
				strLineDot += dspChart_DrawXLegend(oGraph, oLine, j, oParam.XItems, iXCount);			
		}
	}

	strOut += strLineDot;

	if(oGraph.ChartType == 4)
		strOut += dspChart_DrawAxes(oGraph, oParam.BorderColor);
	if ((oParam.DisplayLegend & 1) > 0)
		strOut += dspChart_DrawYLegend(oGraph);

	if ((oParam.DisplayLegend & 4) > 0)
		dspChart_ShowSerieLegend(oGraph, oParam);

	return strOut + "</v:group>";
}

function dspChart_InitPieSliceLegend(oParam) {
	this.LegendCount = 0;
	this.NonEmptyLegendExists = false;
	this.SerieLegendHTML = "";
	this.SerieLegendPosition = oParam.SerieLegend.Position;
	this.DisplaySerieLegendCount = 0;
	this.XAxisFont = oParam.XAxisFont;
	this.YAxisFont = oParam.YAxisFont;
	this.SAxisFont = oParam.SAxisFont;
}

function dspChart_BuildPieChart(oParam, iSerieIndex) {
	var iXCount = oParam.XItems.length, sSlices = "";
	var i, iLeft=0,iSize, iStart=5898230, strOut="", sTitle, iValue, sTitle, iTotal=0, oText;
	var oGraph = new dspChart_InitPieSliceLegend(oParam);
	var iRadie = Math.min(oParam.WebPartWidth, oParam.WebPartHeight);
	var sCoordPath = "coordsize='" + (iRadie*2) + "," + (iRadie*2) + "' path='m " + iRadie + " " + iRadie + " ae " + iRadie + " " + iRadie + " " + Math.floor(iRadie*0.9) + " " + Math.floor(iRadie*0.9) + " ";
	for (i=0;i<iXCount;i++)
		iTotal += Math.abs(oParam.Values[iSerieIndex][i]);
	iSize = ((iTotal*(360/iTotal))*65536);

	var sOutLine = "<v:shape style='z-index:0;position:relative;width:" + (iRadie) + "px;height:" + (iRadie) + "px' filled='false' stroked='true' strokecolor='" + oParam.BorderColor + "' strokeweight='1pt' " +
				   sCoordPath + Math.floor(iStart) + " " + Math.floor(iSize) + " x e'></v:shape>";
	for (i=0;i<iXCount;i++) {
		var oCellAction = new dspChart_CellActionInfo(oParam.Action, oParam.Values[iSerieIndex][i].CellId, "pie");
		var oValue = oParam.Values[iSerieIndex][i];
		if (oValue.ForeColor!=null)
			sColor = oValue.ForeColor;
		else
			sColor = dspChart_GetSerieColor(oParam.SerieColor, i);	
		iValue = oValue;
		dspChart_AddToSerieLegend(oGraph, oParam.Action, oParam.XItems[i].MemberId, oParam.XItems[i] + " (" + oParam.Values[iSerieIndex+1][i].Formatted + ")" , sColor, oParam.XItems[i].Tooltip);
		sTitle = oParam.XItems[i] + " : " + oParam.Values[iSerieIndex][i].Formatted + " (" + oParam.Values[iSerieIndex+1][i].Formatted + ")" + oCellAction.Description;
		iSize = ((Math.abs(iValue)*(360/iTotal))*65536);
		if (iSize > 0) {
			sSlices += "<v:shape title='" + sTitle + "'" + oCellAction.LineCommand + 
				" style='z-index:" + i*((iStart>19233380)?-1:1) + ";" + 
				"flip:x;position:relative;left:" + iLeft + ";" + 
				"width:" + (iRadie) + "px;height:" + (iRadie) + "px'" + 
				" stroked='false' strokecolor='" + oParam.BorderColor + "' strokeweight='1pt' " + 
				" fillcolor='" + sColor + "' " + sCoordPath + Math.floor(iStart) + " " + Math.floor(iSize) + " x e'>" + 
				"<v:fill opacity='" + oParam.FillOpacity + "%'/>" + 
				"</v:shape>";
			iStart += iSize;
		}
	}
	var sSliceGroup = dspChart_DrawGraphArea(iRadie, iRadie) + sSlices + sOutLine + "</v:group>";
	dspChart_ShowSerieLegend(oGraph, oParam);
	return sSliceGroup;
}

function dspChart_DrawGauge(oParam, iSerieIndex) {
	var oValue = new dspChart_GaugeCalculate(oParam, iSerieIndex);
	var oG = new dspChart_GaugeProperties(oParam, oValue);
	var s = "<v:group style='width:" + oG.WidthPx + "px;height:"  + oG.HeightPx + "px' coordorigin='0,0' coordsize='" + oG.CoordWidth + "," + oG.CoordHeight + "'>";
	s += "<v:arc style='position: absolute; top: " + oG.LabelHeight + "; left:" + oG.LabelWidth + ";visibility: visible; width: " + 2*oG.Radius + "; height: " + 2*oG.Radius + ";' startangle='-90' endangle='90' stroked='true' strokecolor='" + oParam.BorderColor + "' filled='false'/>";
	s += "<v:line from='" + oG.LabelWidth + ", " + (oG.Origo.y) + "' to='" + (oG.Origo.x + oG.Radius) + "," + (oG.Origo.y) + "' strokecolor='" + oParam.BorderColor + "' strokeweight='1pt'/>";
	s += "<v:arc fillcolor='silver' style='position: absolute; top: " + (oG.Origo.y - oG.InnerRadius) + " ;left: " + (oG.Origo.x - oG.InnerRadius) + ";visibility: visible; width: " + (2*oG.InnerRadius) + "; height: " + (2*oG.InnerRadius) + "; z-index: 100' startangle='-90' endangle='90' opacity='1.0' stroked='true' strokecolor='#696969' strokeweight='0.75pt' filled='true' fillcolor='silver'></v:arc>";
	s += "<v:arc style='position: absolute; top: " + (oG.Origo.y - oG.PointRadius) + ";left: " + (oG.Origo.x - oG.PointRadius) + ";visibility: visible; width: " + (2*oG.PointRadius) + "; height: " + (2*oG.PointRadius) + "; z-index: 101' startangle='-90' endangle='90' opacity='1.0' stroked='true' strokecolor='#696969' strokeweight='1pt' filled='true' fillcolor='#696969'/>"
	var iSectorCount = oParam.Values[iSerieIndex].length;
	for(var iSector = oValue.PointerCount+1; iSector < iSectorCount; iSector++) {
		var iSectorMin = oParam.Values[iSerieIndex][iSector-1];
		var iSectorMax = oParam.Values[iSerieIndex][iSector];
		var pmin = dspChart_GaugeGetArcPoint(iSectorMin,oValue.Min,oValue.Max,oG,0);
		var pmax = dspChart_GaugeGetArcPoint(iSectorMax,oValue.Min,oValue.Max,oG,0);
		var sTooltip = ((iSector>2&&iSector<(iSectorCount-1))?iSectorMin.Formatted + " <= ":"") + oParam.XItems[iSector] + ((iSector<(iSectorCount-1))?" < " + iSectorMax.Formatted:" >= " + iSectorMin.Formatted);
		var sColor = (iSectorMax.ForeColor!=null)?iSectorMax.ForeColor:oParam.SerieColor[iSector-1];
		s += "<v:shape title='" + sTooltip + "' style='position: absolute; top: 0;left: 0; width:100%;height:100%; z-index: 50' stroked='false' fillcolor='" + sColor + "'>";
		s += "<v:path stroked='false' v='wr " + (oG.Origo.x - oG.Radius) + "," + (oG.Origo.y - oG.Radius) + ", " + (oG.Origo.x + oG.Radius) + ", " + (oG.Origo.y + oG.Radius) + ", " + pmin.x  + ", " + pmin.y + ", " + pmax.x  + "," + pmax.y  + " l " + oG.Origo.x + ", " + oG.Origo.y + "," + pmin.x  + ", " + pmin.y  + "  e'/>";
		s += "<v:fill opacity='" + oParam.FillOpacity + "%'/>"; 
		s += "</v:shape>";    
	}
	if ((oParam.DisplayLegend & 1) > 0) {
		var fValue, p1, p2, p3;
		if (oParam.XLegendPosition == 1) {
			for(var iSector = oValue.PointerCount+1; iSector < (iSectorCount+1); iSector++) {
				fValue = (iSector<iSectorCount)?oParam.Values[iSerieIndex][iSector-1]:oValue.Max;
				p1 = dspChart_GaugeGetArcPoint(fValue, oValue.Min, oValue.Max, oG, 0);
				p3 = dspChart_GaugeLabelPosition(p1, oG);
				s += "<v:shape id='rect01' coordorigin='0 0' coordsize='200 200' filled='false' stroked='false' style='z-index: 300;top:" + p3.y + ";left:" + p3.x + ";width:" + oG.LabelWidth + ";height:" + oG.LabelHeight + "'>" +
					"<v:path id= 'mypath' v='m 1,1 l 1,200, 200,200, 200,1 x e' textboxrect='0 0 200 200'/>" +
					"<v:textbox inset='0 0 0 0' style='text-align: " + (p3.Angle < 0 ? "right" : (p3.Angle > 0 ? "left" : "center")) + "'><span class='dsp-chartlegend-y' style='padding: 1px' size=1><nobr>" + dspFormat_FormatNumber(fValue, oParam.YAxisNumFormat) + "</nobr></span></v:textbox>" +
					"</v:shape>";
			}
		}
		else {
			fValue = oValue.Min;
			var fDelta = Math.abs((oValue.Max - oValue.Min)/oG.NumberOfLabels);
			for(var iLabel = 0; iLabel <= oG.NumberOfLabels; iLabel++) {
				p1 = dspChart_GaugeGetArcPoint(fValue, oValue.Min, oValue.Max, oG, 0);
				p2 = dspChart_GaugeGetArcPoint((iLabel == oG.NumberOfLabels ? oValue.Max : fValue),oValue.Min,oValue.Max,oG,oG.LineLength);
				if(iLabel > 0 && iLabel < oG.NumberOfLabels)
					s += "<v:line style='z-index: 200' from='" + p1.x + "," + p1.y + "' to='" + p2.x + "," + p2.y + " stroked='true' strokecolor='#696969' strokeweight='2pt'/>"; 
				p3 = dspChart_GaugeLabelPosition(p1,oG);
				s += "<v:shape id='rect01' coordorigin='0 0' coordsize='200 200' filled='false' stroked='false' style='z-index: 300;top:" + p3.y + ";left:" + p3.x + ";width:" + oG.LabelWidth + ";height:" + oG.LabelHeight + "'>" +
					"<v:path id= 'mypath' v='m 1,1 l 1,200, 200,200, 200,1 x e' textboxrect='0 0 200 200'/>" +
					"<v:textbox inset='0 0 0 0' style='text-align: " + (p3.Angle < 0 ? "right" : (p3.Angle > 0 ? "left" : "center")) + "'><span class='dsp-chartlegend-y' style='padding: 1px' size=1><nobr>" + dspFormat_FormatNumber(fValue, oParam.YAxisNumFormat) + "</nobr></span></v:textbox>" +
					"</v:shape>";
				fValue += fDelta;
			}
		}
	}
	for (var i=0;i<oValue.PointerCount;i++) {
		if (oValue.Pointers[i].Value.Formatted.length > 0) {
			s += dspChart_GaugePointer(oValue, i, oG);
			dspChart_AddToSerieLegend(oG, oParam.Action, "", oValue.Pointers[i].SerieLegend , oValue.Pointers[i].Color, "");
		}
	}
	if ((oParam.DisplayLegend & 2) > 0 && oValue.PointerCount == 1) {
		s += "<v:shape id='rect01' coordorigin='0 0' stroked='false' filled='false' coordsize='200 200' stroked='false' strokecolor='red' style='z-index: 300;top:" + oG.Origo.y + ";left:" + (oG.Origo.x - oG.ValueLabelWidth/2) + ";width:" + oG.ValueLabelWidth + ";height:" + oG.LabelHeight + "'>" +
				"<v:path id= 'mypath' v='m 1,1 l 1,200, 200,200, 200,1 x e' textboxrect='0 0 200 200'/>" +
				"<v:textbox inset='1 1 1 1' style='text-align:left'><font class='dsp-chartlegend-x' style='padding:1px' size=1><nobr>" + oValue.Pointers[0].Value.Formatted + "</nobr></font></v:textbox>" +
				"</v:shape>";
	}
	if ((oParam.DisplayLegend & 2) > 0 && oG.SerieLegendArray != null && oValue.PointerCount > 1)
		dspChart_ShowSerieLegend(oG, oParam);
	return s + "</v:group>";
}

function dspChart_GaugePointer(oValue, iIndex, oGauge){
	var v = new Number(oValue.Pointers[iIndex].Value);
	var p = dspChart_GaugeGetArcPoint(v, oValue.Min, oValue.Max, oGauge, 0);
	var iAngle = Math.atan((oGauge.PointerWidth/2)/oGauge.InnerRadius);

	var x1 = Math.floor(Math.cos((p.Angle/360.0)*2*Math.PI-Math.PI/2 - iAngle)*(oGauge.Radius/2) + oGauge.Origo.x);
	var y1 = Math.floor(Math.sin((p.Angle/360.0)*2*Math.PI-Math.PI/2 - iAngle)*(oGauge.Radius/2) + oGauge.Origo.y);
	var y2 = Math.floor(Math.sin((p.Angle/360.0)*2*Math.PI-Math.PI/2 - iAngle)*(oGauge.Radius/2) + oGauge.Origo.y);

	var x3 = Math.floor(Math.cos((p.Angle/360.0)*2*Math.PI-Math.PI/2 + iAngle)*(oGauge.Radius/2) + oGauge.Origo.x);
	var y3 = Math.floor(Math.sin((p.Angle/360.0)*2*Math.PI-Math.PI/2 + iAngle)*(oGauge.Radius/2) + oGauge.Origo.y);
	var y4 = Math.floor(Math.sin((p.Angle/360.0)*2*Math.PI-Math.PI/2 + iAngle)*(oGauge.Radius/2) + oGauge.Origo.y);

	y1 = (y1>oGauge.Origo.y)?oGauge.Origo.y:y1;
	y2 = (y2>oGauge.Origo.y)?oGauge.Origo.y:y2;
	y3 = (y3>oGauge.Origo.y)?oGauge.Origo.y:y3;
	y4 = (y4>oGauge.Origo.y)?oGauge.Origo.y:y4;

	var s ="<v:shape title='" + oValue.Pointers[iIndex].Title + "' style='width:" + oGauge.CoordWidth + ";height:" + oGauge.CoordHeight + ";position:absolute;top:0;left:0;z-index:50;rotation:0' stroked='true' strokeweight='1px' strokecolor='#696969' filled='true' fillcolor='" + oValue.Pointers[iIndex].Color + "'>";
	s += "<v:path v='m "+ oGauge.Origo.x +"," + oGauge.Origo.y + " c " + x1 +  "," + y1 + " " + x1 +  "," + y2 + " " + p.x + "," + p.y + " m " + p.x + "," + p.y + " c " + x3 +  "," + y4 + ", " + x3 +  "," + y3 + ", "+ oGauge.Origo.x +"," + oGauge.Origo.y + " e x'/>";
	s += "</v:shape>";
	return s;
}	

function dspChart_GaugeLabelPosition(oPoint, oGauge){
	var oNewPoint = new dspChart_GaugePoint();
	oNewPoint.Angle = Math.floor(oPoint.Angle);
	if(oNewPoint.Angle == 0){
		oNewPoint.x = oPoint.x - oGauge.LabelWidth/2;
		oNewPoint.y = oPoint.y - oGauge.LabelHeight;
	}
	if(oNewPoint.Angle > 0){
		oNewPoint.x = oPoint.x;
		oNewPoint.y = oPoint.y - oGauge.LabelHeight;			
	}
	if(oNewPoint.Angle < 0){
		oNewPoint.x = oPoint.x - oGauge.LabelWidth;
		oNewPoint.y = oPoint.y - oGauge.LabelHeight;	
	}
	return oNewPoint;
}

function dspChart_GaugeSort(v1, v2) {
	return (v1==v2)?0:(v1<v2)?-1:1;
}

function dspChart_GaugeCalculate(oParam, iSerieIndex) {
	var aValues = oParam.Values[iSerieIndex];
	var iPointers=1, iMin=0, iMax=0, i, xItem, sToken = "(No of needles)";
	if (oParam.XItems[0].toUpperCase() == sToken.toUpperCase()) {
		iPointers = aValues.shift();
		xItem = oParam.XItems.shift();
	}
    var aPointerValues = new Array();
	for(i=0;i<iPointers;i++) 
		aPointerValues[i] = aValues.shift();
    aValues.sort(dspChart_GaugeSort);
	for(i=iPointers-1;i>-1;i--) 
	    aValues.unshift(aPointerValues[i]);
	this.Pointers = new Array();
	if (aValues.length < 3) {
		if (aValues.length == 2)
			iMax = Math.abs(aValues[1]);
		else
			iMax = aValues[0] * 2;
		this.Pointers[0] = new dspChart_GaugeCalculateRawPointer(aValues[0], oParam, iMin, iMax);
	}
	else {
		iMin = aValues[iPointers];
		iMax = aValues[aValues.length - 1];
		for(i=0;i<iPointers;i++) 
			this.Pointers[i] = new dspChart_GaugeCalculateRawPointer(i, aValues[i], oParam, iMin, iMax);
	}
	this.Min = iMin;
	this.Max = iMax;
	this.PointerCount = iPointers;
	if (xItem != null)
		oParam.XItems.unshift(xItem);
	this.Values = aValues;
}

function dspChart_GaugeCalculateRawPointer(iIndex, iValue, oParam, iMin, iMax) {
	this.Value = iValue;
	this.Rotation = dspChart_GaugeCalcRotation(iValue, iMin, iMax);
	this.Title = oParam.XItems[iIndex] + "=" + iValue.Formatted;
	this.SerieLegend = oParam.XItems[iIndex] + " (" + iValue.Formatted + ")";
	this.Color = (iValue.ForeColor!=null)?iValue.ForeColor:oParam.SerieColor[iIndex];
}

function dspChart_GaugeProperties(oParam, oValue) {
	var sLabel = dspFormat_FormatNumber(((Math.abs(oValue.Min) > Math.abs(oValue.Max))? oValue.Min: oValue.Max), oParam.YAxisNumFormat);
	var oText = new dspChart_Text("y", oParam.MasterTextDiv, sLabel+"-X", 0, 0);
	var iLabelWidthPx = oText.Width;
	var iLabelHeightPx = oText.Height;
	
	var sValueLabel = oValue.Pointers[0].Value.Formatted;
	oText = new dspChart_Text("y", oParam.MasterTextDiv, sValueLabel+"X",0, 0);
	var iValueLabelWidthPx = oText.Width;
	
	this.XAxisFont = oParam.XAxisFont;
	this.YAxisFont = oParam.YAxisFont;
	this.SAxisFont = oParam.SAxisFont;

	this.LegendCount = 0;
	this.NonEmptyLegendExists = false;
	this.SerieLegendHTML = "";
	this.SerieLegendPosition = oParam.SerieLegend.Position;
	this.DisplaySerieLegendCount = 0;
	this.SerieLegendArray = null;
	
	this.CoordHeight = 10000;
	this.PointsPerPixel = 10000/oParam.WebPartHeight;
	this.InnerRadius = 2000;
	this.PointRadius = 100;
	this.LineLength = 300;
	this.PointerWidth = 400;
	this.NumberOfLabels = Math.min(((oParam.YAxisUnits!=null)? Math.floor(Math.abs((oValue.Max-oValue.Min)/oParam.YAxisUnits)):4), 50);
	this.LabelWidth = Math.floor(this.PointsPerPixel*iLabelWidthPx);
	this.ValueLabelWidth = Math.floor(this.PointsPerPixel*iValueLabelWidthPx);
	this.LabelHeight = Math.floor(this.PointsPerPixel*iLabelHeightPx);
	this.Radius = Math.floor(this.CoordHeight - 2*this.LabelHeight);
	this.CoordWidth = 2*this.Radius + 2*this.LabelWidth;
	this.Origo = new dspChart_GaugePoint(this.Radius + this.LabelWidth, this.Radius + this.LabelHeight);
	this.WidthPx = Math.floor(this.CoordWidth / this.PointsPerPixel);
	this.HeightPx = oParam.WebPartHeight;
} 

function dspChart_GaugePoint(x,y) {
	this.x = x;
	this.y = y;
}

function dspChart_GaugeGetArcPoint(v, iMin, iMax, oGauge, iRadiusAdjust) {
	var iRotation = (180/(iMax-iMin))*(v-iMin)-90;
	var iAngle = (iRotation<0)?Math.max(iRotation, -90):Math.min(iRotation, 90);
	var x = Math.floor(Math.cos((iAngle/360.0)*2*Math.PI-Math.PI/2)*(oGauge.Radius-iRadiusAdjust) + oGauge.Origo.x);
	var y = Math.floor(Math.sin((iAngle/360.0)*2*Math.PI-Math.PI/2)*(oGauge.Radius-iRadiusAdjust) + oGauge.Origo.y);
	var oPoint = new dspChart_GaugePoint(x,y);
	oPoint.Angle = iAngle;
	return oPoint;
}
			
function dspChart_GaugeCalcRotation(v, iMin, iMax) {
	var iRotation = (180/(iMax-iMin))*(v-iMin)-90;
	return (iRotation<0)?Math.max(iRotation, -90):Math.min(iRotation, 90);
}

function dspChart_GraphProperties(oParam, iYCount, iXCount, iBarCount) { 
	this.MasterTextDiv = oParam.MasterTextDiv;
	
	this.XAxisFont = oParam.XAxisFont;
	this.YAxisFont = oParam.YAxisFont;
	this.SAxisFont = oParam.SAxisFont;
	
	this.ChartType = oParam.ChartType;
	this.BorderColor = oParam.BorderColor;
	this.StackedTotal = (this.ChartType==5)?dspChart_CalcStackedTotal(oParam.Values, iYCount, iXCount):null;
	this.StackedValues = (this.ChartType==4)?dspChart_Stack(oParam.Values, iYCount, iXCount):null;
	this.XPositions = new Array();
	this.SerieBarCount = iBarCount;
	this.SerieLegendPosition = oParam.SerieLegend.Position;
	this.DisplaySerieLegendCount = oParam.DisplaySerieLegendCount;
	this.CntMode = oParam.XLegendCntMode;
	this.CutMode = oParam.XLegendCutMode;
	this.XLegWordWrap = new Number(oParam.XLegendWordWrap);
	
	this.Action = oParam.Action;
	this.YAxisNumFormat = oParam.YAxisNumFormat;
	this.LegendCount = 0;
	this.NonEmptyLegendExists = false;
	this.SerieLegendHTML = "";
	this.AutoScaleOn = (oParam.MinValue==null && oParam.MaxValue==null && oParam.YAxisUnits==null);
	
	this.Width = oParam.WebPartWidth;
	this.Height = oParam.WebPartHeight;

	var oRange = new dspChart_GetValueRange((this.ChartType==4)?this.StackedValues:oParam.Values, iYCount, iXCount, oParam.MinValue, oParam.MaxValue, oParam.YAxisUnits, this.ChartType, this.YAxisNumFormat);
	this.Min = oRange.Min;
	this.Max = oRange.Max;
	this.Step = oRange.Step;
	this.Negative = oRange.Negative;
	this.NegativeAll = oRange.NegativeAll;
	
	var oText = new dspChart_Text("y", this.MasterTextDiv, dspFormat_FormatNumber((this.Max.toString().length>=this.Min.toString().length)?this.Max:this.Min, this.YAxisNumFormat), 0, 0);
	this.YLegendWidth = oText.Width;
	this.YLegendHeight = oText.Height;
	this.LeftMargin = ((oParam.DisplayLegend & 1)>0)?this.YLegendWidth+5:2;
	this.XLegLeft = this.LeftMargin;
	
	this.BarCount = dspChart_CalcBarCount(iXCount, iYCount, this.ChartType, iBarCount);
	this.LastBarLeft = 0;
	this.LastBarPos = 0;
	this.LastBarNeg = 0;
	this.LastUsedBar = 0;
	var oXUnits = new dspChart_SpaceAndBarWidth(this.Width,this.ChartType,this.BarCount,this.LeftMargin,iXCount);
	this.Space = oXUnits.Space; 
	this.BarWidth = oXUnits.BarWidth;

	var iXLegMaxWidth = 0;
	if (this.ChartType==1 || this.ChartType==3) 
		iXLegMaxWidth = this.BarWidth * this.SerieBarCount + this.Space + (this.SerieBarCount-1);
	if (this.ChartType==5) 
		iXLegMaxWidth = this.BarWidth + this.Space;
	if (this.ChartType==2 || this.ChartType==4)
		iXLegMaxWidth = this.Space + 1;
	
	var iWidestXLegend = dspChart_XLegWidest(oParam, this.CutMode, this.XLegWordWrap, 0);
	switch (oParam.XLegendOrientation) {
		case 0: this.XLegendVertical = false; break;
		case 1: this.XLegendVertical = true; break;
		default: this.XLegendVertical = (iWidestXLegend > iXLegMaxWidth) && (iWidestXLegend*2<oParam.WebPartHeight); break;
	}
		 			
	this.XLegendHeight = (this.XLegendVertical)?iWidestXLegend+4:dspChart_XLegHeight(oParam, this.XLegWordWrap, iXLegMaxWidth);
	this.XLegendWidth = iXLegMaxWidth;
		    
    	var iMarginOffset = 5;
	this.BottomMargin = (((oParam.DisplayLegend & 2)>0) && this.NegativeAll)?iMarginOffset:Math.floor(this.XLegendHeight+iMarginOffset);
	this.TopMargin = (((oParam.DisplayLegend & 2)>0) && this.NegativeAll)?Math.ceil(this.XLegendHeight):0;

	this.XLegTop = (this.NegativeAll)?0:Math.ceil(this.Height-this.BottomMargin+1);

	var oYAxis = new dspChart_GetYAxisProperties(oRange, this.Height - this.TopMargin - this.BottomMargin);
	this.MinMaxDiff = oYAxis.MinMaxDiff;
	this.ScaleDiff = oYAxis.Diff;
	this.Scale = oYAxis.Scale;
	this.ZeroBase = dspChart_CalcZeroBase(this.Height, this.Negative, this.NegativeAll, this.Scale, oRange.Min, this.BottomMargin, this.TopMargin);

}

function dspChart_ShowSerieLegend(oGraph, oParam) {
	if (oGraph.NonEmptyLegendExists) {
		if (oParam.SerieLegend.Position == 1 || oParam.SerieLegend.Position == 3)
			dspChart_ApplyVerticalSerieLegend(oGraph.LegendCount, oParam.MasterTextDiv, oParam.SerieLegend.HtmlObject, oGraph.SerieLegendHTML, oParam.WebPartWidth, oParam.UseImg);
		if (oParam.SerieLegend.Position == 2)
			dspChart_ApplyHorizontalSerieLegend(oParam.SAxisFont, oParam.SerieLegend.HtmlObject, (oGraph.ChartType==4||oGraph.ChartType==5)?oGraph.SerieLegendArray.reverse():oGraph.SerieLegendArray, oParam.WebPartHeight, oParam.UseImg, oParam.Action);
	}
}

function dspChart_ApplyHorizontalSerieLegend(oFont, oSerieLegend, aSerie, iMaxHeight, bUseImg, oAction) {
	var s = "";
	var iMaxDisp = Math.floor(iMaxHeight/(oFont.Height));
	var iOverflow = (aSerie.length > iMaxDisp);
	var sButton = "";
	for (var i=0;i<aSerie.length;i++) {
		sButton = "";
		if (iOverflow && bUseImg) {
			if (i==(iMaxDisp-1))
				sButton = "<img style='cursor:hand' src='/_layouts/images/TPMax1.gif'/>";
			if (i==(aSerie.length-1))
				sButton = "<img style='cursor:hand' src='/_layouts/images/TPMin1.gif'/>";
		}
		if (sButton.length > 0)
			s += "<tr><td " + aSerie[i].Action + " nowrap style='font-family:" + oFont.FontFamily + ";font-size:" + oFont.FontSize + "'>" + aSerie[i] + "</td><td onclick='dspChart_ShowLegend(this.parentElement.parentElement.parentElement, false)' style='padding-left:2px'>" + sButton + "</td></tr>";
		else	
			s += "<tr><td " + aSerie[i].Action + " colspan=2 nowrap style='font-family:" + oFont.FontFamily + ";font-size:" + oFont.FontSize + "'>" + aSerie[i] + "</td></tr>";
	}
	s = "<table border=0 cellspacing=0 cellpadding=0;>" + s + "</table>";
	if (iOverflow)
		oSerieLegend.style.height = iMaxDisp * (oFont.Height);
	oSerieLegend.innerHTML = s;
	oSerieLegend.parentElement.style.display = "block";
}

function dspChart_ShowLegend(oTag, bVertical) {
	if (bVertical) {
		var sHTML = oTag.rows[0].cells[0].innerHTML;
		if (sHTML.indexOf("<SPAN") > -1) {
			sHTML = sHTML.replace(/<SPAN/g, "<DIV").replace(/SPAN>/g, "DIV>");
			if (oTag.rows[0].cells[1].innerHTML.length > 0) {
				oTag.rows[0].cells[1].innerHTML = "<img style='cursor:hand' src='/_layouts/images/TPMin1.gif'/>";
				oTag.rows[0].cells[1].style.verticalAlign = "bottom";
			}
			oTag.parentElement.style.overflow = "visible"; 
		}
		else {
			sHTML = sHTML.replace(/<DIV/g, "<SPAN").replace(/DIV>/g, "SPAN>");
			if (oTag.rows[0].cells[1].innerHTML.length > 0) {
				oTag.rows[0].cells[1].innerHTML = "<img style='cursor:hand' src='/_layouts/images/TPMax1.gif'/>";
				oTag.rows[0].cells[1].style.verticalAlign = "top";
			}
			oTag.parentElement.style.overflow = "hidden"; 
		}
		oTag.rows[0].cells[0].innerHTML = sHTML;
	}
	else {
		var bCollapsed = (oTag.parentElement.style.overflow == "hidden");
		oTag.parentElement.style.overflow = (bCollapsed)?"visible":"hidden";
		var oImg = oTag.getElementsByTagName("IMG");
		if (oImg.length > 0)
			oImg[0].style.display = (bCollapsed)?"none":"block";
	}
}

function dspChart_ApplyVerticalSerieLegend(iLegCount, oFontDiv, oLegDiv, sHTML, iMaxWidth, bUseImg) {
	var oText = new dspChart_Text("s", oFontDiv, sHTML, false, 0);
	if ((oText.Width + 4*iLegCount) > iMaxWidth) {
		var sButton = (bUseImg)?"<img style='cursor:hand' src='/_layouts/images/TPMax1.gif'/>":"";
		sHTML = "<table border=0 onclick='dspChart_ShowLegend(this, true);'" + 
			    " width='100%'><tr><td nowrap><div style='text-overflow:ellipsis;" +
			    " white-space:nowrap;width:" + (iMaxWidth-30) + "px;overflow:hidden'>" + 
			    sHTML + "</div></td><td style='vertical-align:top'>" +
			    sButton + "</td></tr></table>";
	}
	oLegDiv.style.height = oText.Height + 4;
	oLegDiv.style.width = iMaxWidth;
	oLegDiv.innerHTML = sHTML;
	oLegDiv.parentElement.style.display = "block";
}

function dspChart_Stack(aValues, iYCount, iXCount) {
	var a = dspChart_CopyValueArray(aValues);
	for (var i=1; i < iYCount; i++) {
		for (var j=0; j < iXCount; j++)
			a[i][j] += a[i-1][j];
	}
	return a;
}

function dspChart_DrawGraphArea(iWidth, iHeight) {
	var s = "<v:group style='position:relative;width:" + iWidth + "px;height:" + iHeight + "px' coordsize='" + iWidth + " " + iHeight + "'>";
	s += "<v:shape style='overflow-y:hidden;position:relative;width:" + iWidth + "px;height:" + iHeight + "px' />";
	return s;
}

function dspChart_DrawYLegend(oGraph) {
	var sFormat = oGraph.YAxisNumFormat;
	var iCenter = oGraph.YLegendHeight/2;
	var t = "<div nowrap class='dsp-chartlegend-y' style='cursor:default;width:" + oGraph.YLegendWidth + 
		"px;text-align:right;margin:0px;padding:0px;position:absolute;left:2px;top:";
	var iMin = oGraph.Min;
	var iStep = oGraph.Step;
	var iMaxLegPos = oGraph.Height - oGraph.BottomMargin - iCenter;
	var iTop = Math.floor(dspChart_CalcLineYValue(iMin,oGraph,true) - iCenter);
	var s = "";
	var iMaxLoop = 0;
	while ((oGraph.NegativeAll && (iTop < iMaxLegPos)) || (!oGraph.NegativeAll && (iTop >= -1))) {
		if ((oGraph.Negative && !oGraph.NegativeAll && iTop <= iMaxLegPos) || !oGraph.Negative || oGraph.NegativeAll)
			s += t + Math.floor(iTop) + "px'>" + dspFormat_FormatNumber(iMin, sFormat) + "</div>";
		iTop = dspChart_CalcLineYValue(iMin+=iStep,oGraph,true) - iCenter;
		iMaxLoop++;
		if (iMaxLoop>100)
			break;
	}
	return s;
}

function dspChart_DrawAxes(oGraph, sAxisColor) {
	var s, sXPath, sYPath, iLeft, iXTop, iYTop1, iYTop2;
	iLeft = oGraph.LeftMargin;
	iXTop = oGraph.ZeroBase;
	if (oGraph.NegativeAll) {
		iYTop1 = iXTop;
		iYTop2 = oGraph.Height - oGraph.BottomMargin;
	}
	else {
		iYTop1 =  oGraph.TopMargin;
		iYTop2 = (oGraph.Negative)?Math.floor((oGraph.Height-oGraph.BottomMargin)):iXTop;
	}
	sXPath = "m" + iLeft + "," + Math.floor(iXTop) + "l " + Math.floor(oGraph.Width) + "," + Math.floor(iXTop) + " e";
	sYPath = "m" + iLeft + "," + Math.floor(iYTop1) + "l " + Math.floor(iLeft) + "," + Math.floor(iYTop2) + " e";
	s = "<v:shape style='position:relative;width:200;height:4;left:0;top:0' strokecolor=\"" + sAxisColor + "\" coordsize=\"200,4\" path='" + sXPath + "'/>";
	s += "<v:shape style='position:relative;width:4;height:" + oGraph.Height + ";left:0;top:0' strokecolor=\"" + sAxisColor + "\" coordsize=\"4," + oGraph.Height + "\" path='" + sYPath + "'/>";
	return s;
}

function dspChart_DrawBar(oBar) {
	var s="";
	if (!oBar.IsNull && !oBar.OutOfLimit) {
		s = "<v:rect title='" +  oBar.Description + "' " + oBar.Action.Command + 
			" style='position:relative;width:" + oBar.Width + ";height:" + ((oBar.Height==0)?0:oBar.Height) + ";top:" + oBar.Top + ";left:" + oBar.Left + "' strokecolor='" + oBar.StrokeColor + "' fillcolor='" + oBar.Color + "'>" +
			"<v:fill opacity='" + oBar.Opacity + "%'/></v:rect>";
	}
	return s;
}

function dspChart_DrawArea(oLine, iXCount) {
	var s = "<v:shape title='" + oLine.SerieLegend + "'" +
		" style='position:relative;width:" + oLine.Width + "px;height:" + oLine.Height + "px;left:0;top:-1' strokecolor='" + oLine.StrokeColor + "' filled='true' fillcolor='" + oLine.Color + "' strokeweight='1pt' path='m" + Math.floor(oLine.Left[0]) + "," + Math.floor(oLine.Top[0]) + "l ";
	for (var j=1; j < iXCount; j++)
		s += (Math.floor(oLine.Left[j]) + 0) + "," + Math.floor((oLine.Top[j])) + " ";
	for (j=iXCount-1; j > -1; j--)
		s += (Math.floor(oLine.Left[j]) + 0) + "," + (Math.floor(oLine.PrevTop[j]) + 0) + " ";
	s += (Math.floor(oLine.Left[0])) + "," + (Math.floor(oLine.Top[0]-0)) + "e'><v:fill opacity='" + oLine.FillOpacity + "%'/></v:shape>";
	return s;
}

function dspChart_DrawLine(oLine, iXCount) {
	var s = "", iPrevTop = 0;
	var l = (iXCount>1)?oLine.IsNull[1]:false;
	for (var j=0; j < iXCount; j++) {
		if (!oLine.IsNull[j]) {
			var iLeft = oLine.Left[j];
			var iTop = oLine.Top[j];
			if (iTop < oLine.MaxYCoord || iTop > oLine.MinYCoord) {
				var iBound = (iTop < oLine.MaxYCoord)?oLine.MaxYCoord:oLine.MinYCoord;
				if ((iTop < oLine.MaxYCoord)?(j > 0 && iPrevTop > iBound):(j > 0 && iPrevTop < iBound)) {
					iLeft = oLine.Left[j-1] + (iBound - iPrevTop) * (oLine.XCoordDiff/(iTop - iPrevTop));
					s += ((l)?" l " + Math.floor(iLeft) + "," + Math.floor(iBound) + "e ":"");
				}
				iLeft = oLine.Left[j+1] - (iBound - oLine.Top[j+1]) * (oLine.XCoordDiff/(iTop - oLine.Top[j+1]));
				iTop = iBound;
				l = false;
			}
			s += (((j+1==iXCount) && !l)?"":((l)?" l ":"m ") + Math.floor(iLeft) + "," + Math.floor(iTop));
		}
		else
			s += (((s.length>0)||(j+1==iXCount))?" e":"");
		l = !oLine.IsNull[j];
		iPrevTop = oLine.Top[j];
	}
	s = "<v:shape title='" + oLine.SerieLegend + "' style='position:relative;width:200;height:" + oLine.Height + ";left:0;top:0' strokecolor='" + oLine.Color + "' filled='false' strokeweight='" + oLine.LineWidth + "pt' coordsize='200," + oLine.Height + "' path='" + s + "' ><v:stroke opacity='" + oLine.Opacity + "%'/></v:shape>";
	return s;
}

function dspChart_DrawPoint(oGraph, oLine, iXCount, bVisible) {
	var s = "";
	var h = oLine.LineWidth*2;
	var w = h;
	var sVisible = (bVisible)?"t":"f";
	for (var j=0; j < iXCount; j++) {
		if (!oLine.IsNull[j] && (oLine.Top[j] >= oLine.MaxYCoord) && (oLine.Top[j] <= oLine.MinYCoord)) {
			x1 = Math.floor(oLine.Left[j]-w);
			x2 = Math.floor(oLine.Left[j]+w);
			y1 = Math.floor(oLine.Top[j]-h);
			y2 = Math.floor(oLine.Top[j]+h);
			s += "<v:shape " + oLine.Action[j] + " title='" + oLine.Description[j] + "'" +
				" style='position:relative;width:" + oGraph.Width + ";height:" + oGraph.Height + ";left:0;top:0' strokecolor='" + oLine.StrokeColor + "' stroked='false' filled='" + sVisible + "' fillcolor='" + oLine.Color + "'" +
				" path='m" + x1 + "," + y1 + "l " + x2 + "," + y1 + "," + x2 + "," + y2 + "," + x1 + "," + y2 +
				"'><v:fill opacity='" + oLine.Opacity + "%'/></v:shape>";
		}
	}
	return s;
}

function dspChart_CalcAutoMinMax(aValues, iYCount, iXCount, iChartType) {
	var iMinv = 0, iMaxv = 0;
	var iMax,iMin;
	for (var i=0; i < iXCount; i++) {
		for (var j=0; j < iYCount; j++) {
			if (aValues[j][i].Formatted != "") { 
				iMax = aValues[j][i];
				iMin = iMax;
				break;
			}
		}
		if (iMax!=null)
			break;
	}
	if (iMax==null) 
	{
		iMax = 0;
		iMin = 0;	
	}
	else 
	{
		switch (iChartType) {
			case 5:
				for (var i=0; i < iXCount; i++) {
					for (var j=0; j < iYCount; j++) {
						if (aValues[j][i].Formatted != "") { 
							if(aValues[j][i] > 0) 
								iMaxv += aValues[j][i];
							else 
								iMinv += aValues[j][i];
						}
					}
					iMax = Math.max(iMax, iMaxv);
					iMin = Math.min(iMin, iMinv);
					iMaxv = 0; 
					iMinv = 0;
				}
				break;
			default:
				for (var i=0; i < iYCount; i++) {
					for (var j=0; j < iXCount; j++) {
						if (aValues[i][j].Formatted != "") { 
							iValue = aValues[i][j];
							iMax = Math.max(iMax, iValue);
							iMin = Math.min(iMin, iValue);
						}
					}
				}
				break;
		}
	}
	this.Min = iMin;
	this.Max = iMax;
	
}

function dspChart_CalcAutoStep(iMin, iMax, bNegative, bNegativeAll) {
	var dblPower = Math.log(Math.abs(iMax - iMin))/Math.LN10;
	if(dblPower == -Infinity)
		dblPower = 0;
	var iStep = Math.pow(10, dblPower - Math.floor(dblPower));
	if((iStep>0) && (iStep<1.3))
		iStep = 0.2;
	if((iStep>1.3)&&(iStep<3.6))
		iStep = 0.5;
	if((iStep>3.6)&&(iStep<6.3)) 
		iStep = 1;
	if(iStep>6.3)
		iStep = 2;

	iStep = iStep*Math.pow(10,Math.floor(dblPower));
	
	var iExtra = 1;
	
	if (bNegative) {
		if (bNegativeAll) {
			iMin = iStep * (Math.floor(iMin / iStep) + iExtra);
			iMax = iStep * (Math.ceil(iMax / iStep) - iExtra);
			iStep = iStep*-1;
			if(iMin > 0) 
				iMin = 0;
		}
		else {
			iMin = (iStep * (Math.floor(Math.abs(iMin / iStep)) + iExtra))*-1;
			iMax = iStep * (Math.floor(Math.abs(iMax / iStep)) + iExtra);
		}
	}
	else {
		iMin = iStep * (Math.ceil(Math.abs(iMin / iStep)) - iExtra);
		iMax = iStep * (Math.floor(Math.abs(iMax / iStep)) + iExtra);
		if(iMin < 0) 
			iMin = 0;
	}
	this.Step = iStep;
	this.Min = iMin;
	this.Max = iMax;
}

function dspChart_GetValueRange(aValues, iYCount, iXCount, iManMin, iManMax, iManSteps, iChartType, YAxisNumFormat) {
	var oAutoMinMax = new dspChart_CalcAutoMinMax(aValues, iYCount, iXCount, iChartType);
	var iMin = (iManMin!=null&&iManMin!=iManMax)?iManMin:oAutoMinMax.Min;
	var iMax = (iManMax!=null&&iManMin!=iManMax)?iManMax:oAutoMinMax.Max;
	
	var iStep = 2;
	var bNegative = false; 
	var bNegativeAll = false;
	if (iMin==0 && iMax==0) {
		
		iMax=(dspFormat_FormatNumber(1, YAxisNumFormat).indexOf("%")>=0)?1:10;
		iStep = (iMax==10)?2:0.2;
	}
	else {
		var oNegative = new dspChart_Negative(iChartType, iMin, iMax);
		bNegative = oNegative.Negative; 
		bNegativeAll = oNegative.NegativeAll;
		if (iChartType != 6) {
			iMin = oNegative.Min;
			iMax = oNegative.Max;
			var oAutoStep = new dspChart_CalcAutoStep(iMin, iMax, bNegative, bNegativeAll);
			iStep = (iManSteps!=null&&iManMin!=iManMax)?Math.max(iManSteps, oAutoStep.Step/4):oAutoStep.Step;
			// Adjust min axis value down one step where diff lowest value and min axis value is < 25% of step value. 
			var iMinAdjust = 0;
			if (iChartType==1 || iChartType==2 || iChartType==3) {
				iMinAdjust = (((oAutoMinMax.Min - oAutoStep.Min)/iStep) < 0.25)?iStep:0;
			}			
			iMin = (iManMin!=null&&iManMin!=iManMax)?oNegative.Min:oAutoStep.Min - iMinAdjust;
			if (iMinAdjust > 0 && iMin < 0 && !bNegative) //If all values are positive and min is adjusted below 0, set min to 0
				iMin = 0;
			iMax = (iManMax!=null&&iManMin!=iManMax)?oNegative.Max:oAutoStep.Max;
			
		}
	}
	this.Negative = bNegative;
	this.NegativeAll = bNegativeAll;
	this.Step = iStep; 
	this.Max = iMax;
	this.Min = iMin;		
}

function dspChart_Negative(iChartType, iMin, iMax) {
	var bNegative = false;
	var bNegativeAll = false;
	if (iChartType != 6) {
		bNegative = (iMin < 0);
		bNegativeAll = (iMax <= 0 && iMin <= 0);
		if (bNegativeAll) {
			var t = iMin;
			iMin = iMax;
			iMax = t;
		}
		if ((iChartType==4 || iChartType==5) && (bNegativeAll || !bNegative))
			iMin = 0;
		if ((bNegativeAll || !bNegative) && iMin==iMax)
			iMin = 0;
	}
	this.Negative = bNegative;
	this.NegativeAll = bNegativeAll;
	this.Min = iMin;
	this.Max = iMax;
}

function dspChart_GetYAxisProperties(oRange, iScaleBase) {
	var iAddToDiff, iScale;
	var iMinMaxDiff = oRange.Max - oRange.Min;
	var iDiff = 0;
	if (oRange.Negative && !oRange.NegativeAll) {
		iScale = iScaleBase/iMinMaxDiff;
	}
	else {
		var g = Math.log(Math.abs(iMinMaxDiff))/Math.LN10;
		iAddToDiff = Math.pow(10,g-1);
		iScale = iScaleBase/(Math.abs(iMinMaxDiff) + Math.abs(iAddToDiff));
		iDiff = Math.max(oRange.Min-iAddToDiff,oRange.Min);
	}
	this.Scale = iScale;
	this.Diff = iDiff;
	this.MinMaxDiff = iMinMaxDiff;
}

function dspChart_CalcZeroBase(iScaleHeight, bNegative, bNegativeAll, iScale, iMin, iBottomMargin, iTopMargin, iHeightFactor) {
	if (bNegativeAll)
		return iTopMargin;
	else {
		if (bNegative)
			return iScaleHeight + Math.floor(iScale*(iMin))- iBottomMargin;
		else
			return iScaleHeight - iBottomMargin;
	}
}

function dspChart_CalcBarCount(iXCount, iYCount, iChartType, iBarCount) {
	switch (iChartType) {
		case 1:
			return iXCount * iYCount;
			break;
		case 3:
			return iXCount * iBarCount;
			break;
		default:
			return iXCount;
			break;
	}
}

function dspChart_SpaceAndBarWidth(iWidth,iChartType,iBarCount,iLeftMargin,iXCount) {
	if (iChartType==2||iChartType==4) {
		this.Space = Math.floor((iWidth-iLeftMargin-iXCount)/(iXCount));
		this.BarWidth = 1;
	}
	else {
		var xUnits = 2 * iBarCount - (iBarCount - iXCount);
		var xWidth = (iWidth-iLeftMargin-(iBarCount - iXCount));
		this.BarWidth = Math.floor(xWidth/xUnits);
		this.Space = this.BarWidth;
		var xWaste = xWidth-xUnits*this.Space;
		if (xWaste > 0) {
			if (iXCount <= xWaste)
				this.Space += Math.floor(xWaste/iXCount);
		}
	}
}

function dspChart_CalcLineXValue(oGraph, x) {
	var c = ((oGraph.ChartType==3)?oGraph.SerieBarCount:1);
	var t = c*oGraph.BarWidth;
	if (oGraph.ChartType!=3)
		return  oGraph.Space/2 + oGraph.LeftMargin + ((t + oGraph.Space) * x);
	else
		return oGraph.XPositions[x];
}

function dspChart_BarProperties(oGraph,v,aColors,aSerieItems,sXItem,i,j,iBarCount,iBarIndex,iXCount,sStrokeColor,sOpacity) {
	if (v.ForeColor!=null)
		this.Color = v.ForeColor;
	else
		this.Color = dspChart_GetSerieColor(aColors, j);	
	this.StrokeColor = sStrokeColor;
	this.Opacity = sOpacity;
	this.Legend = sXItem;
	this.IsNull = (v.Formatted == "");
	this.OutOfLimit = false;
	this.Action = new dspChart_CellActionInfo(oGraph.Action, v.CellId, "bar");
	if (i==0) 
		dspChart_AddToSerieLegend(oGraph, oGraph.Action, aSerieItems[j].MemberId, aSerieItems[j], this.Color, aSerieItems[j].Tooltip);
	this.Description = ((aSerieItems[j]!="")?aSerieItems[j] + " : ":"") + sXItem + " : " + v.Formatted + ((oGraph.ChartType ==5)?" : Total = " + dspFormat_FormatNumber(oGraph.StackedTotal[i], oGraph.YAxisNumFormat):"") + " " + this.Action.Description;
	this.Width = oGraph.BarWidth;

	var iValue = v;
	if(oGraph.ChartType == 5) {
		v = Math.floor((iValue-oGraph.ScaleDiff) * oGraph.Scale);
		this.Height = (v<0)?-v:v;
		if((oGraph.LastBarPos.Top == null && v > 0) || (oGraph.LastBarNeg.Top == null && v < 0)  || (oGraph.LastBarPos.i  < i) || (oGraph.LastBarNeg.i  < i)) {
			this.Top = (v<0)?oGraph.ZeroBase:oGraph.ZeroBase-this.Height;
			if((oGraph.LastBarPos.i  < i) || (oGraph.LastBarNeg.i  < i)) {
				oGraph.LastBarPos = 0;
				oGraph.LastBarNeg = 0;
			}
		}
		else
			this.Top = (v==0)?oGraph.LastBarPos.Top:(v<0)?oGraph.LastBarNeg.Top + oGraph.LastBarNeg.Height:oGraph.LastBarPos.Top - this.Height;
		this.Left = oGraph.Space/2 + oGraph.LeftMargin + ((this.Width + oGraph.Space) * i);
	}
	else {
		if(oGraph.LastBarLeft == 0)
			this.Left = oGraph.Space/2 + oGraph.LeftMargin + ((this.Width + oGraph.Space) * iBarIndex);
		else
			this.Left = oGraph.LastBarLeft + this.Width + ((j==0)?oGraph.Space:1);
		var oHT = new dspChart_CalcBarTopHeight(iValue, oGraph);
		this.Height = oHT.Height;
		this.Top = oHT.Top;
		this.OutOfLimit = oHT.OutOfLimit;
	}
	if (j==0)
		oGraph.XPositions[i] = this.Left + ((this.Width*((oGraph.ChartType!=5)?iBarCount:1)+((oGraph.ChartType!=5)?iBarCount:0))/2);

	oGraph.LastBarLeft = this.Left;
	oGraph.LastUsedBar = this;
	oGraph.LastUsedBar.i = i;
	oGraph.LastUsedBar.v = v;
	
	if(v >= 0){
		oGraph.LastBarPos = this;
		oGraph.LastBarPos.i = i;
		oGraph.LastBarPos.v = v;
	}
	else {
		oGraph.LastBarNeg = this;
		oGraph.LastBarNeg.i = i;
		oGraph.LastBarNeg.v = v;
	}
}

function dspChart_LineProperties(oGraph, aValues, aColors, sSerieLegend, aXItems, i, iChartType, sLineWidth, sOpacity, sStrokeColor, sFillOpacity) {
	var x = aXItems.length, v;
	this.Color = dspChart_GetSerieColor(aColors, i);
	this.Opacity = sOpacity;
	this.Width = oGraph.Width;
	this.Height = oGraph.Height;
	this.FillOpacity = sFillOpacity;
	this.StrokeColor = sStrokeColor;
	this.SerieLegend = sSerieLegend;
	this.LineWidth = sLineWidth;
	dspChart_AddToSerieLegend(oGraph, oGraph.Action, sSerieLegend.MemberId, sSerieLegend, this.Color, sSerieLegend.Tooltip);
	this.Left = new Array(x);
	this.Top = new Array(x);
	this.PrevTop = new Array(x);
	this.Description = new Array(x);
	this.FormatValue = new Array(x);
	this.IsNull = new Array(x);
	this.MaxYCoord = dspChart_CalcLineYValue((!oGraph.NegativeAll)?oGraph.Max:oGraph.Min, oGraph, false);
	this.MinYCoord = dspChart_CalcLineYValue((!oGraph.NegativeAll)?oGraph.Min:oGraph.Max, oGraph, false);
	this.XCoordDiff =  dspChart_CalcLineXValue(oGraph, 2) - dspChart_CalcLineXValue(oGraph, 1);
	this.Action= new Array();
	for (var j = 0; j < x; j++) {
		v = aValues[i][j];
		var oAction = new dspChart_CellActionInfo(oGraph.Action, v.CellId, "point"); 
		this.Action[j] = (oGraph.ChartType!=4)?oAction.LineCommand:"";
		this.IsNull[j] = (v.Formatted == "");
		this.Description[j] = ((sSerieLegend!="")?sSerieLegend + " : ":"") + aXItems[j] + " : " + v.Formatted + ((oGraph.ChartType!=4)?oAction.Description:"");
		this.Left[j] = dspChart_CalcLineXValue(oGraph, j);
		oGraph.XPositions[j] = this.Left[j];
		if (iChartType==4)
			v = oGraph.StackedValues[i][j];
		this.Top[j] = dspChart_CalcLineYValue(v, oGraph, false);
		if (i==0)
			this.PrevTop[j] = oGraph.ZeroBase;
		else
			this.PrevTop[j] = dspChart_CalcLineYValue(((iChartType==4)?oGraph.StackedValues[i-1][j]:aValues[i-1][j]), oGraph,false);
	}
}

function dspChart_CalcLineYValue(v, oGraph, bReverse) {
	var i = (v - oGraph.ScaleDiff) * oGraph.Scale;
	if (!oGraph.Negative && bReverse)
		i = ((i<0)?(-i):i);
	return oGraph.ZeroBase-i;
}

function dspChart_GetSerieColor(aColors, iIndex) {
	var sColor = "", iRandNo;
	if (iIndex >= aColors.length) {
		for (var j = 0;j < 3; j++) {
			iRandNo = Math.floor(Math.random()*256);
			sColor += iRandNo.toString(16);
 		}
		aColors[iIndex] = "#" + sColor;
	}
	return aColors[iIndex];
}

function dspChart_AddToSerieLegend(oChart, oAction, sMemberId, sText, sColor, sTooltip) {
	var sAction = oAction.SerieTooltipAndEvent.replace("_MEMBERID_", sMemberId).replace("_TOOLTIP_", sTooltip);
	if (oChart.SerieLegendArray == null)
		oChart.SerieLegendArray = Array();
	if (oChart.LegendCount < oChart.DisplaySerieLegendCount || oChart.DisplaySerieLegendCount==0) {
		if (oChart.SerieLegendPosition == 1 || oChart.SerieLegendPosition == 3)
			oChart.SerieLegendHTML += "<span " + sAction + " class='dsp-chartlegend-s' style='padding-left:4px'><font style='padding-right:4px;font-family:wingdings;color:" + sColor + "'>l</font>" + sText + "</span>";
		if (oChart.SerieLegendPosition == 2) {
			var oLegend = new String("<span style='padding-right:4px;font-family:wingdings;color:" + sColor + "'>l</span>" + sText);
			oLegend.Action = sAction;
			oChart.SerieLegendArray[oChart.LegendCount] = oLegend;
		}
		oChart.LegendCount++;
		if (sText != "")
			oChart.NonEmptyLegendExists = true;
	}
}

function dspChart_CopyValueArray(a) {
	var n = new Array(a.length);
	for(var i=0;i<n.length;i++) {
		n[i] = new Array(a[i].length);
		for(var j=0;j<a[i].length;j++) {
			n[i][j] = new Object(a[i][j]);
		}
	}
	return n;		
}

function dspChart_InitActionProps(oParam) {
	this.Cell = ((oParam.CellActionName!="")?true:false);
	this.CellTooltip = oParam.CellActionDescription.toString();
	var sEvent = " memberid=_MEMBERID_ onmouseover=\"this.style.cursor='hand';this.style.textDecoration='underline'\" onmouseout=\"this.style.textDecoration='none'\"";
	if (oParam.ChartType == 6) {
		this.SerieTooltipAndEvent = (oParam.RowActionName!="")?"title='_TOOLTIP_ " + oParam.RowActionDescription + "' " + sEvent:"title='_TOOLTIP_'";
		this.XLegendEvent = (oParam.ColumnActionName!="")?sEvent:"";
		this.XLegendText = (oParam.ColumnActionName!="")?oParam.ColumnActionDescription:"";
	}
	else {
		this.SerieTooltipAndEvent = (oParam.ColumnActionName!="")?"title='_TOOLTIP_ " + oParam.ColumnActionDescription + "'" + sEvent:"title='_TOOLTIP_'";
		this.XLegendEvent = (oParam.RowActionName!="")?sEvent:"";
		this.XLegendText = (oParam.RowActionName!="")?oParam.RowActionDescription:"";
	}
}

function dspChart_CellActionInfo(oAction, sCellId, sType) {
	if (oAction.Cell) {
		this.Command = " cellid='" + sCellId + "' onmouseover=\"this.style.cursor='hand';this.strokeweight=2\" onmouseout=\"this.style.cursor='none';this.strokeweight=1\""; 
		this.LineCommand = " cellid='" + sCellId + "' onmouseover=\"this.style.cursor='hand';this.stroked=1;this.strokeweight=2\" onmouseout=\"this.style.cursor='none';this.stroked=0\"";
		this.Description = oAction.CellTooltip.replace("_CHARTTYPE_", sType); 
	}
	else {
		this.Command = "";
		this.Description = "";
	}
}

function dspChart_CalcBarTopHeight(iValue, oGraph) {
	var bOutOfLimit = false;
	if (!oGraph.AutoScaleOn) {
		if (oGraph.NegativeAll) {
			if (iValue < oGraph.Max){
				iValue = oGraph.Max;
				bOutOfLimit = true;
			}
			if (iValue > oGraph.Min)
				iValue = oGraph.Min;
		}
		else {
			if (iValue > oGraph.Max)
				iValue = oGraph.Max;
			if (iValue < oGraph.Min) {
				iValue = oGraph.Min;
				bOutOfLimit = !oGraph.Negative;
			}
		}
	}
	var v = Math.floor((iValue-oGraph.ScaleDiff) * oGraph.Scale);
	this.Height = (v<0)?-v:v;
	this.Top = (v<0)?oGraph.ZeroBase:oGraph.ZeroBase-this.Height;
	this.OutOfLimit = bOutOfLimit;
}

function dspChart_CalcStackedTotal(a, s, x) {
	var n = new Array(x);
	for(var i=0;i<x;i++) {
		var v = 0;
		for(var j=0;j<s;j++) 
			v += a[j][i];
		n[i] = v;
	}
	return n;
}

function dspChart_Text(sAxis, divText, s, iWrap, iMaxWidth) {
	divText.className = "dsp-chartlegend-" + sAxis;
	divText.style.whiteSpace = ((iWrap&1)>0)?"normal":"nowrap";
	divText.style.wordWrap = ((iWrap&2)>0)?"break-word":"normal";
	if (iMaxWidth>0 && iWrap > 0) {
		divText.style.width = iMaxWidth;
		divText.style.overflowX = "hidden";
		divText.style.padding = "1px";
	}
	else {
		divText.style.width = "5px";
		divText.style.overflowX = "visible";
	}
	divText.innerHTML = (iWrap==0)?s.replace(/\s/g, "&nbsp;"):s;
	if (iMaxWidth>0 && iWrap > 0)
		this.Width = iMaxWidth;
	else
		this.Width = divText.clientWidth;
	this.Height = divText.clientHeight;
	this.FontFamily = divText.currentStyle.fontFamily;
	this.FontSize = divText.currentStyle.fontSize;
}

function dspChart_DrawXLegend(oGraph, oLineObar, iBarIndex, aLegend, iXCount) {
	var s="", oText, bVertical = oGraph.XLegendVertical, oCaption = null;
	var sTable = "<table bordercolor='silver' border=" + (oGraph.CntMode!=0?"0":"1 frame='void' rules=" + 
		((bVertical)?"'rows'":"'cols'")) + " cellpadding='1px' style='left:" + oGraph.XLegLeft + ";top:" + 
		oGraph.XLegTop + ";table-layout:fixed;position:absolute;border-collapse:collapse;padding:0;margin:0" +
		((bVertical)?";filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'":"'") + " >";
	for (var j=0; j < iXCount; j++) {
		oCaption = new dspChart_XLegCaption(oGraph.NegativeAll, oGraph.CutMode, oGraph.CntMode, ((dspChart_XLegInMode(oGraph.CntMode, j, iXCount))?aLegend[j]:""), oGraph.XLegendWidth, oGraph.XLegendVertical, oGraph.XLegWordWrap);
		if (bVertical)
			s += "<tr><td class='dsp-chartlegend-x dsp-chartlegend-vertical' " + 
				oGraph.Action.XLegendEvent.replace("_MEMBERID_", aLegend[j].MemberId) + 
				" title='" + oCaption.Tooltip + oGraph.Action.XLegendText + "'" + 
				" style='font-family:" + oGraph.XAxisFont.FontFamily + ";font-size:" + 
				oGraph.XAxisFont.FontSize + ";overflow-x:hidden;text-overflow:ellipsis;white-space:" + 
				(((oGraph.XLegWordWrap&1)>0)?"normal":"nowrap") + ";word-wrap:" + 
				(((oGraph.XLegWordWrap&2)>0)?"break-word":"normal") + ";border-color:" + 
				oGraph.BorderColor + ";cursor:default;text-align:" + 
				((oGraph.NegativeAll)?"left": "right") + "'" + 
				" width='" + oGraph.XLegendHeight + "' height='" + oGraph.XLegendWidth + "'>" + 
				oCaption.TextShort + "</td></tr>";
		else 
			s += "<td class='dsp-chartlegend-x' " + 
				oGraph.Action.XLegendEvent.replace("_MEMBERID_", aLegend[j].MemberId) + 
				" valign=" + ((oGraph.NegativeAll)?"bottom":"top") + " align=center title='" + 
				oCaption.Tooltip + oGraph.Action.XLegendText + "'" + 
				" width='" + oGraph.XLegendWidth + "' height='" + oGraph.XLegendHeight + 
				"' style='font-family:" + oGraph.XAxisFont.FontFamily + ";font-size:" + 
				oGraph.XAxisFont.FontSize + ";overflow-x:hidden;text-overflow:ellipsis;white-space:" + 
				(((oGraph.XLegWordWrap&1)>0)?"normal":"nowrap") + ";word-wrap:" + 
				(((oGraph.XLegWordWrap&2)>0)?"break-word":"normal") + ";border-color:" + 
				oGraph.BorderColor + ";cursor:default'>" + 
				oCaption.TextShort + "</td>";
	}
	return sTable + ((bVertical)?"":"<tr>") + s + ((bVertical)?"":"</tr>") + "</table>";
}

function dspChart_XLegHeight(oParam, iWrap, iXLegendWidth) {
	var iHeight=oParam.XAxisFont.Height;
	if (iWrap>0) {
		for (var i=0;i<oParam.XItems.length;i++) {
			var c = new dspChart_Text("x", oParam.MasterTextDiv, oParam.XItems[i], iWrap, iXLegendWidth);
			iHeight = Math.max(c.Height, iHeight);
		}
	}
	return iHeight;
}

function dspChart_XLegWidest(oParam, iCutMode, iWrap, iMaxWidth) {
	var iWidth=0;
	for (var i=0;i<oParam.XItems.length;i++) {
		var s = oParam.XItems[i];	
		if (iCutMode != 0) {
			var a = iCutMode.toString().split(".");
			var iLeft = new Number(a[0]);
			var iRight = new Number(a[1]);
			s = ((iLeft>0)?s.substr(-1, iLeft):"") + ((iRight>0)?s.substr(s.length - iRight):"");
		}
		var c = new dspChart_Text("x", oParam.MasterTextDiv, s, iWrap, iMaxWidth);
		iWidth = Math.max(c.Width, iWidth);
	}
	return iWidth;
}

function dspChart_XLegCaption(iNegAll, iCutMode, iCntMode, sLegend, iLegendWidth, bVertical, iWrap) {
	var	l = sLegend.replace(/'/g, "\\'");
	var s = l;
	if (iCutMode != 0) {
		var a = iCutMode.toString().split(".");
		var iLeft = new Number(a[0]);
		var iRight = new Number(a[1]);
		s = ((iLeft>0)?l.substr(-1, iLeft):"") + ((iRight>0)?l.substr(l.length - iRight):"");
	}
	if (iWrap==0) {
		s = s.replace(/\s/g, "&nbsp;");
		l = l.replace(/\s/g, "&nbsp;");
	}
	this.TextLong = l;
	this.TextShort = s;
	if (sLegend != "")
		this.Tooltip = (sLegend.Tooltip=="")?l:sLegend.Tooltip;
	else
		this.Tooltip = l
}

function dspChart_XLegInMode(iCntMode, j, iXCount) {
	switch (iCntMode) {
		case 1:	return (j==(Math.ceil(iXCount/2)-1)); break;
		case 2:	return (j==0 || j==iXCount-1);break;
		case 3:	return  (j==0 || j==iXCount-1 || (j==(Math.ceil(iXCount/2)-1))); break;
		case 4:	return (j%2==0); break;
		default: return true;
	}
}

