/*###################################################################

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,#322d26,#09b0e9,#7ef1f0";  // 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 PanelHideType = "visibility"; // can be 'visibility' or 'display'

var LegendIconVisible = 'iView.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).

// 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['Units'] = 'UKA,OIC'; 
Categories['Offshore'] = 'OFI'; //Offshore Regulated
//####### End Variables that can be over-ridden by client applications #######

var cws = new ChartingWebService();

function pageInitialise() // over-ride as required.
{
	toggleDataSelector('SelectFundBox');
	loadMenu('hdUnitManagerList', 'slctFundManager', 'Select manager...');
	loadMenu('hdUTSector', 'slctFundSector', 'Select sector...');
	loadMenu('hdSector', 'slctFundSectorAve', 'Select sector...');
	loadTimeValues('Y', 'slctTimevalue');

}

function respPageState(n, ctrl)
{
	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="<h2>Select fund to add to chart:</h2>";				
	}
}


// 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 elements, className;

	//Retrieve all div tag elements within the ChartBuilder element
	elements = GetElementById("ChartBuilder").getElementsByTagName("div");
	for (var i in elements)
	{
		// 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 (PanelHideType == "display")	{
				elements[i].style.display = "none";
			} else {
				elements[i].style.visibility = "hidden";
			}
		}
	}
	
	//Display the selection element matching the parameter lyr only
	if (PanelHideType == "display") {
		visLyr.style.display = "block";
	}	else {
		visLyr.style.visibility = "visible";
	}
}


//	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;
	
	for (var i = 0; i < Categories.length; i++)
	{
		var fld = GetElementById('rgFundType_' + Categories[i]);
		if (fld == null) continue;
		if (fld.checked) {
			field = fld;
			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 = (categories != '') ? Categories[categories] : 'UKA,OIC';
	
	return categories;
}

//################
// Functions which call web services
//##############################
function EquitySearch()
{
	var filter = '';
	var sep = '';
	var epic = GetElementById('txtEqEPIC').value.replace('"','').replace("'", "").replace('%', '');
	var name = GetElementById('txtEqName').value.replace('"','').replace("'", "").replace('%', '');
	if (epic != '')
	{
		filter += "Epic LIKE '%" + epic + "%'";
		sep = ' OR ';
	}
	if (name != '')
	{
		filter += sep + "Name LIKE '%" + name + "%'";
	}
	cws.LoadEquities(LoadEquityList, 'Name', filter);
}

function FundManagerChange()
{
	var code = getValue('slctFundManager');
	if(code != '')
	{
	    cws.LoadFundsByManagerCode(LoadFundList, GetCategories(), code);
	}
	else
	{
	    clearMenu('slctFunds');
	}
	clearMenu('slctUnits');
}

function FundChange()
{
    var code = getValue('slctFunds');
    if(code != '')
    {
        cws.LoadUnitsByFundCode(LoadUnitList, code);
    }
    else
    {
        clearMenu('slctUnits');
    }
}

function UnitChange()
{
    var code = getValue('slctUnits');
    if(code == 'mul')
    {
        checkMultiSelect();
    }
    else if(code == '')
    {
        changeSelectSize();
    }
}


function FundSectorChange()
{
	var code = getValue('slctFundSector');
	cws.LoadUnitsBySectorClassCode(LoadFundList, GetCategories(), code);
	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, 'slctFunds', 'funds');
	if(r.Items.length == 1)
	{
	    FundChange();
	}
	//respPageState(1, 'hdFundResults');
}

function LoadUnitList(r)
{
	LoadOptionList(r, 'slctUnits', 'units');
	//respPageState(1, 'hdFundResults');
}

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 qStr = new Array();
	var qCodes = new Array();
	var qHide = new Array();
	var qSpan = new Array();
					
	if (aUrl.length > 1){
	
		qStr = aUrl[1].split("&");
		
		qCodes = qStr[0].split("=");
			allCodes = qCodes[1];
		
		if (qStr.length > 1){						
			qHide = qStr[1].split("=");	
			hideCodes = qHide[1];				
		}
		
		if (qStr.length > 2){
			qSpan = qStr[2].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;
	}
	
	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){
	
	//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 + "spinner.gif";

	//"codes" refers to the codes used for the image
	var allCodes = parseURL(currSrc,"codes");
	var hiddenCodes = parseURL(currSrc,"hide");
	var span = parseURL(currSrc,"span");
	
	var arrAllCodes = new Array();
	
	//Retrieve a comma delimited list of all codes
	if (allCodes!=""){
		arrAllCodes = allCodes.split(",");
	}
	var len = arrAllCodes.length;		
	
	var ispresent = false;
	for(j=0; j<len; j++)
	{
		if(arrAllCodes[j] == code)
		{
			ispresent = true;
		}
	}
	
	//If the code is not already on the graph, then it needs to be added
	if (!ispresent && code!=''){
						
		//If less than 10 codes are present
		if (len < 10){
			
			//Add the code to the array
			arrAllCodes[len] = code;
			
			//Concatenate array elements into a single string
			var strCodes = arrAllCodes.join();
			
			//Add new codes to the IMG tag source
			newSrc = "chartbuilder.aspx?codes=" + strCodes + "&hide=" + hiddenCodes + "&span=" + span;		
			
			img.src = newSrc;
			
			cws.LoadInstruments(updateLegend, strCodes);
			if (GetElementById('PerfTables', false) != null)
			{
				cws.LoadPerformance(updatePerformanceTables, strCodes);
			}
		}
		else {
			img.src=currSrc;
			alert("Maximum of 10 instruments");
			
		}
	}
	else 
	{
		//No changes were needed to the graph
		img.src=currSrc;
	}
	
}

//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)
{
    if(ageStatus == "hide5yrs")
    {
        UpdatePerfTablesSub(r, true, false);
    }
    else
    {
        UpdatePerfTablesSub(r, true, true);
    }
}

function CreateHeader(showFiveYearPerf)
{
    /* Header */
    
    var performanceTable = GetElementById("tblCumulativePerformance");
    var performanceHeader = document.createElement("thead");
	performanceHeader.id = "theadCumulativePerformance";
	performanceTable.appendChild(performanceHeader);
	
    var headRow = document.createElement("tr");
    headRow.id = "perfHeader";
    headRow.className = "head";
    performanceHeader.insertBefore(headRow, null);
    
    var noOfColumns = 9;
    if(!showFiveYearPerf)
    {
        --noOfColumns;
    }
    var cells = LegendRowAddCells(headRow, noOfColumns);
    
    var txtNode= document.createTextNode("Key");
	cells[0].appendChild(txtNode);
	txtNode= document.createTextNode("Rathbone Funds/Sector");
	cells[1].appendChild(txtNode);
	txtNode= document.createTextNode("6 months");
	cells[2].className = "ac";
	cells[2].appendChild(txtNode);
	txtNode= document.createTextNode("1 year");
	cells[3].className = "ac wide";
	cells[3].appendChild(txtNode);
	txtNode= document.createTextNode("3 years");
	cells[4].className = "ac widex";
	cells[4].appendChild(txtNode);
	if(showFiveYearPerf)
	{
	    txtNode= document.createTextNode("5 years");
	    cells[5].className = "ac widex";
	    cells[5].appendChild(txtNode);
	}
	txtNode= document.createTextNode("Since Launch");
	cells[noOfColumns - 3].className = "ac";
	cells[noOfColumns - 3].appendChild(txtNode);
	txtNode= document.createTextNode("Show");
	cells[noOfColumns - 2].className = "sml";
	cells[noOfColumns - 2].appendChild(txtNode);
	txtNode= document.createTextNode("Remove");
	cells[noOfColumns - 1].className = "sml";
	cells[noOfColumns - 1].appendChild(txtNode);
	
	/* End Header */
}

function UpdatePerfTablesSub(r, isCumulative, showFiveYearPerf)
{
	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 = '';
	var coreSector = '';
	
	var data = r.PerfItems;
	
	var performanceTable = GetElementById("tbl" + pfText + "Performance");
	if (performanceTable == null)
	{
		return;
	}

	var performanceHeader = GetElementById("theadCumulativePerformance");
	performanceTable.removeChild(performanceHeader);
	CreateHeader(showFiveYearPerf);
	
	var performanceBody = GetElementById("tbdy" + pfText + "Performance");
	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 sectorCode = parseURL(currSrc, "sector");
	var arrAllCodes = new Array();
	var numCodes = 0;
	var numCoreRows = 0;
	var numPerfItems = data.length;
	
	if(sectorCode != "")
	{
	    allCodes += (allCodes != "") ? "," + sectorCode : sectorCode;
	}
	if (allCodes != "")
	{
		arrAllCodes = allCodes.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
			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);
		}
	}
	
	var navRow = null;
	for (var i = 0; i < performanceBody.childNodes.length; i++)
	{
		var oRow = performanceBody.childNodes[i];		
		if (performanceBody.flaggedRows == null)
		{
			oRow.NotData = true;
		}
		else if (oRow.NotData == null)
		{
			performanceBody.removeChild(oRow);
			i--; // to counter the removal.
		}
		if (navRow == null && oRow.NotData == true)
		{
			navRow = oRow;
		}
	}
	performanceBody.flaggedRows = true;
    
	// Order data
	if (tmpArr.length > 0)
	{
		for (var i = 0; i < tmpArr.length; i++)
		{
		    var codeValueArr = tmpArr[i].split("@");
			for (var x = 0; x < data.length; x++)
			{
				if (data[x].Code == codeValueArr[0])
				{
				    var fundRow = document.createElement("tr");
					fundRow.id = "i" + (x + 1);
					performanceBody.insertBefore(fundRow, navRow);
					
					//var fundRow = performanceBody.insertRow(posToAddNewRow);
					if(i % 2 == 0)
			        {
				        classname = "rw";
			        }
			        else
			        {
				        classname = "rwa";
			        }
			        if(data[x].Name.indexOf("IMA") < 0)
			        {
			            chartColourArr = ChartingColors.split(",");
					    addRowFunc(fundRow, data, x, data[x].Name, "P", classname, showFiveYearPerf, chartColourArr[i]);
					}
					else
					{
					    addRowFunc(fundRow, data, x, data[x].Name, "P", classname, showFiveYearPerf, "");
					}
					posToAddNewRow++;
					break;
				}
			}
		}
	}		
}


function addDiscretePerformanceRow(row, data, m, title, type, classname)
{
	var tdCells = createCells(row, 6, 'titleCell', 'numberData');
	
	SetInnerText(tdCells[0], title);
	tdCells[0].className = classname + 'first';
	tdCells[1].className = classname;
	tdCells[2].className = classname;
	tdCells[3].className = classname;
	tdCells[4].className = classname;
	tdCells[5].className = classname;
	
	switch (type)
	{
		case "P":	// Performance
			SetCellsToPropVals(
				tdCells, 1, data[m],
				['P12', 'P12t24', 'P24t36', 'P36t48', 'P48t60'],
				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, name, showFiveYearPerf, chartingColor)
{
    var noOfColumns = 9;
    if(!showFiveYearPerf)
  {
        --noOfColumns;
    }
	var tdCells = createCells(row, noOfColumns, 'titleCell', 'numberData');

	SetInnerText(tdCells[1], title);
	tdCells[0].className = classname + " ac";
	if(chartingColor != "")
	{
	    tdCells[0].innerHTML = '<Center><div class="key" style="background-color:#' +  chartingColor + '" ></Center>';
	}
	else
	{
	    tdCells[0].innerHTML = '<Center><img src="Images/dash.gif" /></Center>';
	}
	tdCells[1].className = classname;
	tdCells[2].className = classname + " ac";
	tdCells[3].className = classname + " ac";
	tdCells[4].className = classname + " ac";
	tdCells[5].className = classname + " ac";
	if(showFiveYearPerf)
	{
	    tdCells[6].className = classname + " ac";
	}

	switch (type)
	{
		case "P":	// Performance
		    if(showFiveYearPerf)
		    {
			    SetCellsToPropVals(
				    tdCells, 2, data[m],
				    ['P6', 'P12', 'P36', 'P60', 'PBase'],
				    roundPercentage
			    );
			}
			else
			{
			    SetCellsToPropVals(
				    tdCells, 2, data[m],
				    ['P6', 'P12', 'P36', 'PBase'],
				    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;
	}
	
	tdCells[noOfColumns - 2].className = classname + " ac";
	var img = GetElementById("ChartImg");
    var currSrc = img.src;
    var hiddenCodes = parseURL(currSrc, "hide");
    var aHideCodeArr = hiddenCodes.split(",");
    var isToShow = true;
    for(var i=0; i<aHideCodeArr.length; i++)
    {
        if(aHideCodeArr[i] == data[m].Code)
        {
            isToShow = false;
        }
    }
    if(isToShow)
    {
	    tdCells[noOfColumns - 2].innerHTML = '<input type="checkbox" name="cbLegend" checked id="cb' + data[m].Code + '" value="' + data[m].Code + '" onclick=ChangeChart("'+ data[m].Code +'") />';
	}
	else
	{
	    tdCells[noOfColumns - 2].innerHTML = '<input type="checkbox" name="cbLegend" id="cb' + data[m].Code + '" value="' + data[m].Code + '" onclick=ChangeChart("'+ data[m].Code +'") />';
	}
	tdCells[noOfColumns - 1].className = classname + " ac";
	tdCells[noOfColumns - 1].innerHTML = '<a href="#" onclick="RemoveCode(\''+ data[m].Code +'\')"><img src="Images/cross.gif" alt="delete" width="13"  height="13" /></a>';
}		


// 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 aColors = ChartColors.split(",");
	
	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;
		}
		
		// 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], aColors[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, 4);

	cells[0].className = classname;
	cells[0].innerHTML = '<center><input type="checkbox" checked 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;
	var imgname = ImagePath + color.substring(1, color.length);
	cells[2].innerHTML = '<center><img src="' + imgname + '.png"  /></center>';

	var txtNode= document.createTextNode(instr.Name);
	cells[3].className = classname + 'first';
	cells[3].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 allCodes = parseURL(currSrc,"codes");
	var span = parseURL(currSrc,"span");
	if (fieldName == null) fieldName = 'cbLegend';
	var items = document.frmLegend[fieldName];
	
	var aCodes = new Array();
	var hCodes = new Array();				
					
	var a=0;
	var h=0;

	if(items)
	{
	if(items.length)
	{
		for (var i=0; i<items.length; i++)
		{
			if (items[i].checked==false)
			{
				aCodes[a] = items[i].value;
				a++;
			
				if (cHiddenCodes.indexOf(items[i].value) >= 0)
				{
					hCodes[h] = items[i].value;
					h++;
				}
			}
			items[i].checked = false;
		}
	}
	else
	{
		if (items.checked==false)
		{
			aCodes[a] = items.value;
			a++;
			
			if (cHiddenCodes.indexOf(items.value) >= 0)
			{
				hCodes[h] = items.value;
				h++;
			}
		}
		items.checked = false;
	}	
	}
	
	var strCodes = aCodes.join();		
	var hidCodes = hCodes.join();
	
	if (aCodes.length > 0){
		GetElementById("ChartImg").src="chartbuilder.aspx?codes=" + strCodes + "&hide=" + hidCodes + "&span=" + span;					
	}else {
		GetElementById("ChartImg").src="chartbuilder.aspx";												
	}
    
    if(cHiddenCodes != hidCodes || allCodes != strCodes)
    {
	    cws.LoadInstruments(updateLegend, strCodes);
	}
	if (GetElementById('PerfTables', false) != null)
	{
		cws.LoadPerformance(updatePerformanceTables, strCodes);
	}
	
	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 hidden code stuff
	var currHiddenCodes = parseURL(currSrc,"hide");
	var aHideCodes = new Array();				
	var hCodeLen = 0;
	var hideCodes = "";
	
	if (currHiddenCodes!=""){
		aHideCodes = currHiddenCodes.split(",");
		hCodeLen = aHideCodes.length;
	}

	// Get span 
	var span = parseURL(currSrc,"span");
	var a=0;
	if(items)
	{
		if(items.length)
		{
			for (var i=0; i<items.length; i++)
			{
				aAllCodes[i] = items[i].value;
				// Hide instruments
				if (action=="hide")
				{
					if (currHiddenCodes.indexOf(items[i].value) < 0)
					{
						if (items[i].checked)
						{
							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 + "iView.gif"															
						}
					}
				}
				items[i].checked=false;
			}
			ChartUpdate(aAllCodes.join(), aHideCodes.join(), span);
		}
		else if(action == "hide")
		{
			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;
				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 + "iView.gif"															
					}
				}
				if(itemchecked == 1)
				{
					ChartUpdate(aAllCodes.join(), aHideCodes.join(), span);
				}
			}
			items.checked = false;
		}
	}
	document.frmLegend.cbSelectAll.checked=false;
}


function ChartUpdate(allCodes, hideCodes, span)
{
	GetElementById("ChartImg").src="chartbuilder.aspx?codes=" + allCodes + "&hide=" + hideCodes + "&span=" + span;		
}

//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>Fund</center>";
				break;
			case "E":
				r="<center>Equity</center>";
				break;
			case "N":
				r="<center>Index</center>";
				break;
			case "X":
				r="<center>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)
{
	alert("Loading tempFunction");
	
	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 == "M")
	{
		options = new Array("12:12 Months", "6:6 Months", "3:3 Months", "1:1 Month");
		selectedIndex = 0;
	}
	else
	{
		options = new Array("60:5 Years", "36:3 Years", "12:1 Year");
		selectedIndex = 2;
	}

	for (var i = 0; i < options.length; i++)
	{
		var option = options[i];
		var optionArr = option.split(":");
			
		var optValue = optionArr[0];
		var optText = optionArr[1];
			
		menu.options.add(new Option(optText, optValue), 0);		
	}
	
	menu.selectedIndex = selectedIndex;
}


function changeTimescale(val)
{				
	var img = GetElementById("ChartImg");
	var currSrc = img.src;
	var script = parseURL(currSrc,"script")	
	var allCodes = parseURL(currSrc,"codes")
	var hiddenCodes = parseURL(currSrc,"hide");
	
	var newSrc = script + "?codes=" + allCodes + "&hide=" + hiddenCodes + "&span=" + val;
					
	img.src = newSrc;
}

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++){
		items[i].checked=state;
	}
}

function displayFull(ctrl)
{
	var menu = GetElementById(ctrl);
	menu.title=menu.options[menu.selectedIndex].text;
}
				
// This function is used to populate drop-down boxes.
// Parameters:
//   xmlResult ....... the parameter result from the web service.
//   selectControl ... either the id of an element in the document or the element itselft. Must be a <SELECT>.
//   itemPlural ...... a string denoting the type of item, e.g. 'funds', 'indices', etc.
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;
	
	if(itemPlural == "units")
	{
	    FundFirstItem(sc, data.length, itemPlural);
	}
    else
    {
	    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);
	}
}

// This function can be over-ridden with a custom function as required.
function InfoFirstItem(selectControl, itemCount, itemPlural)
{
	var text = null;
	if (itemCount > 1)
	{
		text = itemCount + " " + itemPlural + " found...";
	}
	else if (itemCount < 1)
	{
		text = "0 " + itemPlural + " found!";
	}
	if (text != null)
	{
		selectControl.options.add(new Option(text, ""), 0)
	}
}

// This function can be over-ridden with a custom function as required.
function FundFirstItem(selectControl, itemCount, itemPlural)
{
	var text = null;
	if (itemCount > 1)
	{
		text = itemCount + " " + itemPlural + " found...";
	    selectControl.options.add(new Option(text, ""), 0)
        selectControl.options.add(new Option("<Multiple Selection>", "mul"), 1)
	}
	else if (itemCount < 1)
	{
		text = "0 " + itemPlural + " found!";
		selectControl.options.add(new Option(text, ""), 0)
	}
}

				
function checkMultiSelect()
{
     if(getValue('slctUnits') == "mul")
     {
        GetElementById("slctUnits").size = '6';
        GetElementById("slctUnits").multiple = true;
     }
     else if(getValue('slctUnits') == "")
     {
        changeSelectSize();
     }
}

function changeSelectSize()
{
    var select = GetElementById('slctUnits');
    select.size='1';
    select.selectedIndex = 0;
    select.multiple = false;
}

function addCodesToChart()
{
    var select = GetElementById('slctUnits');
    for (var i=0; i<select.options.length; i++)
    {
        if(select.options[i].selected == true && select.options[i].value != 'mul' && select.options[i].value != '')
        {
            addToChart(select.options[i].value);
        }
    }
}
