
//DHTML RT Scripting interface layered on top of rtajax.js (DTS RT AJAX/COMET engine)

var DTS_RTSCRIPTING_BUILDNUM = 141;


//Variables

var arrayRequests = new Array();  //2D array - holds timeout information for each request
var nRequests = 0;
var arrayStatusRequests = new Array();  //2D array - status request info
var nStatusRequests = 0;
var bInited = false;
var g_bRequestError = false;
var g_strDefaultService = "";
var g_bReplaceLinefeeds = false;
var g_bTypewriterText = false;
var g_bPageLinking = false;
var g_strUpdateCol = '#B4B4D4';
var g_ajaxClient = null;
var g_bActiveX = false;
var g_nNextLocId = 0;


//Constants

//array index indentifiers
var AI_REQUEST_LOCATION = 0;   
var AI_TIMEOUTID		= 1;
var AI_REQUEST_RECORD	= 2;
var AI_REQUEST_FIELD	= 3;
var AI_REQUEST_SERVICE	= 4;
var AI_REQUEST_FORMAT	= 5;
var AI_BGCOLOR		= 6;
var AI_CLASS		= 7;
var AI_REQUEST_CALLBACK	= 8;
var CELL_VALUE_INITIAL	= "Pending...";
var CELL_VALUE_NOTAVAIL = "N/A";
var SAI_LOCATION		= 0;						//SAI = Status Array Index
var SAI_TYPE			= 1;

var STATUSREQUEST_CONNECT	= "stateConnect"
var STATUSREQUEST_LATENCY	= "stateLatency"
var STATUSREQUEST_BANDWIDTH	= "stateBandwidth"

var AUTO_FORMAT_NUMBERS = true;

var ID_SEL_PAGE_REF   = "idSelPageRef";
var ID_SEL_SARRTREQ   = "idSelSarRtReq";

var CSSNAME_CELL_UPDATE = "rtcellupd";
var CSSNAME_CELL_NORMAL = "rtcell";
var CSSNAME_CELL_SELECTED = "rtcell_selected";  //by default, we do not update colour of a selected cell
var CSSNAME_CELL_UPDATE_UP = "rtcellupd_up";
var CSSNAME_CELL_UPDATE_DOWN = "rtcellupd_down";
var CSSNAME_CELL_UPDATE_SAME = "rtcellupd_same";
var CSSNAME_CELL_UPDATE_AFTER_UP = "rtcellupd_after_up";
var CSSNAME_CELL_UPDATE_AFTER_DOWN = "rtcellupd_after_down";
var CSSNAME_CELL_UPDATE_AFTER_SAME = "rtcellupd_after_same";
var CSSNAME_CELL_UPDATE_GTZERO = "rtcellupd_gt0";  //value is greater than 0
var CSSNAME_CELL_UPDATE_LTZERO = "rtcellupd_lt0";  //value is less than 0

var ID_STATUS_AREA = "rt-status";

//Functions

//regsters the dtsrtInit() in the window onload event
function dtsrtRegister()
{
	addEvent(window, 'load', dtsrtInit);
	addEvent(window, 'unload', dtsrtClose);
}

function dtsrtInit()
{
    if ((g_ajaxClient == null) && (g_bActiveX == false))
	{
	   alert("DTS RT client library not initialised correctly. Ensure that one of the useRtClient* calls has been made.");
	   return;
	}
	
	requestStatusRecords();

	if (g_ajaxClient)
	{
		//When streaming we want to send record requests in the initial connect message, so request before connect.
		//if (g_ajaxClient.IsStreaming())
		  requestRecords();  
		bInited = g_ajaxClient.Connect();
	}
	else
		bInited = RtWebClient.InitializeAsync();
}

function dtsrtClose()
{
  if (g_ajaxClient)
    g_ajaxClient.Disconnect();
}

function formatDecimal(argvalue, addzero, decimaln) 
{
  var fValue = parseFloat(argvalue);
  if (isNaN(fValue))
	return argvalue;

  if (addzero == null)
	return ("" + fValue);

  var numOfDecimal = (decimaln == null) ? 2 : decimaln;
  var number = 1;

  number = Math.pow(10, numOfDecimal);

  argvalue = Math.round(fValue * number) / number;
  argvalue = "" + argvalue;

  if (argvalue.indexOf(".") == 0)
    argvalue = "0" + argvalue;

  if (addzero == true) {
    if (argvalue.indexOf(".") == -1)
      argvalue = argvalue + ".";

    while ((argvalue.indexOf(".") + 1) > (argvalue.length - numOfDecimal))
      argvalue = argvalue + "0";
  }

  return argvalue;
}

function formatValue(strValue, strFormat)
{
	var strReturn = strValue;

	if (strFormat != null)
	{
		if (strFormat.substring(0,1) == "%")
		{
			return sprintf(strFormat, strValue);
//			nDigitsAfterPoint = strFormat.substring(2, strFormat.length);
//			return formatDecimal(strReturn, true, nDigitsAfterPoint);
		}
		else if (strFormat == "MinToTime")  //used in Ten4 time fields
		{
			//Minutes to 24hr time.

			var hours = Math.floor(strValue / 60);
			if (hours < 10)
			   hours = '0' + hours;
			var mins = (strValue % 60);
			if (mins < 10)
			   mins = '0' + mins;

			return hours + ":" + mins;  
		}
	}

//AK 24/04/09: Not sure what autoformatting was for. I might need to re-enable it. Seems to default to 2dp's.
	//auto format works on numbers beginning with '+'
//	if ((AUTO_FORMAT_NUMBERS) && (strReturn.charAt(0) == '+')) 
//		strReturn = formatDecimal(strReturn);

	if (g_bReplaceLinefeeds)
	{
		//strReturn = strReturn.replace(/</g, "&#60;");
		//strReturn = strReturn.replace(/>/g, "&#62;");
		strReturn = strReturn.replace(/\n/g, "<br>");
		//strReturn = strReturn.replace(/\t/g, "&#09;");  //tabs don't work
		strReturn = strReturn.replace(/\s/g, "&nbsp");  //replace spaces
		//strReturn = strReturn.replace(/#/g, "&#35;");  //hash signs
	}

	//page links <> should be replaced before other tags (<br>'s and <tt>'s) are inserted
	if (g_bPageLinking)
	{
		//Replace <xxx> with <a href="news.html?xxx"> &#60;xxx&#62;</A>
		strReturn = strReturn.replace(/(<)([ ]{0,1})(>)/g, "&#60;$2&#62;"); //non-link exceptions
		strReturn = strReturn.replace(/(<)([^ >]+)(>)/g, "<a href=\"page.htm?$2\">&#60;$2&#62;</A>");
	}

	if (g_bTypewriterText)
	{
		strReturn = "<tt>" + strReturn + "</tt>";
	}

	return strReturn;
}

function updateReceived(strLocation, strValue)
{
	//var strValue = com.derivs.rt.utils.decodeDataTransmitString(strValue);
	var nIndex = getRequestIndex(strLocation);
	if (nIndex == -1)
	  return;  //old released field

	//callback requests will just pass the update to a client function.
	var strCallback = arrayRequests[nIndex][AI_REQUEST_CALLBACK];
	if (strCallback != null)
	{
		var strEscaped = strValue;
		var strEscaped = strEscaped.replace(/'/g, "\\'");
		var strEscaped = strEscaped.replace(/\r/g, "");
		var strEscaped = strEscaped.replace(/\n/g, "");
		eval(strCallback + "('" + strEscaped + "');");
		return;
	}

	resetTimeout(strLocation);

//	document.getElementById("testarea").innerHTML = strLocation;  //DEBUG TEST

	strFormat = arrayRequests[nIndex][AI_REQUEST_FORMAT];
	var strValueFormatted = formatValue(strValue, strFormat);

	elem = document.getElementById(strLocation);
    var strOldValue = elem.innerHTML;

//Update the value:
	elem.innerHTML = strValueFormatted;

//Update the cell/background colour/style:

	//if this is a selected cell, don't apply the update style
	if (isStyleDefined(CSSNAME_CELL_SELECTED) && parentStyleIs(elem, CSSNAME_CELL_SELECTED))
	  return; 

    //Figure out the CSS class value for the updated cell
    var strClassUpdate = CSSNAME_CELL_UPDATE;
	if (isStyleDefined(CSSNAME_CELL_UPDATE_UP) && valueUp(strOldValue, strValueFormatted))
	   strClassUpdate = CSSNAME_CELL_UPDATE_UP;
	else if (isStyleDefined(CSSNAME_CELL_UPDATE_DOWN) && valueDown(strOldValue, strValueFormatted))
	   strClassUpdate = CSSNAME_CELL_UPDATE_DOWN;
	else if (isStyleDefined(CSSNAME_CELL_UPDATE_SAME))
	   strClassUpdate = CSSNAME_CELL_UPDATE_SAME;

	var elemParent = xParentNode(elem);
	if (isIdStyleDefinedForElem(CSSNAME_CELL_UPDATE_GTZERO, elemParent) && valueGtZero(strValueFormatted))
	   strClassUpdate = CSSNAME_CELL_UPDATE_GTZERO;
	if (isIdStyleDefinedForElem(CSSNAME_CELL_UPDATE_LTZERO, elemParent) && valueLtZero(strValueFormatted))
	   strClassUpdate = CSSNAME_CELL_UPDATE_LTZERO;

	//elem.parentElement.bgColor = g_strUpdateCol;
	xParentNode(elem).className = strClassUpdate; //CSSNAME_CELL_UPDATE;
	strCommand = "clearUpdateColour('" + strLocation + "')";
	timerId = setTimeout(strCommand, 3000);

	rememberTimeout(strLocation, timerId);
}

function isIdStyleDefinedForElem(strStyle, elem)
{
	var strId = elem.getAttribute("id");
	if ((strId == null) || (strId == ""))
		return false;

	var strIdStyle = "#" + strId + "." + strStyle;

	return isStyleDefined(strIdStyle);
}

function valueUp(strOld, strNew)
{
  var nOld = parseFloat(strOld);
  var nNew = parseFloat(strNew);

  if (isNaN(nOld) || isNaN(nNew))
     return false;

  return (nNew > nOld);
}

function valueDown(strOld, strNew)
{
  var nOld = parseFloat(strOld);
  var nNew = parseFloat(strNew);

  if (isNaN(nOld) || isNaN(nNew))
     return false;

  return (nNew < nOld);
}

function valueSame(strOld, strNew)
{
  var nOld = parseFloat(strOld);
  var nNew = parseFloat(strNew);

  if (isNaN(nOld) || isNaN(nNew))
     return false;

  return (nNew == nOld);
}

function valueUp(strOld, strNew)
{
  var nOld = parseFloat(strOld);
  var nNew = parseFloat(strNew);

  if (isNaN(nOld) || isNaN(nNew))
     return false;

  return (nNew > nOld);
}

function valueGtZero(strVal)
{
  var nVal = parseFloat(strVal);
  if (isNaN(nVal))
     return false;
  return (nVal > 0);
}

function valueLtZero(strVal)
{
  var nVal = parseFloat(strVal);
  if (isNaN(nVal))
     return false;
  return (nVal < 0);
}

function getStyleClass(className) 
{
	var strSelector = className.substr(0,1) == "#" ? className : "."+className;

	for (var s = 0; s < document.styleSheets.length; s++)
	{
		if(document.styleSheets[s].rules)
		{
			for (var r = 0; r < document.styleSheets[s].rules.length; r++)
			{
				if (document.styleSheets[s].rules[r].selectorText == strSelector)
				{
					return document.styleSheets[s].rules[r];
				}
			}
		}
		else if(document.styleSheets[s].cssRules)
		{
			for (var r = 0; r < document.styleSheets[s].cssRules.length; r++)
			{
				if (document.styleSheets[s].cssRules[r].selectorText == strSelector)
					return document.styleSheets[s].cssRules[r];
			}
		}
	}
	
	return null;
}

//cached call (much quicker than findStyle/getStyleClass)
function isStyleDefined(strClassName)
{
	return g_styleCache.isStyleDefined(strClassName);
}

function findStyle(strClassName)
{
	return (getStyleClass(strClassName) != null);
}

function onConnected()
{
	if ((g_ajaxClient != null) && g_ajaxClient.IsStreaming())  //we've already reqeusted records in the connect message when streaming.
		{}
	else if (g_bActiveX)
		requestRecords();

	//client event
	if (window.rtevent_connected)
		rtevent_connected();
}

function stateReceived(strLocation, strValue)
{
    whichEl = eval("document.all." + strLocation);
    whichEl.innerHTML = strValue;
}

function resetTimeout(strLocation)
{
	//find timeout in array
	index = getRequestIndex(strLocation);
	if (index == -1)
		return;
	timerId = arrayRequests[index][AI_TIMEOUTID];

	clearTimeout(timerId);

	arrayRequests[index][AI_TIMEOUTID] = 0;
}

function rememberTimeout(strLocation, timerId)
{
	index = getRequestIndex(strLocation);
	if (index == -1)
		return;
	arrayRequests[index][AI_TIMEOUTID] = timerId;
}

function clearUpdateColour(strLocation)
{
	resetTimeout(strLocation);

	el = document.getElementById(strLocation);
	if (el != null)
	{
    	//if this is a selected cell, don't apply the update style
	    if (isStyleDefined(CSSNAME_CELL_SELECTED) && parentStyleIs(el, CSSNAME_CELL_SELECTED))
	      return; 

		var className = xParentNode(el).className;
		if ((className == CSSNAME_CELL_UPDATE_UP) && (isStyleDefined(CSSNAME_CELL_UPDATE_AFTER_UP)))
			xParentNode(el).className = CSSNAME_CELL_UPDATE_AFTER_UP;
		else if ((className == CSSNAME_CELL_UPDATE_DOWN) && (isStyleDefined(CSSNAME_CELL_UPDATE_AFTER_DOWN)))
			xParentNode(el).className = CSSNAME_CELL_UPDATE_AFTER_DOWN;
		else if ((className == CSSNAME_CELL_UPDATE_SAME) && (isStyleDefined(CSSNAME_CELL_UPDATE_AFTER_SAME)))
			xParentNode(el).className = CSSNAME_CELL_UPDATE_AFTER_SAME;
		else
			xParentNode(el).className = arrayRequests[getRequestIndex(strLocation)][AI_CLASS];
	} 	

}

//go through a few levels of parents to find is style is used
function parentStyleIs(el, strClass)
{
  var parent = el;

  for (n=0; n<5; n++)
  {
	if (parent.className == CSSNAME_CELL_SELECTED)
	  return true;

    parent = xParentNode(parent);
	if (parent == null)
	  return false;
  }

  return false;
}

function xParentNode(el)
{
	return ((el.parentElement)?el.parentElement:el.parentNode);
}

function getRequestIndex(strLocation)
{
	for (var i=0; i<nRequests; i++)
	{
		if (arrayRequests[i] != null)
		{
			if (arrayRequests[i][AI_REQUEST_LOCATION] == strLocation)
				return i;
		}
	}

	return -1;
}

function getDomElement(strLocation)
{
	//return eval("document.all." + strLocation);
	return document.getElementById(strLocation);
}

function initElement(strLocation)
{
	el = getDomElement(strLocation);
	if (el == null)  //can be Callback request (no UI)
		return;

	if (bInited || g_ajaxClient.IsStreaming())
		el.innerHTML = CELL_VALUE_INITIAL;
//	else
//		el.innerHTML = CELL_VALUE_NOTAVAIL;
}

function requestFromActivex(strLocation, strRecord, strField, strService)
{
	initElement(strLocation);

	if (g_ajaxClient)
	{
		return g_ajaxClient.AddRequest(strLocation, strRecord, strField, strService);
	}

	return RtWebClient.AddRequestDhtml(strLocation, strRecord, strField, strService);
}

function requestStatusFromActivex(strLocation, strType)
{
	if (g_ajaxClient)
		return false;

	return RtWebClient.AddStatusRequest(strLocation, strType);
}

function setDefaultService(strService)
{
	g_strDefaultService = strService;

	if (g_ajaxClient)
		return false;

	RtWebClient.SetDefaultService(strService);
}

function getDefSvc()
{
	return g_strDefaultService;
}

function setReplaceLinefeeds(bOn)
{
	g_bReplaceLinefeeds = bOn;
}

function setTypewriterText(bOn)
{
	g_bTypewriterText = bOn;
}

function setPageLinking(bOn)
{
	g_bPageLinking = bOn;
}

function LoadUIRecords()
{
}

function setUpdateCol(strUpdateCol)
{
	g_strUpdateCol = strUpdateCol;
}

function requestRecords()
{
	//go through our request list and make the requests from the activex control

	for (i=0; i<nRequests; i++)
	{
		var strLocation, strRecord, strField, strService;

		strLocation = arrayRequests[i][AI_REQUEST_LOCATION];
		strRecord = arrayRequests[i][AI_REQUEST_RECORD];
		strField = arrayRequests[i][AI_REQUEST_FIELD];
		strService = arrayRequests[i][AI_REQUEST_SERVICE];

		if (strRecord == null)  //request already made directly to transport object.
			continue;

		//remember background color
		//whichEl = eval("document.all." + strLocation);  //NON STANDARD APPARENTLY
		el = document.getElementById(strLocation);
//		arrayRequests[i][AI_BGCOLOR] = whichEl.parentElement.bgColor;
		if (el != null)  //can be callback - no UI elem
			arrayRequests[i][AI_CLASS] = xParentNode(el).className;

		if (!requestFromActivex(strLocation, strRecord, strField, strService))
		{
			alert("Could not make request to the RtWebClient ActiveX control");
			return false;
		}

	}

	return true;
}

function requestStatusRecords()
{
	//request status records from activex control 

	for (i=0; i<nStatusRequests; i++)
	{
		var strLocation = arrayStatusRequests[i][SAI_LOCATION];
		var strType = arrayStatusRequests[i][SAI_TYPE];

		if (!requestStatusFromActivex(strLocation, strType))
			return false;
	}

	return true;
}


//request() function params:
//[1]: strRecord
//[2]: strField
//[3]: strService=defaultService  (optional parameter)
//[4]: strFormat=null (optional)
//[5]: strCallback=null (optional)
function request(strRecord, strField, strService, strFormat, strCallback)
{
	if (g_bRequestError)  
		return false;  //to prevent loads of error messages being displayed

	if (strService == null)
		strService = g_strDefaultService;

	if (strService == "")
	{
		if (g_bRequestError == false)
		{
			alert("Default service has not been defined.");
			g_bRequestError = true;
		}

		return false;
	}

	//generate a location identifier
	var strLocation = "request" + nRequests;

	//store request details
	arrayRequests[nRequests] = new Array();
	arrayRequests[nRequests][AI_REQUEST_LOCATION] = strLocation;
	arrayRequests[nRequests][AI_REQUEST_RECORD] = strRecord;
	arrayRequests[nRequests][AI_REQUEST_FIELD] = strField;
	arrayRequests[nRequests][AI_REQUEST_SERVICE] = strService;
	arrayRequests[nRequests][AI_REQUEST_FORMAT] = strFormat;
	arrayRequests[nRequests][AI_REQUEST_CALLBACK] = strCallback;

	nRequests ++;

	//output HTML identifier for this request (using SPAN)
	if (strCallback == null)
	  document.write("<SPAN ID='" + strLocation + "' onmouseup='onMouseUp(this)' onDblClick='onDblClickReq(this)'>" + CELL_VALUE_INITIAL + "</SPAN>");

	if ((g_ajaxClient != null) && g_ajaxClient.IsConnected())
	{
		if (!requestFromActivex(strLocation, strRecord, strField, strService))
		  return false;
	}

	return true;
}

function release(nIndex)
{
  var strLoc = arrayRequests[nIndex][AI_REQUEST_LOCATION];

  g_ajaxClient.ReleaseField(strLoc);

  //TODO: I need to rework arrayRequests. It was originally designed for 
  //a static number of requests (done on page load) but now we are dynamically 
  //requesting/releasing. For now I'm leaving an entry in the array for 
  //released fields but am just nulling the details.
  //FUTURE: I will probably need some logic to iterate through the array 
  //every so often, looking for old/expired released fields, and deleting them.

  arrayRequests[nIndex] = null;

  //delete the request details from array
//  arrayRequests.splice(nIndex, 1);
//  nRequests--;
}

function requestStatus(strType)
{
	var strLocation = "st" + nStatusRequests;

	arrayStatusRequests[nStatusRequests] = new Array();
	arrayStatusRequests[nStatusRequests][SAI_LOCATION] = strLocation;
	arrayStatusRequests[nStatusRequests][SAI_TYPE] = strType;

	nStatusRequests ++;

	//output HTML identifier for this request (using SPAN)
	document.write("<SPAN ID='" + strLocation + "'>" + CELL_VALUE_INITIAL + "</SPAN>");
}

function requestHistoric(strFeed, strRecord, strField, dateStart, dateEnd, strInterval, strCalcType, nValues, strCallback)
{
	if (g_bRequestError)  
		return false;  //to prevent loads of error messages being displayed

	if (strFeed == null)
		strFeed = g_strDefaultService;

	if (!g_ajaxClient)
	{
 		alert("Historic calls not supported in ActiveX control");
		return false;
	}
	
	//generate a (unique) location identifier
	var strLocation = "request" + nRequests;

	//store request details
	arrayRequests[nRequests] = new Array();
	arrayRequests[nRequests][AI_REQUEST_LOCATION] = strLocation;
	arrayRequests[nRequests][AI_REQUEST_CALLBACK] = strCallback;
	arrayRequests[nRequests][AI_REQUEST_RECORD] = null;

	nRequests ++;

	return g_ajaxClient.RequestHistoric(strFeed, strRecord, strField, dateStart, dateEnd, strInterval, strCalcType, nValues, strLocation);
}

function sendMessage(strRecord, strField, strService, strMessageData)
{
	if (g_bRequestError)  
		return false;  //to prevent loads of error messages being displayed

	if (strService == null)
		strService = g_strDefaultService;

	if (!g_ajaxClient)
		return RtWebClient.SendMessage(strRecord, strField, strService, strMessageData);
	else if ((g_ajaxClient != null) && g_ajaxClient.IsConnected())
	{
		return g_ajaxClient.SendMessage(strRecord, strField, strService, strMessageData);
	}
	else
		alert("Not connected, so cannot perform a SendMessage");
}

function publishValue(strRecord, strField, strService, strValue)
{
	//pStrMessageData format:
	//<message>
	//  <command name="PublishRecord">
	//    <recordname>gbp</recordname>
	//    <field>BID</field>    //can be field number or field name
	//    <feed>MyFeed</feed>   //should be the same as GetFriendlyName()
	//    <value>1.6124</value>
	//  </command>
	//</message>

  var strMsg = "<message>";
  strMsg += " <command name=\"PublishRecord\">";
  strMsg += "  <recordname>" + strRecord + "</recordname>";
  strMsg += "  <field>" + strField + "</field>";
  strMsg += "  <feed>" + strService + "</feed>";
  strMsg += "  <value>" + strValue + "</value>";
  strMsg += " </command>";
  strMsg += "</message>";
  
  sendMessage(strRecord, strField, strService, strMsg);
}

function ShowEventViewer()
{
	RtWebClient.ShowEventViewer();
}

function putElem_SelSarRtReq()
{
//	document.write("<SPAN id='" + ID_SEL_SARRTREQ + "'></SPAN>");
	document.write("<INPUT type='text' name='" + ID_SEL_SARRTREQ + "' id='" + ID_SEL_SARRTREQ + "' value='' size='90'></INPUT>");
}

function onMouseUp(el)
{
	if (el == null)
		return;

	//TODO: Split this function up: OutputPageRef() and OutputPageNum()

	//attempt to output PAGE reference:

	var nRow = el.id.substring(el.id.length-1, el.id.length);

	var selRng = document.selection.createRange();
	var nSelLength = selRng.text.length;
	var elemRng = document.body.createTextRange();
	elemRng.moveToElementText(selRng.parentElement());
	var offset = 0;
	while (selRng.compareEndPoints("StartToStart", elemRng) > 0)
	{
		++offset;
		selRng.move("character", -1);
	}
	el = getDomElement(ID_SEL_PAGE_REF);
	var strPageRef = "PAGE " + nRow + " " + offset + " " + nSelLength + " NONE"; 
//	if (el != null)
//		el.innerHTML = strPageRef;

	//output page number for Telerate pages
	var nPage = getPageFromSelection();
	if (nPage != -1)
		textGoToPage.value = nPage;

	//atempt to find SaracenRT req element
	el = getDomElement(ID_SEL_SARRTREQ);
	if (el != null)
	{
		strRecord = TELERATE_PAGEREQ_PREFIX + location.search.substring(1);
		el.value = "=Rt.Rtm.1|GET!'!" + strRecord + ";" + strPageRef + ";Telerate'";
	}

}

function onDblClickReq(el)
{
	if (el == null)
		return;

	if (getPageFromSelection() != -1)
		onGo();
}

//returns -1 if invalid selection
function getPageFromSelection()
{
	var selText = document.selection.createRange().text;
	var nPage = parseInt(selText);
	if (!isNaN(nPage))
		return nPage;

	//invalid page
	return -1;	
}

function useRtClientActiveX()
{
	g_bActiveX = true;

	//TODO: Test this. I think it doesn't work if called from <HEAD>, which is how it's called in the examples.
	//writeActiveXHtml();
}

function useRtClientAjax(bStreaming)
{
	g_ajaxClient = new RtWebClientAjax("g_ajaxClient", bStreaming);
//	alert("IsStreaming: " + g_ajaxClient.IsStreaming());
}

function writeActiveXHtml()
{
	var strObjActiveX = "<OBJECT codebase='RtWebClient.cab#Version=1,0,0,96' \n" +
		            "classid='CLSID:8BB1D5E8-2A17-11D6-B830-000347CC94C6'\n" +
		            "width='0' height='0' id='RtWebClient'>" +
			"<param name='font' value='Arial'>" +
			"<PARAM NAME='fontsize' VALUE='11'>" +
			"<PARAM NAME='server' VALUE='realtimedata.derivs.org'>" +
			"<PARAM NAME='port' VALUE='8244'>" +
			"<PARAM NAME='useHttp' VALUE='0'>" +
			"<PARAM NAME='UpdateColour' VALUE='0xB4B4D4'>" +
			"<PARAM NAME='modeUI' VALUE='0'>" +
			"<PARAM NAME='serverlist' VALUE='servers.txt'>" +
			"</OBJECT>";

	document.write(strObjActiveX);
}

//StyleCache contains an array of defined stylesheet classes. 
//This saves having to iterate through all of the stylesheet 
//objects on each RT update (which was taking up a lot of CPU time).
function StyleCache()
{
	//public methods:
	this.isStyleDefined = isStyleDefined;

	function isStyleDefined(strStyle)
	{
		var bStyle = m_array[strStyle];
		if (bStyle == null)
		{
			var bStyle = findStyle(strStyle);
			m_array[strStyle] = bStyle;
			return bStyle;
		}
		else
			return bStyle;
	}

	//private data
	var m_array = new Array();
}

var g_styleCache = new StyleCache;


//
//  Javascript sprintf
//  http://www.webtoolkit.info/
//

sprintfWrapper = {

	init : function () {

		if (typeof arguments == "undefined") { return null; }
		if (arguments.length < 1) { return null; }
		if (typeof arguments[0] != "string") { return null; }
		if (typeof RegExp == "undefined") { return null; }

		var string = arguments[0];
		var exp = new RegExp(/(%([%]|(\-)?(\+|\x20)?(0)?(\d+)?(\.(\d)?)?([bcdfosxX])))/g);
		var matches = new Array();
		var strings = new Array();
		var convCount = 0;
		var stringPosStart = 0;
		var stringPosEnd = 0;
		var matchPosEnd = 0;
		var newString = '';
		var match = null;

		while (match = exp.exec(string)) {
			if (match[9]) { convCount += 1; }

			stringPosStart = matchPosEnd;
			stringPosEnd = exp.lastIndex - match[0].length;
			strings[strings.length] = string.substring(stringPosStart, stringPosEnd);

			matchPosEnd = exp.lastIndex;
			matches[matches.length] = {
				match: match[0],
				left: match[3] ? true : false,
				sign: match[4] || '',
				pad: match[5] || ' ',
				min: match[6] || 0,
				precision: match[8],
				code: match[9] || '%',
				negative: parseInt(arguments[convCount]) < 0 ? true : false,
				argument: String(arguments[convCount])
			};
		}
		strings[strings.length] = string.substring(matchPosEnd);

		if (matches.length == 0) { return string; }
		if ((arguments.length - 1) < convCount) { return null; }

		var code = null;
		var match = null;
		var i = null;

		for (i=0; i<matches.length; i++) {

			if (matches[i].code == '%') { substitution = '%' }
			else if (matches[i].code == 'b') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'c') {
				matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument)))));
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'd') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'f') {
				matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'o') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 's') {
				matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length)
				substitution = sprintfWrapper.convert(matches[i], true);
			}
			else if (matches[i].code == 'x') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]);
			}
			else if (matches[i].code == 'X') {
				matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16));
				substitution = sprintfWrapper.convert(matches[i]).toUpperCase();
			}
			else {
				substitution = matches[i].match;
			}

			newString += strings[i];
			newString += substitution;

		}
		newString += strings[i];

		return newString;

	},

	convert : function(match, nosign){
		if (nosign) {
			match.sign = '';
		} else {
			match.sign = match.negative ? '-' : match.sign;
		}
		var l = match.min - match.argument.length + 1 - match.sign.length;
		var pad = new Array(l < 0 ? 0 : l).join(match.pad);
		if (!match.left) {
			if (match.pad == "0" || nosign) {
				return match.sign + pad + match.argument;
			} else {
				return pad + match.sign + match.argument;
			}
		} else {
			if (match.pad == "0" || nosign) {
				return match.sign + match.argument + pad.replace(/0/g, ' ');
			} else {
				return match.sign + match.argument + pad;
			}
		}
	}
}

sprintf = sprintfWrapper.init;


function addEvent(obj, evType, fn)
{ 
	if (obj.addEventListener){ 
		obj.addEventListener(evType, fn, false); 
		return true; 
	} else if (obj.attachEvent){ 
		var r = obj.attachEvent("on"+evType, fn); 
		return r; 
	} else { 
		return false; 
	} 
}


