// Created by YKM (c) 2008
// ------------------------
// Common JS library. Please remove all unnecessary items

/************************************************************************************************************/
/* DocClick module: allows multiple OnClick assignments for the onClick event on the document's BODY object */
/************************************************************************************************************/
var docOnClick_taskList = new Array();
var DocOnClick;

function _taskSort(a,b) {
	return (a[1] - b[1]);
}

function DocumentOnClick() {
	// In order to use this object, define it with "var varname = new DocumentOnClick();" statement.
	// Assign and/or remove tasks using the object's Add and Remove methods defined below.
	this.Add = function(taskid,functionref,optPriority) {
		// This method adds a function reference to the queue.
		// functionref can be either a reference to the function object or a string which will be EVALed.
		// If optMakeFirst is not defined, the reference is added at the bottom of the queue, getting the next available ID
		if ((typeof functionref != "function" && typeof functionref != "string") || typeof taskid != "string") {
			return false;
		}
		if (typeof optPriority == "undefined" || optPriority == null) {
			docOnClick_taskList.push(new Array(functionref,docOnClick_taskList.length,taskid));
		} else {
			// optPriority is defined. The task is added with the proper priority, while the existing tasks with the same priority and lower move down one level
			var newprior = optPriority;
			for (var i=0;i<docOnClick_taskList;i++) {
				if (docOnClick_taskList[i][1] >= newprior) {
					docOnClick_taskList[i][1]++;
				}
			}
			docOnClick_taskList.push(new Array(functionref,docOnClick_taskList.length,taskid));
		}
		// Sort the task array
		if (docOnClick_taskList.length > 1) docOnClick_taskList.sort(_taskSort);
	}
	this.Remove = function(taskid) {
		// Locate the task
		var remindex = null;
		for (var i=0;i<docOnClick_taskList.length;i++) {
			if (docOnClick_taskList[i][2].toUpperCase() == taskid.toUpperCase()) {
				remindex = i;
				break;
			}
		}
		if (remindex == null) return false;
		// Remove the task
		var oldprio = docOnClick_taskList[remindex][1];
		docOnClick_taskList.splice(remindex,1);
		// Move all subsequent task priorities one level up
		for (var i=0;i<docOnClick_taskList.length;i++) {
			if (docOnClick_taskList[i][1] <= oldprio) {
				docOnClick_taskList[i][1]--;
			}
		}
		// Sort the task array
		if (docOnClick_taskList.length > 1) docOnClick_taskList.sort(_taskSort);
	}
	this.RunTasks = function(ev) {
		for (var i=0;i<docOnClick_taskList.length;i++) {
			var ref = docOnClick_taskList[i][0];
			if (typeof ref == "function") try { ref(ev); } catch(e) {}
			if (typeof ref == "string") try { eval(ref); } catch(e) {}
		}
	}
	document.body.onclick = this.RunTasks;
}

/*************************************/
/* Query strings, hashes and cookies */
/*************************************/

function GetQueryString(param) {
	if (document.location.href.indexOf("?")==-1) return null;
	var qs = document.location.href.split("?")[1];
	var allPairs = qs.split("&");
	for (var i=0;i<allPairs.length;i++) {
		var pr = allPairs[i].split("=");
		if (pr[0].toLowerCase() == param.toLowerCase()) return pr[1];
	}
	return null;
}

function SetCookie(cname, cvalue) {
	var latedate = new Date(2099,12,12,0,0,0,0);
	var cookiestr = cname+"="+cvalue+";expires="+latedate.toGMTString();
	document.cookie = cookiestr;
}

function GetCookie(cname) {
	// Returns the string value of the desired cookie or boolean "false" if the cookie not found
	var temparr = document.cookie.split("; ");
	for (var i=0;i<temparr.length;i++) {
		var tempitem = temparr[i].split("=");
		if (tempitem[0] == cname) {
			return tempitem[1];
		}
	}
	return false;
}

function CookiesSupported() {
	// Returns true if cookie set/get cycle was succesful
	this.SetCookie("cookietest","1");
	var test = this.GetCookie("cookietest");
	if (test == "1") {
		this.SetCookie("cookietest","");
		return true;
	} else {
		return false;
	}
}

/****************************************************/
/* Element retrieval extensions, hierarchy controls */
/****************************************************/

function IsChildOf(who,pt) {
	// Returns boolean stating whether "who" is a child of "pt" in any generation
	try {
		if (pt == document.body) return true;
		if (who == pt) return true;
		var t = who.parentNode;
		while (1==1) {
			if (t == document.body) return false;
			if (t == pt) return true;
			t = t.parentNode;
		}
	} catch(e) { return false; }
}

function getElementsByPartialID(partid,optParent) {
	// Returns all elements who's IDs either equal or contain the partid value
	// optParent is used internally, or can be used to find elements which are childnodes of the specified object
	var res = new Array();
	if (typeof optParent == "undefined" || optParent == null) {
		var p = document.body;
	} else {
		var p = optParent;
	}
	if (typeof p.id != "undefined" && p.id.indexOf(partid)>-1) res.push(p);
	if (typeof p.childNodes != "undefined" && p.childNodes != null) {
		for (var j=0;j<p.childNodes.length;j++) {
			var subs = getElementsByPartialID(partid,p.childNodes[j]);
			for (var i=0;i<subs.length;i++) res.push(subs[i]);
		}
	}
	return res;
}

function getElementsByClass(classname,optParent) {
	// Returns all elements who's class either equal or contain the classname value
	// optParent is used internally, or can be used to find elements which are childnodes of the specified object
	var res = new Array();
	if (typeof optParent == "undefined" || optParent == null) {
		var p = document.body;
	} else {
		var p = optParent;
	}
	if (typeof p.className != "undefined" && p.className.indexOf(classname)>-1) res.push(p);
	if (typeof p.childNodes != "undefined" && p.childNodes != null) {
		for (var j=0;j<p.childNodes.length;j++) {
			var subs = getElementsByClass(classname,p.childNodes[j]);
			for (var i=0;i<subs.length;i++) res.push(subs[i]);
		}
	}
	return res;
}

function getElementsByAttribute(attr,tobj,inside) {
	// Returns an array of all elements that have the specified attribute.
	// The tobj parameter is optional and can be used to seek the elements using the tobj element as the root (only tobj's childnodes are scanned)
	// The inside parameter is for internal use only.
	var cres = new Array();
	if ((typeof tobj == "undefined" || tobj == null) && (!inside)) {
		var t = document.body;
	} else if ((typeof tobj == "undefined" || tobj == null) && (inside)) {
		return null;
	} else {
		if (typeof tobj == "string") {
			var t = document.getElementById(t);
		} else {
			var t = tobj;
		}
	}
	for (var inum = 0; inum<t.childNodes.length; inum++) {
		var myitem = t.childNodes[inum];
		if (typeof myitem != "undefined" &&  typeof myitem.getAttribute != "undefined" && myitem.getAttribute(attr) != null) {
			cres.push(myitem);
		}
		var tempres = getElementsByAttribute(attr,myitem,true);
		if (tempres != null) {
			for (var j = 0; j<tempres.length; j++) cres.push(tempres[j]);
		}
	}
	return cres;
}

function getElementsByAttributeValue(attr,val) {
	// Returns an array of all elements who have the specified attribute with the specified value
	var allitems = getElementsByAttribute(attr);
	var temp = new Array();
	for (var i=0;i<allitems.length;i++) {
		if (allitems[i].getAttribute(attr) == val) temp.push(allitems[i]);
	}
	return temp;
}

/************************************/
/* Element location and positioning */
/************************************/

function _getRealX(who) {
	// Returns the true X (from left 0) of an object.
	// The parameter can be either reference of an ID of the object
	var obj = (typeof who == "string")?document.getElementById(who):who;
	var res = 0;
	var t = who;
	while (1 == 1) {
		if (typeof t.offsetLeft != "undefined") res += t.offsetLeft;
		t = t.offsetParent;
		if (t == document.body) return res;
	}
}

function _getRealY(who) {
	// Returns the true Y (from top 0) of an object.
	// The parameter can be either reference of an ID of the object
	var obj = (typeof who == "string")?document.getElementById(who):who;
	var res = 0;
	var t = who;
	while (1 == 1) {
		if (typeof t.offsetTop != "undefined") res += t.offsetTop;
		t = t.offsetParent;
		if (t == document.body) return res;
	}
}

/**************/
/* Prototypes */
/**************/

/** Arrays **/

Array.prototype.AddItems = function(resultFormattedString,optItemDelimiter,optPropDelimiter,optDuplicateContainer) {
	// This method breaks the properly formatted result string and adds the data arrays into the __results array.
	// The string must be formed of "~#~"-separated items (or any other, defined by the optItemDelimiter parameter).
	// Each item contains values (properties) separated by "~!~" (or any other, defined by the optPropDelimiter).
	
	// optDuplicateContainer is an optional reference to another array, which contains items of the similar structure. When this
	// parameter is provided, only the items that are NOT present in the optDuplicateContainer array will be added.
	if (typeof resultFormattedString == "undefined" || resultFormattedString == null || resultFormattedString == "") return;
	
	var blkd = Default(optItemDelimiter,"~#~");
	var itmd = Default(optPropDelimiter,"~!~");
	
	var blocks = resultFormattedString.split(blkd);
	for (var i=0;i<blocks.length;i++) {
		var items = blocks[i].split(itmd);
		if (typeof optDuplicateContainer != "undefined" && optDuplicateContainer != null) {
			// Check if item is already present in the selection list
			if (optDuplicateContainer.ItemPresent(items) == false) {
				this.push(items);
			}
		} else {
			this.push(items);
		}
	}
}

Array.prototype.Clear = function() {
	// This method clears the entire array of data
	this.splice(0,this.length);
}

Array.prototype.ItemPresent = function(obj) {
	// This method scans the array. Returns TRUE if the specified object is found in the array.
	for (var i=0;i<this.length;i++) {
		if (this[i].join(":") == obj.join(":")) return true;
	}
	return false;
}

Array.prototype.ItemIndex = function(obj) {
	// Returns the position of obj within the array, or NULL if not found
	for (var i=0;i<this.length;i++) {
		if (this[i].join(":") == obj.join(":")) return i;
	}
	return null;
}

Array.prototype.FindNestedArrayWithValue = function(seekArray) {
	// This function scans the array for values, which are themselves of the Array type.
	// In case there is such a value, with an inner value(s) corresponding to the one(s) provided, the parent index is returned.
	// If the item is not found, null is returned.
	// seekArray is an Array with the matching structure as the one being seeked, while the irrelevant values are set as NULL, and the relevant ones
	// are filled with the proper value. For example, if we need to find a nested array of 5 values, with the first value of 10, and third value of 15,
	// the seekArray will have to look like this: [10,null,15,null,null].
	for (var i=0;i<this.length;i++) {
		if (typeof this[i].length != "undefined" && typeof this[i].length != "string" && this[i] != null) {
			// Item is probably an array
			var res = true;
			for (var j=0;j<seekArray.length;j++) {
				if (seekArray[j] != null) {
					if (seekArray[j] != this[i][j]) {
						res = false; break;
					}
				}
			}
			if (res == true) return i;
		}
	}
	return null;
}

Array.prototype.MoveItemUp = function(obj) {
	// This method moves the obj (if it's found) one place up the array's index
	var myindex = this.ItemIndex(obj);
	if (myindex == 0) return;
	var tempval = this[myindex - 1];
	this[myindex - 1] = this[myindex];
	this[myindex] = tempval;
}

Array.prototype.MoveItemDown = function(obj) {
	// This method moves the obj (if it's found) one place down the array's index
	var myindex = this.ItemIndex(obj);
	if (myindex == (this.length-1)) return;
	var tempval = this[myindex + 1];
	this[myindex + 1] = this[myindex];
	this[myindex] = tempval;
}

/** Strings **/

String.prototype.Replace = function(seek,repl) {
	// This method returns the original string with ALL instances of seek string replaced with the repl string.
	var temp = this.split(seek);
	var newstr = temp[0];
	for (var i=1;i<temp.length;i++) {
		newstr += (repl + temp[i]);
	}
	return newstr;
}

/** Dates **/

Date.prototype.isSoonerThan = function(thandate) {
	// Returns a boolean of the Date being earlier than "thandate".
	return (this.valueOf() < thandate.valueOf());
}

Date.prototype.isLaterThan = function(thandate) {
	// Returns a boolean of the Date being later than "thandate".
	return (this.valueOf() > thandate.valueOf());
}

Date.prototype.isSameAs = function(asdate,ignoretime) {
	// Returns TRUE if the Date and the asdate are equal.
	// In case ignoretime is TRUE, the time component is omited.
	if (ignoretime == true) {
		var tempdate1 = new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0,0);
		var tempdate2 = new Date(asdate.getFullYear(),asdate.getMonth(),asdate.getDate(),0,0,0,0);
		return (tempdate2.valueOf() == tempdate1.valueOf());
	} else {
		return (this.valueOf() == asdate.valueOf());
	}
}

Date.prototype.isWithin = function(startdate,enddate,ignoretime) {
	// Returns TRUE when Date is between startdate and enddate (included).
	// If ignoretime is TRUE, the time component of all dates is ignored.
	if (ignoretime == true) {
		var tempdate1 = new Date(startdate.getFullYear(),startdate.getMonth(),startdate.getDate(),0,0,0,0);
		var tempdate2 = new Date(enddate.getFullYear(),enddate.getMonth(),enddate.getDate(),0,0,0,0);
		var mydate = new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0,0);
		return (mydate.valueOf()>tempdate1.valueOf() && mydate.valueOf()<tempdate2.valueOf());
	} else {
		return (this.valueOf()>startdate.valueOf() && this.valueOf()<enddate.valueOf());
	}
}


