/*###################################################################

Revision history:

Date      | By | Description
----------+----+------------------------------------------
14-Mar-07   RP   Modified from FundsLibrary. Extended to allow addition of equities.
                 Makes use of ChartingWebService functionality.

####################################################################*/

// This script requires SoapAPI.js and ChartingWebService.js, both found at Clients/Core/Scripts.

//######### Variables below can be safely over-ridden by client applications #########

var ImagePath = "Images/"; // over-ride as required.
var ChartColors = "f65d1a,1a83f6,efd715,53e166,8aa3d8,c97dd2,825f2a";  // Used to syncronise the colors used on the chart with javascript.
var PerfTableCumulativeShow = 'QRSB'; // Display [Q]uartile, [R]ankings, [S]ector, [B]lank row
var PerfTableDiscreteShow = 'QRSB';
var PerfTableShowSector = true;

var LegendIconVisible = 'iVisible.gif'; // the path must not be set just yet.
var LegendIconHidden = 'iHide.gif';
var LegendRowModifierFunc = null;  // set to a custom function to modify the legend (minor changes).
var LegendRowAddCustomFunc = null; // set to a custom function to modify the legend (major changes).

// var PeriodTypeValue = '';

//Chart Vars
var span;
var currHiddenCodes = "";
var plotSingleAsPrice = 0;
var visiblePlotNum = 1; //always 1 item by default..

// Over-ride as required.
// Each key needs to have a field with id = 'rgFundType_<key>' associated with it (a radio input field).
// If only one fund category is required, add a hidden field called 'rgFundType' and with value equal to a key.
var Categories = new Array();
Categories[0] = 'Units'; 
Categories[1] = 'ITR'; //Offshore Regulated
Categories[2] = 'UKP'; //UK Pensions
Categories[3] = 'SIB'; 
Categories[4] = 'INS'; 
//####### End Variables that can be over-ridden by client applications #######

var firstRun=true; //added to avoid loading twice

var cws = new ChartingWebService();
var customCWS = new Charting();
var colorCount = -1;
var clrCount = 0;
function pageInitialise() // over-ride as required.
{
	toggleDataSelector('SelectFundBox');
	loadMenu('hdUnitManagerList', 'slctFundManager', 'Select manager...');
	loadMenu('hdUTSector', 'slctFundSector', 'Select sector...');
	loadMenu('hdUTSector', 'slctFundSectorAve', 'Select sector...');
	loadTimeValues('Y', 'slctTimevalue');
	span  = "60";
	firstRun=false;
}

function respPageState(n, ctrl, item)
{
	var pageState = n;
	var control = GetElementById(ctrl);

	//If page state is not equal to 1, then set the cursor to the waiting icon and 
	//draw a loading image control.
	if (pageState != 1)
	{
		document.body.style.cursor='wait';
		control.innerHTML = "<img src=\"" + ImagePath + "spinner.gif\" width=\"15\" height=\"15\" align=\"absmiddle\" class=\"opague\" hspace=\"8\"  /> Loading...";				
	}
	//Page state indicates the item has not loaded yet
	if (pageState != 0)
	{
		document.body.style.cursor='default';
		control.innerHTML="<b>Select " + item + " to add to chart:</b>";				
	}
}

function cLog(e){
	if (window.console){
		window.console.log(e);
	}
}

// This function is used to either show or hide a panel of data, it is used when making radio
// button decisions so that the UI renders appropriately
function toggleDataSelector(lyr)
{
	var visLyr = GetElementById(lyr);
	var visLyrButton = GetElementById(lyr + "Button");
	var elements, className;

	//Retrieve all div tag elements within the ChartBuilder element
	elements = GetElementById("ChartBuilder").getElementsByTagName("div");
	for (var i = 0; i < elements.length; i++)
	{
		// Test if the class name of the element equals SelectorBox and if so then
		// toggle it's visibility to false
		className = "" + elements[i].className;
		if (className.indexOf('SelectorBox') >= 0)
		{
			if (elements[i].id == visLyr.id)	{
				visLyr.style.display = "block";
			}
			else if(elements[i].id.indexOf('Button') >= 0 && elements[i].id == visLyrButton.id)
			{
				if(visLyrButton != null)
				{
					visLyrButton.style.display = "block";
				}
			}
			else
			{
				elements[i].style.display = "none";
			}
			
			/*else{
					elements[i].style.display = "none";
			}*/
		}
	}
}


//	Using the data from the page load event, this determines what the default code
//	should be on the page. This loads the fund and it's sector code, if none exist
//	then the FTSE index 100 is shown and added to the chart.
function SetActiveCode()
{
	var initCode = GetElementById("hdInitCode").value;
	
	if (initCode == "")
	{
		addToChart('');
	}
	else
	{
		addToChart(initCode);
	}
	
	var items = document.frmLegend.cbLegend;
}
	
	
function loadMenu(src, target, title)
{
	var data = GetElementById(src).value;
	var menu = GetElementById(target);
	menu.length = 0;
									
	var slctIndex = 0;
	
	var dataArr = new Array();
	dataArr = data.split(";");
	
	var i,option, optValue, optText, optionArr;
	for (i=0; i <dataArr.length; i++) {
		
		option = dataArr[i]; //eg XYZ, XYZ Investments
		
		optionArr = new Array();
		optionArr = option.split(",");
		
		optValue = optionArr[0]; // XYZ
		optText = optionArr[1]; // XYZ Investments
							
		if (optText!=null){
			menu.options.add(new Option(optText, optValue),0);							
		}	
	}
	
	menu.options.add(new Option(title, ""), 0);
	
	menu.selectedIndex = slctIndex;				
}


function getIndex(src, match){

	var data = GetElementById(src).value;				
	var dataArr = new Array();
	dataArr = data.split(";");
	
	var i, x, option, optValue, optText, optionArr, rtn;
	
	for (i=0; i <dataArr.length; i++) {
		
		option = dataArr[i]; 
		
		optionArr = new Array();
		optionArr = option.split(",");
		
		optValue = optionArr[0]; 
		optText = optionArr[1]; 
		
		if (optValue==match){
			rtn = i;
			break;
		}
	}
	
	rtn = dataArr.length - rtn - 1
	
	return rtn;
}						

function GetCategories()
{
	var categories = '', field = null;
	var selectedcategory;
	
	for (var i = 0; i < Categories.length; i++)
	{
		var fld = GetElementById('rgFundType_' + Categories[i]);
		if (fld == null) continue;
		if (fld.checked) {
			field = fld;
			selectedcategory = i;
			break;
		}
	}
	
	if (field == null)
	{
		field = GetElementById('rgFundType');
		if (field == null) {
			alert('Error: Unable to find any elements with id starting "rgFundType"');
		} else {
			categories = field.value;
		}
	} 
	else {
		categories = field.id.replace('rgFundType_', '');
	}

	// failsafe, user has already been notified above.
	categories = (selectedcategory != '') ? Categories[selectedcategory] : 'UKA,OIC';
	return categories;
}

//################
// Functions which call web services
//##############################
function EquitySearch()
{
	var filter = '';
	var sep = '';
	respPageState(0, 'hdEquityResults');
	var epic = GetElementById('txtEqEPIC').value.replace('"','').replace("'", "").replace('%', '');
	var name = GetElementById('txtEqName').value.replace('"','').replace("'", "").replace('%', '');
	if (epic != '')
	{
		//change at HL's request
		//filter += "Epic LIKE '%" + epic + "%'";
		filter += "Epic = '" + epic + "'";
		sep = ' OR ';
	}
	if (name != '')
	{
		filter += sep + "Name LIKE '%" + name + "%'";
	}
	if(filter != "")
	{
		cws.LoadEquities(LoadEquityList, 'Name', filter);
	}
	else
	{
		respPageState(1, 'hdEquityResults', 'equity');
	}
	//enable 'add' button
	var button = document.getElementById("bt_eqAddToChart");
	button.disabled = false;

	return false;
}

function FundManagerChange()
{
	var code = getValue('slctFundManager');
	var filterIsRip = "IsRIP='"+false+"'";
	cws.LoadUnitsByManagerCode(LoadFundList, GetCategories(), code, '', filterIsRip);
	respPageState(0, 'hdFundResults');
	resetMenu('slctFundSector');
}

function FundSectorChange()
{
	var code = getValue('slctFundSector');
	var filterIsRip = "IsRIP='"+false+"'";
	cws.LoadUnitsBySectorClassCode(LoadFundList, GetCategories(), code, '', filterIsRip);
	respPageState(0, 'hdFundResults');
	resetMenu('slctFundManager');
}

function SectorClassChange(categories)
{
	var isOfficial = false;
	cws.LoadSectors(LoadSectorList, categories, isOfficial);
}

function IndiceListChange(filter)
{
	cws.LoadIndices(LoadIndiceList, 'Name', filter);
}

function FundCategoryChange()
{
	var isOfficial = false;
	cws.LoadManagers(LoadManagerList, GetCategories());
	cws.LoadSectors(LoadFundSectorList, GetCategories(), isOfficial);
}

//################
// Delegates which are called asyncronously by the SoapAPI via functions in previous section.
//##############################
function LoadFundList(r)
{
	LoadOptionList(r, 'slctFundResults', 'funds');

}

function LoadFundSectorList(r)
{
	LoadOptionList(r, 'slctFundSector', 'sectors');
}

function LoadManagerList(r)
{
	LoadOptionList(r, 'slctFundManager', 'managers');
}

function LoadSectorList(r)
{
	LoadOptionList(r, 'slctFundSectorAve', 'sectors');
}

function LoadEquityList(r)
{
	LoadOptionList(r, 'slctEquityResults', 'equities');
}

function LoadIndiceList(r)
{
	var data = r.Items;
	var ary = new Array();
	if (data != null)
	{
		for (var i = 0; i < data.length; i++)
		{
			if (data[i].Name.indexOf('?') >= 0)
			{
				continue;
			}
			ary[ary.length] = data[i];
		}
	}
	r.Items = ary;
	LoadOptionList(r, 'slctIndex', 'indices');
}

//################
// Functions to modify display of chart.
//##############################

/* 
	Parse the URL and retrieve a list of all codes, the hide flag and how many
	months to span the performance data over. Only used for the performance chart
	querystring.
*/
function parseURL(url,r){
	
	var strReturn = "";
				
	var aUrl = url.split("?");					
	var scriptName = aUrl[0];
	
	var allCodes="";
	var hideCodes="";
	var span = "";
	var color = "";
	
	var qStr = new Array();
	var qCodes = new Array();
	var qHide = new Array();
	var qSpan = new Array();
	var qColor = new Array();
					
	if (aUrl.length > 1){
	
		qStr = aUrl[1].split("&");
		
		qCodes = qStr[0].split("=");
			allCodes = qCodes[1];
		
		if(qStr.length > 1){
			qColor = qStr[1].split("=");
			color = qColor[1];
		}
		
		if (qStr.length > 2){						
			qHide = qStr[2].split("=");	
			hideCodes = qHide[1];				
		}
		
		if (qStr.length > 3){
			qSpan = qStr[3].split("=");
			span = qSpan[1];
		}
	}
	
	switch(r){
		case "script":
			strReturn = scriptName;
			break;
		case "codes":
			strReturn =  allCodes;
			break;
		case "hide":
			strReturn =  hideCodes;
			break;
		case "span":
			strReturn =  span;
			break;
		case "color":
			strReturn =  color;
			break;
	}
	
	return strReturn;
}	
			
/* 
	Adds a code to the chart, will only add a chart code to the IMG if the 
	code has not already been selected.
*/
function addToChart(code){

	if(code =="" || code=="X")
	{
		return;
	}

	//Create an array of colors
	var aColors = ChartColors.split(","); 
	
	//Get a reference to the ChartBuilder.aspx image area
	var img = GetElementById("ChartImg");
	var currSrc = img.src;
	var newSrc;				
	
	//Display a chart loading image
	img.src= ImagePath + "chart_loader.gif";
	
	//"codes" refers to the codes used for the image
	var allCodes = parseURL(currSrc,"codes");
	var hiddenCodes = parseURL(currSrc,"hide");
	var color = parseURL(currSrc,"color");
	span = parseURL(currSrc,"span");
	if (span == "") span = document.getElementById("slctTimevalue").value;
	if (span == "") span = "60";
	
	var arr2AllCodes = new Array();
	var arrAllCodes = new Array();
	var arrColor = new Array();
	
	//Retrieve a comma delimited list of all codes
	if (allCodes!=""){
		arr2AllCodes = allCodes.split(",");
		arrColor = color.split(",");
	}
	
	var len = arr2AllCodes.length;		

	var ispresent = false;
	var k=0;
	for(j=0; j<len; j++)
	{
		if(arr2AllCodes[j] != "")
		{
			arrAllCodes[k] = arr2AllCodes[j];
			k++;
		}
	}
	
	len = arrAllCodes.length;	
	for(j=0; j<len; j++)
	{
		if(arrAllCodes[j] == code)
		{
			ispresent = true;
		}
	}
	
	var colorLen = aColors.length;
	var cl = 0;
	var k;
	var count;
	var tempColors = ChartColors.split(","); 

	var c=0;
	var tc;
	
	for(j =0; j <arrColor.length; j++)
	{
		for(k=0; k<colorLen; k++)
		{
		  if(arrColor[j] == aColors[k])
		  {			
				if(k+1 >=10)
				{
					c=0;
				}
				else
				{
					c = k+1;
				}
				tempColors[k] = "";
				tc = aColors[c];
				
		  }
		}
	}

	var boolval = 0;
	var tempcol = "";
	for(j = 0; j<tempColors.length; j++)
	{
		
		if(tempColors[j] != "")
		{
			tempcol += tempColors[j] +",";
		}
	}
	
	var arrtempCol = tempcol.split(",");
	for(j = 0; j<arrtempCol.length; j++)
	{
		
		if(arrtempCol[j] == tc)
		{
			boolval = 1;
		}
	}
	
	 var col;
	if(boolval == 0)
	{
		col = arrtempCol[0];
	}
	else
	{
		col = tc;
	}
	
	/*
	if(cl >= 10)
	{
		cl = cl%10;
	}
	alert(" Color :"+ cl);*/
	
	//If the code is not already on the graph, then it needs to be added
	if (!ispresent){
						
		//If less than 10 codes are present
		if (len < 7){
			
			//Add the code to the array
			arrAllCodes[len] = code;
			arrColor[len] = col;
			
			//Concatenate array elements into a single string
			var strCodes = arrAllCodes.join();
			var color = arrColor.join();
			var totalReturn = GetElementById("rd_totalReturn").checked;
			//Add new codes to the IMG tag source
			newSrc = "chartbuilder.aspx?codes=" + strCodes + "&color=" + color + "&hide=" + hiddenCodes + "&span=" + span + "&totalReturn=" +totalReturn ;	
			
			//added to check for % mode or currency mode
			plotSingleAsPrice = GetElementById("chk_plotSingleAsPrice").checked;
	        if(len<1&&plotSingleAsPrice)
	        {   
	        
		        newSrc =newSrc+'&plotSingleAsPrice=' + plotSingleAsPrice +  '&yAxisLabel=_';
        		//alert(newSrc);
	        }
			
			img.src = newSrc;
						
			cws.LoadInstruments(updateLegend, strCodes);
			cws.LoadPerformance(updatePerformanceTables, strCodes, '');

			var chartAxisOptions = document.getElementById("ChartAxis");
			var unhideCodes="";
			for(var k=0; k<arrAllCodes.length;k++) {
				if(!IsStringFoundInArray(hiddenCodes, arrAllCodes[k])) {
					unhideCodes += (unhideCodes.length == 0) ? arrAllCodes[k] : ","+arrAllCodes[k];
				}
			}
			var arrUnhideCodes = unhideCodes.split(",");
			var hideLen = arrUnhideCodes.length;
			
			if (hideLen > 1){
				chartAxisOptions.className = "CAO_Off";
			}
			else if(hideLen == 1) {
					chartAxisOptions.className = "CAO_On";
					
			}
			else {
			
				chartAxisOptions.className = "CAO_Off";
			}
		}
		else {
			img.src=currSrc;
			alert("Maximum of 7 instruments");
			
		}
	}
	else 
	{
		
		//No changes were needed to the graph
		img.src=currSrc;
	}
	
}

function IsStringFoundInArray(array, stringValue)
{
    var found = false;
    for(var i=0; i< array.length; i++)
    {
        if(array[i] == stringValue)
        {
            found = true;
            break;
        }
    }   
    return found;
}

//Will round a number to two decimal places and add a percent sign
function roundPercentage(number) {
	if (number > 99999) return "-";
	return Math.round(number*100)/100 + "%";
}

//Used to tidy the output if no ranking data exists
function getRank(rank, total) {
	if (rank<0 || rank==2147483647) return "-";
	return rank + "/" + total;	
}

//Used to tidy the output
function getQuartile(value) {
	if (value<0 || value==2147483647) return "-";
	return value;	
}

function updatePerformanceTables(r)
{
	UpdatePerfTablesSub(r, true);
	UpdatePerfTablesSub(r, false);
}

function updatePerformanceTableCum(r)
{
	UpdatePerfTablesSub(r, true);
}

function updatePerformanceTableDisc(r)
{
	UpdatePerfTablesSub(r, false);
}

function UpdatePerfTablesSub(r, isCumulative)
{
	var perfTableShow = (isCumulative ? PerfTableCumulativeShow : PerfTableDiscreteShow);
	var pfText = (isCumulative ? 'Cumulative' : 'Discrete');
	var addRowFunc = (isCumulative ? addCumulativePerformanceRow : addDiscretePerformanceRow);
	
	// if we can't find PerfTables division, then don't do anything.
	/*
	if (GetElementById('PerfTables') == null)
	{
		return;
	}
	*/
	
	var coreFund = GetElementById("hdFundCode").value;
	var coreSector = GetElementById("hdSectorCode").value;
	
	var data = r.PerfItems;
	
	var performanceTable = GetElementById("tbl" + pfText + "Performance", false);
	
	if (performanceTable == null)
	{
		return;
	}

	var performanceBody = GetElementById("tbdy" + pfText + "Performance", false);
	
	if (performanceBody) performanceTable.removeChild(performanceBody);
	
	var performanceBody = document.createElement("tbody");
	
	performanceBody.id = "tbdy" + pfText + "Performance";
	performanceTable.appendChild(performanceBody);
	var img = GetElementById("ChartImg");
	var currSrc = img.src;	
	var allCodes = parseURL(currSrc, "codes");
	var color = parseURL(currSrc, "color");
	var arrAllCodes = new Array();
	var arrColor = new Array();
	var numCodes = 0;
	var numCoreRows = 0;
	var numPerfItems = data.length;
	
	if (allCodes!="")
	{
		arrAllCodes = allCodes.split(",");
		arrColor = color.split(",");
		numCodes = arrAllCodes.length;															
	}
	
	var lastItem = numCodes - 1;

	// Load core fund & sector performance, quartiles & rankings
	var x = 0;
	for (var i = 0; i < numCodes; i++)
	{
		if(data[i] == null)
		{
			return;
		}

		if (i < lastItem && data[i].Code == coreSector)
		{
			arrAllCodes.splice(i, 1); // remove it
			arrColor.splice(i, 1);
			
			arrAllCodes[lastItem] = coreSector; // stick it at the end 
			
			var tmp = data[i];
			data.splice(i, 1);
			data[lastItem] = tmp;
			
			i--; // backtrack
			
			continue;
		}
					
		if (data[i].Code == coreFund)
		{
			// Core Fund Performance rows
			var fundRow = performanceBody.insertRow(0);
			addRowFunc(fundRow, data, i, data[i].Name, "P");
			numCoreRows++;
			
			// Core Fund Rankings
			if (perfTableShow.indexOf('R') >= 0)
			{
				var fundRankRow = performanceBody.insertRow(1);
				addRowFunc(fundRankRow, data, i, "Rank in sector", "R");
				numCoreRows++;
			}
			
			// Core Fund Quartiles
			if (perfTableShow.indexOf('Q') >= 0)
			{
				var fundQuartileRow = performanceBody.insertRow(2); 
				addRowFunc(fundQuartileRow, data, i, "Quartile", "Q");
				numCoreRows++;
			}
			
			x = 1;
		}
		
		if (perfTableShow.indexOf('S') >= 0)
		{
			if (i == lastItem && data[i].Code == coreSector)
			{
				// Core Sector erformance rows
				var sectorRow = performanceBody.insertRow(x);
				addRowFunc(sectorRow, data, i, data[i].Name, "P");
				numCoreRows++;
			}
		}
	}

	var posToAddNewRow = numCoreRows;

	// Add seperator 
	if (posToAddNewRow > 0 && perfTableShow.indexOf('B') >= 0)
	{
		var blankRow = performanceBody.insertRow(posToAddNewRow);
		addRowFunc(blankRow, data, 0, "", "B");
		posToAddNewRow++;
	}

	// Load user selected instruments

	var tmpArr = new Array();
	tmpArr = arrAllCodes;
	
	for (var i = 0; i < tmpArr.length; i++)
	{
		if (tmpArr[i] == coreFund)
		{
			tmpArr.splice(i, 1);
		}
		if (tmpArr[i] == coreSector)
		{
			tmpArr.splice(i, 1);
		}
	}

	// Order data
	if (tmpArr.length > 0)
	{
		for (var i = 0; i < tmpArr.length; i++)
		{
			for (var x = 0; x < data.length; x++)
			{
				if (data[x].Code == tmpArr[i])
				{
					var fundRow = performanceBody.insertRow(posToAddNewRow);
					addRowFunc(fundRow, data, x, data[x].Name, "P");
					posToAddNewRow++;
					break;
				}
			}
		}
	}		
}


function addDiscretePerformanceRow(row, data, m, title, type)
{
	//var tdCells = createCells(row, 6, 'titleCell', 'numberData');
	var tdCells = createCells(row, 6, 'smallPref', 'perfright');
	
	SetInnerText(tdCells[0], title);

	switch (type)
	{
		case "P":	// Performance
			SetCellsToPropVals(
				tdCells, 1, data[m],
				//['P48t60', 'P36t48', 'P24t36', 'P12t24', 'P12'],
				['P48t60','P36t48' , 'P24t36', 'P12t24', 'P12'],
				roundPercentage
			);
			break;
		case "R":	// Ranking
			SetCellsToPropVals(
				tdCells, 1, data[m],
				['RY4', 'RY3', 'RY2', 'RY1', 'RYTD'],
				['TY4', 'TY3', 'TY2', 'TY1', 'TYTD'],
				getRank
			);
			break;
		case "Q":
			SetCellsToPropVals(
				tdCells, 1, data[m],
				['QY4', 'QY3', 'QY2', 'QY1', 'QYTD'],
				getQuartile
			);
			break;			
		case "B":
			for (var i = 0; i < tdCell.length; i++)
			{
				SetInnerText(tdCells[i], ' ');
				tdCells[i].className = 'emptyCell';
			}
			break;
	}
}


function addCumulativePerformanceRow(row, data, m, title, type)
{
	//var tdCells = createCells(row, 6, 'titleCell', 'numberData');
	var tdCells = createCells(row, 6, 'smallPref', 'perfright');

	SetInnerText(tdCells[0], title);

	switch (type)
	{
		case "P":	// Performance
			SetCellsToPropVals(
				tdCells, 1, data[m],
				['P3', 'P6', 'P12', 'P36', 'P60'],
				roundPercentage
			);
			break;
		case "R":	// Ranking
			SetCellsToPropVals(
				tdCells, 1, data[m], 
				['R3', 'R6', 'R12', 'R36', 'R60'], 
				['T3', 'T6', 'T12', 'T36', 'T60'],
				getRank
			);
			break;
		case "Q":
			SetCellsToPropVals(
				tdCells, 1, data[m],
				['Q3', 'Q6', 'Q12', 'Q36', 'Q60'],
				getQuartile
			);
			break;
		case "B":
			for (var i = 0; i < tdCells.length; i++)
			{
				SetInnerText(tdCells[i], ' ');
				tdCells[i].className = 'emptyCell';
			}
			break;
	}
}		


// This function can take either 5 or six parameters.
// The last parameter will always be a function reference.
// Either one or two property arrays can be supplied (depending on whether valueFixFunc takes 1 or 2 parameters).
function SetCellsToPropVals(tdCells, startAt, data, props1) // optional parameters: (props2, valueFixFunc)
{
	var value1, value2 = null, props2 = null, propIdx;
	var paramIdx = arguments.length;
	Debug(paramIdx < 5 || paramIdx > 6, "Incorrect number of parameters supplied to SetCellsToPropVals().");

	paramIdx--;
	if (paramIdx == 5)
	{
		props2 = arguments[paramIdx - 1];
	}
	var valueFixFunc = arguments[paramIdx];

	propIdx = 0;
	for (var i = startAt; i < tdCells.length; i++)
	{
		value1 = GetPropertyFrom(data, props1[propIdx]);
		if (props2 != null)
		{
			value2 = GetPropertyFrom(data, props2[propIdx]);
		}
		if (valueFixFunc != null)
		{
			value1 = valueFixFunc(value1, value2);
		}
		SetPropertyTo(tdCells[i], 'innerText', value1);
		propIdx++;
	}
}


function SetPropertyTo(target, targetProp, value)
{
	if (targetProp == 'innerText')
	{
		SetInnerText(target, value);
	}
	else
	{
		try
		{
			if (typeof(value) == "string")
			{
				value = "'" + value.replace(/'/gi, "\\'") + "'";
			}
			eval("target." + targetProp + " = " + value);
		}
		catch (ex)
		{
			Debug(true, "Unable to set property '" + targetProp + "' to '" + value + "'");
		}
	}
}


function GetPropertyFrom(data, prop)
{
	var res = null;
	eval('res = data.' + prop);
	return res;
}


//Creates an array of cells, need to add a switch for using numberData class
function createCells(row, num, classCell1, classCellRest)
{
	var tdArray = new Array(num);
	var last = null;
	for (var i = 0; i < tdArray.length; i++)
	{
		tdArray[i] = row.insertCell(i);
		tdArray[i].className = (i == 0 ? classCell1 : classCellRest);
	}
	return tdArray;
}

function updateLegend(r)
{
	var data = r.Items;
	var img = GetElementById("ChartImg");
	var currSrc = img.src;	
	var hiddenCodes = parseURL(currSrc, "hide");
	var color = parseURL(currSrc, "color");
	var chartCodes =  parseURL(currSrc, "codes");
	var aLegendColours = new Array(data.length);	
	
	var aChartCodes = chartCodes.split(",");
	var aColors = color.split(",");
	
	//The colours are set in order of the codes that appear on the chart but the webservice that returns
	//the fund details for the legend returns them in a different order. You can't just link the colours to the
	//funds in the order as on the chart. A change to the order of colours is performed here so the same corresponding code
	//in the legend has the colour as it does on the chart due to the different ordering.
	
    for (var i=0; i < data.length; i++)
	{
	    for (var x=0; x < aChartCodes.length; x++)
	    {
	        if (data[i].Code == aChartCodes[x])
	        {
	            aLegendColours[i] = aColors[x];	           
	            break;
	        }
	    }	
	}
	
	var oTable = GetElementById("tblLegend");
	var oTBody = GetElementById("tbdyLegend");
	
	if (oTBody)
	{
		// This section prevents the removal of navigation rows in the body of the table (put there by the client).
		// If the row is a navigation (or stylistic) row then it will be designated with attribute NotData = true.
		var navRow = null;
		for (var i = 0; i < oTBody.childNodes.length; i++)
		{
			var oRow = oTBody.childNodes[i];			
			if (oTBody.flaggedRows == null)
			{
				oRow.NotData = true;
			}
			else if (oRow.NotData == null)
			{
				oTBody.removeChild(oRow);
				i--; // to counter the removal.
			}
			if (navRow == null && oRow.NotData == true)
			{
				navRow = oRow;
			}
		}
		oTBody.flaggedRows = true;
		
		if (LegendRowAddCustomFunc == null)
		{
			LegendRowAddCustomFunc = LegendRowAdd;
		}
		
		//Set global row num
		visiblePlotNum = data.length;
		
		// insert a new row for each code
		for (var m = 0; m < data.length; m++)
		{
			var oRow = document.createElement("tr");
			var isHidden = (hiddenCodes.indexOf(data[m].Code) >= 0);
			oRow.id = "i" + (m + 1);
			oTBody.insertBefore(oRow, navRow);
			if(m % 2 == 0)
			{
				classname = "odd";
			}
			else
			{
				classname = "even";
			}
			LegendRowAddCustomFunc(oRow, data[m], aLegendColours[m], isHidden, classname);
		}
	}
}

// This is the default version. If it is not over-ridden by the client then this version will be used.
function LegendRowAdd(oRow, instr, color, isHidden, classname)
{
	var cells = LegendRowAddCells(oRow, 5);
	
	cells[0].className = classname;
	cells[0].innerHTML = '<center><input type="checkbox" name="cbLegend" id="cb' + instr.Code + '" value="' + instr.Code + '" /><center>';
	
	var icon = ImagePath + LegendIconVisible;
	if (isHidden)
	{
		icon = ImagePath + LegendIconHidden;
	}
	
	cells[1].className = classname;
	cells[1].innerHTML = '<center><img src="' + icon + '" id="i' + instr.Code + '" /></center>';
		
	cells[2].className = classname;
	cells[2].innerHTML = '<center><div name="cbKey" class="key" style="background-color:#' + color + '"/></center>';
	
	cells[3].className = classname;
	cells[3].innerHTML = getInstType(instr.Code);

	cells[4].className = classname;
	var txtNode= document.createTextNode(instr.Name);
	cells[4].appendChild(txtNode);
}

function LegendRowAddCells(oRow, cellCount)
{
	var cells = [];
	var className = 'legendCell';
	for (var i = 0; i < cellCount; i++) 
	{
		var cell = oRow.insertCell(i);
		cell.className = className + (i + 1);
		cells[i] = cell;
	}
	return cells;
}


// This fixes all the nasty <, >, &, etc characters.
// The result is an HTML encoded string.
function MakeTextSafe(text)
{
	var td = document.createElement('td');
	SetInnerText(td, text);
	Debug(true, td.innerHTML);
	td = td.innerHTML.replace('<td>', '').replace('</td>', '');
	return td;
}


function SetInnerText(node, innerText)
{
	var text = document.createTextNode(innerText);
	node.insertBefore(text, null);
}


// fieldName is optional.
function removeInstrument(fieldName)
{
	var img = GetElementById("ChartImg");
	var currSrc = img.src;	
	var cHiddenCodes = parseURL(currSrc,"hide");
	var color = parseURL(currSrc,"color");
	span = parseURL(currSrc,"span");
		
	if (fieldName == null) fieldName = 'cbLegend';
	var items = document.frmLegend[fieldName];
	
	var arrColor = color.split(',');
	var aCodes = new Array();
	var hCodes = new Array();	
	var aColor = new Array();			
	var a=0;
	var h=0;

	
	if(items)
	{
		if(items.length)
		{
			var chartAxisOptions = document.getElementById("ChartAxis");
			if(items.length == 1){
				chartAxisOptions.className = "CAO_On";
			}
			else{
				chartAxisOptions.className = "CAO_Off";
			}
			
			for (var i=0; i<items.length; i++)
			{
				if (items[i].checked==false)
				{
					aCodes[a] = items[i].value;
					aColor[a] = arrColor[i];
					a++;
				
					if (cHiddenCodes.indexOf(items[i].value) >= 0)
					{
						hCodes[h] = items[i].value;
						h++;
					}
				}
			}
			//see if 1 remains from items minus the visible items.. (no 'hidden' enumerator)
			if((items.length - (items.length - a)) == 1){
				chartAxisOptions.className = "CAO_On";
			}
			else{
				chartAxisOptions.className = "CAO_Off";
			}
			
		}
		else
		{
			if (items.checked==false)
			{
				aCodes[a] = items.value;
				aColor[a] = arrColor[0];
				a++;
				
				if (cHiddenCodes.indexOf(items.value) >= 0)
				{
					hCodes[h] = items.value;
					h++;
				}
			}
		}	
	}
	
	var strCodes = aCodes.join();		
	var hidCodes = hCodes.join();
	var colors = aColor.join();
	var totalReturn = GetElementById("rd_totalReturn").checked;
	plotSingleAsPrice = GetElementById("chk_plotSingleAsPrice").checked;
	if (aCodes.length > 0){
	
	    var newSrc="chartbuilder.aspx?codes=" + strCodes + "&color=" + colors +"&hide=" + hidCodes + "&span=" + span + "&plotSingleAsPrice=" + plotSingleAsPrice +"&totalReturn=" +totalReturn;					

        //added to check for % mode or currency mode    	
	    if((getCodesCount(strCodes)-getCodesCount(hidCodes))==1&&plotSingleAsPrice)
	    {   //alert(aCodes.length);
		    newSrc =newSrc+'&yAxisLabel=_';
    		
	    }
		GetElementById("ChartImg").src=newSrc;
		
	}else {
		GetElementById("ChartImg").src="chartbuilder.aspx";												
	}
	
	cws.LoadInstruments(updateLegend, strCodes);
	//if (GetElementById('PerfTables', false) != null)
	//{
		//#### When changing these values, please ensure that you *copy* them to the duplicate code at around line 464. ####
		//PeriodTypeValue = ''; 
		cws.LoadPerformance(updatePerformanceTableCum, strCodes, '');
		//PeriodTypeValue = '';
		cws.LoadPerformance(updatePerformanceTableDisc, strCodes, '');
	//}
	
	var unhideCodes="";
	for(var k=0; k<aCodes.length;k++) {
		if(!IsStringFoundInArray(hCodes, aCodes[k])) {
			unhideCodes += (unhideCodes.length == 0) ? aCodes[k] : ","+aCodes[k];
		}
	}
	var arrUnhideCodes = unhideCodes.split(",");
	var len = arrUnhideCodes.length;
	
	if (len > 1){
		chartAxisOptions.className = "CAO_Off";
	}
	else if(len == 1 && arrUnhideCodes[0].substring(0,1) != "E") {
		var chartAxisOptions = document.getElementById("ChartAxis");
		chartAxisOptions.className = "CAO_On";
	}
	else {
		//chartAxisOptions.className = "CAO_Off";
		chartAxisOptions.className = "CAO_On";
	}
	document.frmLegend.cbSelectAll.checked=false;
}


function toggleInstrument(action)
{

	//debugger;
	var img = GetElementById("ChartImg");
	var currSrc = img.src;	
	var items = document.frmLegend.cbLegend;
	
	// All codes
	var aAllCodes = new Array();
	var strCodes = "";		
	
	// Get Color 
	var color = parseURL(currSrc,"color");
	var arrColor = color.split(',');
	var aColor = new Array(); 
	
	// Get hidden code stuff
	currHiddenCodes = parseURL(currSrc,"hide");
	var aHideCodes = new Array();				
	var hCodeLen = 0;
	var hideCodes = "";
	
	if (currHiddenCodes!=""){
		aHideCodes = currHiddenCodes.split(",");
		hCodeLen = aHideCodes.length;
	}


	// Get span 
	span = parseURL(currSrc,"span");
	var a = 0;
	var shown = 0;
	if(items)
	{
		if(items.length)
		{
	
			for (var i=0; i<items.length; i++)
			{
				var chartAxisOptions = document.getElementById("ChartAxis");
				aAllCodes[i] = items[i].value;
				aColor[i] = arrColor[i];
				// Hide instruments
				if (action=="hide")
				{
					if (currHiddenCodes.indexOf(items[i].value) < 0)
					{
						if (items[i].checked)
						{
							//exit function if only 1 visible item available.
//							if (items.length == (hCodeLen + 1)){
//								alert("Cannot hide only visible item in list");
//								return false;
//							}
							aHideCodes[hCodeLen] = items[i].value;								
							GetElementById("i" + items[i].value).src = ImagePath + "iHide.gif"
							hCodeLen++;
						}
					}
				}
		
				// Show instruments
				if (action=="show")
				{
					aHideCodes.length=a;
					if (currHiddenCodes.indexOf(items[i].value) >= 0) 
					{
						if (items[i].checked==false)
						{
							aHideCodes[a] = items[i].value;	
							a++;
						}
						else 
						{
							GetElementById("i" + items[i].value).src = ImagePath + "iVisible.gif";
							shown++
						}
					}					
				}
				items[i].checked=false;
			}
			//hide/show chartAxis option
			//detract 'shown' items from hidden list and see if that leaves more than one item visible..
			if((items.length - (hCodeLen - shown)) < 2){
				chartAxisOptions.className = "CAO_On";
			}
			else{
				chartAxisOptions.className = "CAO_Off";
			}
			ChartUpdate(aAllCodes.join(), aColor.join(), aHideCodes.join(), span);
		}
		else if(action == "hide")
		{
			//can't hide only item in list!
			//alert("Cannot hide only item in list");
			items.checked = false;
			return false;
//			if (currHiddenCodes.indexOf(items.value) < 0)
//			{
//				if (items.checked)
//				{
//					aHideCodes[hCodeLen] = items.value;								
//					GetElementById("i" + items.value).src = ImagePath + "iHide.gif"
//					hCodeLen++;
//					ChartUpdate(aAllCodes.join(), aHideCodes.join(), span);
//				}
//			}
//			items.checked = false;
		}
		else if(action == "show")
		{
			var itemchecked = 0;
			if(aHideCodes.length > 0)
			{
				aAllCodes[0] = items.value;
				aColor[0] = arrColor[0];
				aHideCodes.length=a;
				if (currHiddenCodes.indexOf(items.value) >= 0) 
				{
					if (items.checked==false){
						aHideCodes = items.value;	
						a++;
					}
					else {
						itemchecked = 1;
						GetElementById("i" + items.value).src = ImagePath + "iVisible.gif"															
					}
				}
				items.checked = false;
				if(itemchecked == 1)
				{
					ChartUpdate(aAllCodes.join(), aColor.join(), aHideCodes.join(), span);
				}
			}
		}
	}
	
	var unhideCodes="";
	for(var k=0; k<aAllCodes.length;k++) {
		if(!IsStringFoundInArray(aHideCodes, aAllCodes[k])) {
			unhideCodes += (unhideCodes.length == 0) ? aAllCodes[k] : ","+aAllCodes[k];
		}
	}
	var arrUnhideCodes = unhideCodes.split(",");
	var len = arrUnhideCodes.length;
	if (len > 1){
		chartAxisOptions.className = "CAO_Off";
	}
	else if(len == 1 && arrUnhideCodes[0].substring(0,1) != "E") {
	var chartAxisOptions = document.getElementById("ChartAxis");
	chartAxisOptions.className = "CAO_On";
	}
	else {
		//chartAxisOptions.className = "CAO_Off";
		chartAxisOptions.className = "CAO_On";
	}
	document.frmLegend.cbSelectAll.checked=false;
}


function ChartUpdate(allCodes, color, hideCodes, span)
{
	//Get options
	plotSingleAsPrice = GetElementById("chk_plotSingleAsPrice").checked;
	var totalReturn = GetElementById("rd_totalReturn").checked;
	
	var newSrc="chartbuilder.aspx?codes=" + allCodes + "&color=" + color + "&hide=" + hideCodes + "&span=" + span + "&plotSingleAsPrice=" + plotSingleAsPrice + "&totalReturn=" +totalReturn;		
	//added to check for % mode or currency mode
	if((getCodesCount(allCodes)-getCodesCount(hideCodes))==1&&plotSingleAsPrice)
	{   
		newSrc =newSrc+ '&yAxisLabel=_';
		
	}
	//alert(hideCodes+" and "+allCodes);
	GetElementById("ChartImg").src=newSrc;
	
}

//Returns a full descriptive name from an instrument type code
function getInstType(code)
{
		var t = code.substring(0,1);
		var r = "";
		
		switch (t){
			case "F":
				r="<center><img src=\"Images/typeFund.gif\" alt=\"Fund\"  /></center>";
				break;
			case "E":
				r="<center><img src=\"Images/typeEquity.gif\" alt=\"Equity\"  /></center>";
				break;
			case "N":
				r="<center><img src=\"Images/typeIndex.gif\" alt=\"Index\"  /></center>";
				break;
			case "X":
				r="<center><img src=\"Images/typeSector.gif\" alt=\"Sector\"  /></center>";
				break;
		}
			
		return r;
}

function disableCtrl(ctrl)
{
	GetElementById(ctrl).disabled=true;
}

function enableCtrl(ctrl)
{
	GetElementById(ctrl).disabled=false;
}

function resetMenu(ctrl)
{
	GetElementById(ctrl).selectedIndex = 0;
}

function clearMenu(ctrl)
{
	var menu = GetElementById(ctrl)
	menu.options.length = 0;
	menu.options.add(new Option("Results...", ""));
}

//Simply erases the text content of an element
function clearField(ctrl)
{
	GetElementById(ctrl).value = "";
}

//Returns the value of a control
function getValue(ctrl)
{
	return GetElementById(ctrl).value;
}

function tempFunction(r)
{
	
	data = r.Items;
	
	if (data != null)
	{
		alert(data[0].Name);
	}
}

//Sets browser focus on a control
function setFocus(ctrl)
{
	var control = GetElementById(ctrl);
	control.focus();
}

function loadTimeValues(val, ctrl)
{
	var options = null, selectedIndex = 0;
	var menu = GetElementById(ctrl);
	menu.options.length = 0;

	if (val == "D")
	{
		options = new Array("W7:1 week", "W14:2 weeks", "W21:3 weeks", "W28:4 weeks");
		selectedIndex = 3;
	}
	else if (val == "M")
	{
		options = new Array("M18:18 Months", "M12:12 Months", "M6:6 Months", "M3:3 Months", "M1:1 Month");
		selectedIndex = 4;
	}
	else
	{
		options = new Array("M60:5 Years", "M36:3 Years", "M12:1 Year");
		selectedIndex = 2;
	}

	var span = 0;
	for (var i = 0; i < options.length; i++)
	{
		var option = options[i];
		var optionArr = option.split(":");
			
		var optValue = optionArr[0];
		var optText = optionArr[1];
		if(i == 0)
		{
		 span = optValue;
		}

		
		menu.options.add(new Option(optText, optValue), 0);		
	}
	
	menu.selectedIndex = selectedIndex;
	
	if(!firstRun)
	{ changeTimescale(span); 
	 }
}

function GetPriceType()
{
    return GetElementById('rd_priceReturn').checked ? '' : 'TR';
}

function PriceOrTotalReturn()
{
	//var price = GetElementById("rd_priceReturn").checked;
	var img = GetElementById("ChartImg");
	var currSrc = img.src;
	var script = parseURL(currSrc,"script")	
	var allCodes = parseURL(currSrc,"codes")
	var hiddenCodes = parseURL(currSrc,"hide");
	var color = parseURL(currSrc,"color");
	span = parseURL(currSrc,"span");
	plotSingleAsPrice = GetElementById("chk_plotSingleAsPrice").checked;
	
	var totalReturn = GetElementById("rd_totalReturn").checked;
	var newSrc = script + "?codes=" + allCodes + "&color=" + color + "&hide=" + hiddenCodes + "&span=" + span + "&plotSingleAsPrice=" + plotSingleAsPrice + "&totalReturn=" +totalReturn;
    
    if((getCodesCount(allCodes)-getCodesCount(hiddenCodes))==1&&plotSingleAsPrice)
	{   
		newSrc += "&yAxisLabel=_";
		
	}
	
	img.src = newSrc;
}
function changeTimescale(val)
{				

	var img = GetElementById("ChartImg");
	var currSrc = img.src;
	plotSingleAsPrice = GetElementById("chk_plotSingleAsPrice").checked;
	var script = parseURL(currSrc,"script")	
	var allCodes = parseURL(currSrc,"codes")
	var hiddenCodes = parseURL(currSrc,"hide");
	var color = parseURL(currSrc,"color");
	var totalReturn = GetElementById("rd_totalReturn").checked;
	var newSrc = script + "?codes=" + allCodes + "&color=" + color + "&hide=" + hiddenCodes + "&span=" + val + "&plotSingleAsPrice=" + plotSingleAsPrice + "&totalReturn=" +totalReturn;
	
	if((getCodesCount(allCodes)-getCodesCount(hiddenCodes))==1&&plotSingleAsPrice)
	{   
		newSrc += "&yAxisLabel=_";
		
	}
					
	img.src = newSrc;
}

function getCodesCount(codes)
{
  var temp=codes.split(",");
  
  var result=new Array();
  var j=0;
  for(var i=0;i<temp.length;i++)
  {
    if(temp[i]!="")
    { result[j]=temp[i];
      j++;
     }
  }
  return result.length;
}

function toggleChb()
{
	var cbAll = document.frmLegend.cbSelectAll;
	var items = document.frmLegend.getElementsByTagName("input");
	var len = items.length;
	
	var state = false;	
	
	if (cbAll.checked){
		state=true;					
	}		
	
	for (var i=0; i<len; i++){
		if(items[i].name=="cbLegend")
		{ items[i].checked=state;
		}
		
	}
}

function displayFull(ctrl)
{
	var menu = GetElementById(ctrl);
	menu.title=menu.options[menu.selectedIndex].text;
}
				
function LoadOptionList(xmlResult, selectControl, itemPlural)
{
	var data = null;
	var sc = selectControl;
	
	if (sc != null && sc.options == null)
	{
		sc = GetElementById(sc);
	}
	
	Debug(sc == null || sc.options == null, 'LoadOptionList parameter selectControl "' + selectControl + '" could not be resolved.');
	
	sc.options.length = 0;

	if (xmlResult == null || xmlResult.Items == null)
	{
		return;
	}
	
	data = xmlResult.Items;

	InfoFirstItem(sc, data.length, itemPlural);

	for (var i = 0; i < data.length; i++)
	{
		sc.options.add(new Option(data[i].Name, data[i].Code), sc.options.length);
	}
	if(itemPlural == 'funds')
	{
		respPageState(1, 'hdFundResults', 'fund');
	}
	else if(itemPlural == 'equities')
	{
		respPageState(1, 'hdEquityResults', 'equity');
	}
}
