//////////////////////////////////////////////
// Generic function script
// This file contains some generic functions
// used throughout the site.
// Also defines some constants used throughout
// the site also
// Ali Russell 2004
//
// Modified by Tony Ambrus
// added bless() function
//////////////////////////////////////////////


//browser sniffer
var browserDetails=new Array(4);
var osDetails=new Array(2);
browserDetails=getBrowser();
osDetails=getOS();

// XMLRequest Lock Variables
var XMLRequestBusy_ColumnBrowser = false;
var XMLRequestBusy_InfoPanel = false;
var XMLRequestBusy_LoginControl = false;
var XMLRequestBusy_AdvancedSearch = false;

// Login Globals
var UserID = null;
var Username = null;

// Help switch
var HelpOn = false;
var HelpUseHighlight = true;

// Tooltip Timeout
var TooltipTimeout = 2000;

//////////////////////
//ENUMERATIONS
/////////////////////

//ZoomableStatus Enum
var ZoomableStatus_Minimised = 0;
var ZoomableStatus_Maximised = 1;
var ZoomableStatus_Restored = 2;

//ZoomableContainerType Enum
var ZoomableContainerType_Horizontal = 3;
var ZoomableContainerType_Verticle = 4;

//EventType Enum
var EventType_ColClose = 5;
var EventType_ColOpen = 6;
var EventType_MoveLeft = 7;
var EventType_MoveRight = 8;
var EventType_DragStart = 9;
var EventType_DragStop = 10;
var EventType_Drag = 11;
var EventType_ScrollBarShow = 12;
var EventType_ScrollBarHide = 13;
var EventType_ItemClick = 14;
var EventType_PreviewClick = 15;
var EventType_UpdateColumns = 16;

//ResultType return value
var ResultType_GetColumns = 100;
var ResultType_GetDefaultColumns = 101;
var ResultType_GetColumnContents = 102;
var ResultType_Abort = 103;
var ResultType_GetPreviewCues = 104;
var ResultType_GetLocationID = 105;
var ResultType_GetInterest = 106;
var ResultType_SetInterest = 107;
var ResultType_GetDates = 108;

//Drag Object Types
var DragType_ListItem = 200;
var DragType_InterestItem = 201;
var DragType_Column = 202;
var DragType_ColumnListItem = 203;


//Object type enumeration
var ObjectType_ZContainer = 300;
var ObjectType_ZPanel = 301;
var ObjectType_TitleBar = 302;
var ObjectType_StatusBar = 303;
var ObjectType_LeftBar = 304;
var ObjectType_RightBar = 305;
var ObjectType_ZPopup = 306;

//Panel Contents types
var PanelType_ColumnPanel = 400;
var PanelType_InterestPanel = 401;
var PanelType_InformationPanel = 402;
var PanelType_PreviewPanel = 403;

//////////////////////
//END ENUMERATIONS
//////////////////////


function getClassName(obj)
{
	var str = "Object";
	
	if (obj.constructor)
	{
		var functionStr = "function ";
		str = obj.constructor.substring(obj.constructor.indexOf(functionStr) + functionStr.length, obj.constructor.indexOf("("));
	}
	
	return str;
}

function setFloat(element, floatVal)
{
	if (browserDetails[0]=="msie")
	{
		element.style.styleFloat = floatVal;
	}
	else
	{
		element.style.cssFloat = floatVal;
	}
}


function URLEncode(sStr) {
    return escape(sStr).replace(/\+/g, '%2B').replace(/\"/g,'%22').replace(/\'/g, '%27').replace(/\//g,'%2F');
  }
  
function URLDecode(sStr) {
    return unescape(sStr).replace('%2B', '+').replace('%22', '"').replace('%27', '\'').replace('%2F','/');
  }  

function getWindowHeight() {
	if (window.self && self.innerHeight) 
	{
		return self.innerHeight;
	}
	if (document.documentElement && document.documentElement.clientHeight) 
	{
		return document.documentElement.clientHeight;
	}
	return 0;
}

function getWindowWidth() {
	if (window.self && self.innerWidth) 
	{
		return self.innerWidth;
	}
	if (document.documentElement && document.documentElement.clientWidth) 
	{
		return document.documentElement.clientWidth;
	}
	return 0;
}

var browser;

if((navigator.userAgent.toLowerCase().indexOf("msie") + 1)){
	browser = "IE";
}
else{
	browser = "Other";
}


function Contains(elementX, elementY, elementW, elementH, x, y)
{
	
	if ((elementX<=x) && ((elementX+elementW)>=x) && (elementY<=y) && ((elementY+elementH)>=y))
	{
		return true;
	}
	else
	{
		return false;
	}
}

//function to find the x position in pixels of any object on the page.
function findPosX(obj)
{
	var curleft = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curleft += (obj.offsetLeft + obj.scrollLeft);
			obj = obj.offsetParent;
		}
	}
	else if (obj.x)
		curleft += obj.x;
	return curleft;
}

//function to find the y position in pixels of any object on the page.
function findPosY(obj)
{
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{	
			curtop += (obj.offsetTop - obj.scrollTop);
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	return curtop;
}

function mousePosX(e)
{
	if (document.all) {
    tempX = event.clientX + document.body.scrollLeft;
  } else {
    tempX = e.pageX;
  }

  return tempX;
}

function mousePosY(e)
{
	if (document.all) {
    tempY = event.clientY + document.body.scrollTop;
  } else {
    tempY = e.pageY;
  }

  return tempY;
}

//function for ie to populate a div with another pages html
function srcDownload(url) {
	var xmlr;
	/*
	netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserAccess');
	try {
		// IE stuff, for some reason it doesn't know it doesn't
		// have XMLHTTPRequest objects...
		xmlr = new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		xmlr = new XMLHttpRequest();
	}
	*/
	
	xmlr = new XMLHttpRequest();
	try {
		xmlr.open("GET", "ieinfo.php?url=" + escape(url), false);
		xmlr.send(null);
		//xmlr.send();
		return xmlr.responseText;
	} catch(ex) {
		var debug_text="";
		for (var i in ex)
			debug_text += "\n"+i+" = "+ex[i];
	
		alert(debug_text);
		return null;
	}
}


/* A general function that associates an object instance with an event
   handler. The returned inner function is used as the event handler.
   The object instance is passed as the - obj - parameter and the name
   of the method that is to be called on that object is passed as the -
   methodName - (string) parameter.
*/
function associateObjWithEvent(obj, methodName){
    /* The returned inner function is intended to act as an event
       handler for a DOM element:-
    */
    return (function(e){
        /* The event object that will have been parsed as the - e -
           parameter on DOM standard browsers is normalised to the IE
           event object if it has not been passed as an argument to the
           event handling inner function:-
        */
        e = e||window.event;
        /* The event handler calls to method of the object - obj - with
           the name held in the string - methodName - passing the now
           normalised event object and a reference to the element to
           which the event handler has been assigned using the - this -
           (which works because the inner function is executed as a
           method of that element because it has been assigned as an
           event handler):-
        */
		//alert(this + " -- "  + methodName);
        return obj[methodName](e, this);
    });
}

function stopEventBubble(e)
{
	if ((browserDetails[0]=="msie") && (browserDetails[1]!="7.0"))
	{
		window.event.cancelBubble = true;
	}
	else
	{
		e.stopPropagation();
	}	
}

//function to return if true if a number is even, false if odd
function isEven(x) { return (x%2)?false:true; }

function isParentOf(p, o, notSelf)
{
	if(notSelf && o == p) return false;
	while(o)
		if(o != p)	o = o.parentNode;
		else		return true;
	return false;
}

function getSrc(e)
{
	var targ;
	if (!e) var e = window.event;
	if (e.target) targ = e.target;
	else if (e.srcElement) targ = e.srcElement;
	if (targ.nodeType == 3) // defeat Safari bug
		targ = targ.parentNode;
		
	return targ;
}


// Function to sleep for a number of milliseconds.
// This is mainly used for debugging.
function Sleep(intNumMS)
{
 // Checks for a valid number
 if(!isNaN(intNumMS))
 {
  // Uses JS built-in date object
  var datNow = new Date();
  var intNumMSNow = datNow.getTime();
  var intNumMSThen = (intNumMSNow + intNumMS);
  var i=0;

  // Does something useless until the time is right
  while(new Date().getTime() <= intNumMSThen)
  {i++;}
 } return;
}


//Method to set a cookie with the passed values on the client
//computer.
function setCookie(name, value, nDays, path, domain, secure) {
	var expires=new Date();
	expires.setDate(expires.getDate()+nDays);

	
  var curCookie = name + "=" + escape(value) +
      ((expires) ? "; expires=" + expires.toGMTString() : "") +
      ((path) ? "; path=" + path : "") +
      ((domain) ? "; domain=" + domain : "") +
      ((secure) ? "; secure" : "");
  document.cookie = curCookie;
}


//Method to get a cookie with the passed name.
function getCookie(name) {
  var dc = document.cookie;
  var prefix = name + "=";
  var begin = dc.indexOf("; " + prefix);
  if (begin == -1) {
    begin = dc.indexOf(prefix);
    if (begin != 0) return null;
  } else
    begin += 2;
  var end = document.cookie.indexOf(";", begin);
  if (end == -1)
    end = dc.length;
  return unescape(dc.substring(begin + prefix.length, end));
}


//Method to blend an RGB colour with white based on
//an alpha value.  This simulates alpha transparency
//without having to use the new CSS styles, which
//make a whole object and its childeren transparent.
//Method written by A.Russell (11/04)
function alphaColour(r, g, b, a) {

	if (a>1) {
		return new Array(r, g, b);
	}

	var newR = Math.round((255 * (1-a)) + (r * a));
	var newG = Math.round((255 * (1-a)) + (g * a));
	var newB = Math.round((255 * (1-a)) + (b * a));

	return new Array(newR, newG, newB);

}

function mSpaceOptions()
{
	//Dummy method used to create an options object passed to objects on creation
}

function mSpaceObject()
{
	//Dummy method used to create an options object passed to objects on creation
}


//Function to take an object and inherit all its methods.  This is essentially like object inheritance 
function ImplementInterface(interfaceClass, sourceControl)
{
		var m_interfaceObject = new interfaceClass();
		if (m_interfaceObject.initialise)
		{
			m_interfaceObject.initialise();
		}
		for(x in m_interfaceObject) {
			if ((x!="initialise") && (x!="extend"))
			{
				if (!sourceControl.base)
				{
					sourceControl.base = new Object();
				}
				sourceControl.base[x] = m_interfaceObject[x];					
				if(sourceControl[x]==undefined)
				{
					sourceControl[x]=m_interfaceObject[x];
				}
			}
		}
}

//Function to take an object and inherit all its methods.  This is essentially like object inheritance, 
function ParseOptions(optionsObject, sourceControl)
{
		for(x in optionsObject) {					
				sourceControl["m_" + x]=optionsObject[x];
		}
}

//
// Class construction helper
// 11.07.06 Tony Ambrus
// creates the class className, calling the function eval(className+"()") when instantiating
function bless(className) {
	return (window[className] = function(){
		
		this.extend = function(child){
			var o = this;
			var c = child.prototype;
			//o.$ = {};
			
			for(x in c) {
				if(this[x]==undefined) this[x]=c[x];
				/*
				switch(typeof(this[x])){
					case 'undefined': this[x]=c[x]; break;
					case 'function':
						if(x != 'initialise')
						{
							var f = c[x];
							this.$[x] = function(){
								f.apply(o, arguments);
							}
						}
						break;
					default:
					//	this.$[x]=c[x]; //<-- won't be helpful
				}
				*/
			}
			
			var i = c.initialise;
			var o = this;
			return i ? function(){i.apply(o, arguments)} : function(){};
		}
		
		if(this.initialise)
			this.initialise.apply(this, arguments);

	});

}

//
// Div creation helper - to become a buffer
function createDiv(id,isClassName) {
	var d = document.createElement("div");
	//For w3c compatibility
	d.alt = "";
	d.title = "";
	//###
	if(isClassName)	d.className = id;
	else			d.id = id;
	return d;
}

function dbg(o,delim, recurse){ 
	delim = delim || "\n";
	recurse = recurse || false;
	var t='';
	var ot;
	for(x in o){
		try{
			ox = (recurse) ? ((typeof(o[x])=='object') ? "{ "+dbg(o[x])+"}" : o[x]) : o[x];
			if(typeof(ox) != 'function')
				t+= x+"="+ox+delim;
			else
				t+= "["+x+"]"+delim;
		}catch(e){}
	}
	
	return t;
}

function findCSSRule(id, returnIndex) {

	id = id.toLowerCase();
	// TODO: handle multiple stylesheets
	if(!this.rules)
	{
		this.rules = [];
		if(document.styleSheets[0].cssRules)
			for(var i = 0; i < document.styleSheets.length; i++)
				this.rules.push(document.styleSheets[i].cssRules);
		else
			for(var i = 0; i < document.styleSheets.length; i++)
				this.rules.push(document.styleSheets[i].rules);
	}
			
	if(!this.cache)
		this.cache = {};
	else if(this.cache[id])
		return returnIndex ? this.cache[id] : this.rules[this.cache[id][0]][this.cache[id][1]];
	
	
	for(var i = 0; i < this.rules.length; i++) {
		for(var j = 0; j < this.rules[i].length; j++) {
			if(this.rules[i][j].selectorText.toLowerCase().indexOf(id) != -1) {
				this.cache[id] = [i,j];
				return returnIndex ? [i,j] : this.rules[i][j];
			}
		}
	}
	
	return returnIndex ? -1 : null;
}

function binSearch(x, array)
{
	var low = 0;
	var high = array.length - 1;
	var mid;
	
	while (low <= high) {
		mid = Math.floor((low + high)/2);
		
		if (x < array[mid])			high = mid - 1;
		else if (x > array[mid])	low = mid + 1;
		else						return mid;
	}
	return -1;
}

function binFuzzyCallSearch(x, array, lessThan)
{
	if(!lessThan) return -1;
	
	var low = 0;
	var high = array.length - 1;
	var mid;
	while (low <= high) {
		mid = Math.floor((low + high)/2);
		
		if(lessThan(x,array[mid]))			high = mid - 1;
		else if (lessThan(array[mid], x))	low = mid + 1;
		else								return mid;
	}
	return mid;
}

function getStyle(x,styleProp)
{
	if (x.currentStyle)
		var y = x.currentStyle[styleProp];
	else if (document.defaultView.getComputedStyle)
	{
		try{
			var y = document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
		}catch(e){
			//Fixes a problem with Safari
		}
	}
	return y;
}

function isOdd(num)
{
	var lowNum = Math.floor(num/2);
	var highNum = Math.ceil(num/2);
	return ((highNum-lowNum) == 1);
}


function ObjectToString(object)
{
	if (!object)
		return "";
	var isArray = false;
	if (typeof(object.length)=="number")
		isArray=true;
		
	var returnStr = "";
	
	if (isArray)
	{
		returnStr += "[";
	}
	else
	{
		returnStr += "{";
	}
	
	var firstItem = true;
		
	for (x in object)
	{
		
		
		if (typeof(object[x])=="object")
		{
			if (!firstItem)
			{
				returnStr += ",";
			}			
			if (!isArray)
			{
				returnStr += x + ": ";
			}			
			firstItem = false;
			returnStr += ObjectToString(object[x]);
		}
		else if ((typeof(object[x].length)=="number") && (typeof(object[x])!="string") && (typeof(object[x])!="function"))
		{
			if (!firstItem)
			{
				returnStr += ",";
			}		
			if (!isArray)
			{
				returnStr += x + ": ";
			}				
			firstItem = false;
			returnStr += ObjectToString(object[x]);
		}
		else if (typeof(object[x])!="function")
		{
			if (!firstItem)
			{
				returnStr += ",";
			}			
			if (!isArray)
			{
				returnStr += x + ": ";
			}				
			firstItem = false;
			returnStr += "'" + object[x].replace(/\'/g, '&acute;') + "'";			
		}
		
		
	}
	
	if (returnStr[returnStr.length-1]==",")
	{
		returnStr = returnStr.substring(0,returnStr.length-1);
	}
	
	if (isArray)
	{
		returnStr += "]";
	}
	else
	{
		returnStr += "}";
	}	
	
	return returnStr;
}

function getElementsByClassName(className) {
	var children = document.getElementsByTagName('*') || document.all;
	var elements = new Array();
  
	for (var i = 0; i < children.length; i++) {
		var child = children[i];
		var classNames = child.className.split(' ');
		for (var j = 0; j < classNames.length; j++) {
			if (classNames[j] == className) {
				elements.push(child);
				break;
			}
		}
	}
	return elements;
}

window.mSpaceShortMonthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
window.mSpaceLongMonthNames = ["January", "Febuary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

function DatesIntersect(date1Start, date1End, date2Start, date2End)
{
	
	if ((date1Start>date2Start) && (date1Start<date2End))
	{
		return true;
	}
	else if ((date1End>date2Start) && (date1End<date2End))
	{
		return true;
	}
	else if ((date2Start>date1Start) && (date2Start<date1End))
	{
		return true;
	}	
	else if ((date2End>date1Start) && (date2End<date1End))
	{
		return true;
	}	
	
	return false;
}

function CloneArray(array)
{
	var newarr = new Array();
	for (var i=0;i<array.length;i++)
	{
		newarr.push(array[i]);
	}
	return newarr;
}

