//#require /script/csiCom/global/Event.js

var PROTOTYPING={PROTOTYPING:true};

function guid(){
	return Math.random().toString(16).substring(2).toUpperCase() + Math.random().toString(16).substring(2).toUpperCase();
}

/// Firebug disabler
// disable console (if needed)
if (!("console" in window) || !("firebug" in console)){
	var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
	"group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];

	window.console = {};
	for (var i = 0; i < names.length; i++){
		window.console[names[i]] = function() {}
	}
}

//________________________________________________________________
//================================================ Typeof Function

//________________________________________________________________
//================================================ Typeof Function
// from javascript.crockford.com
/*
function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (value instanceof Array) {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}
*/
//The typeOf function above will only recognize arrays that are created in the same context (or window or frame). JavaScript does not provide an infallible mechanism for distinguishing arrays from objects, so if we want to recognize arrays that are constructed in a different frame, then we need to do something more complicated.
function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (typeof value.length === 'number' &&
                    !(value.propertyIsEnumerable('length')) &&
                    typeof value.splice === 'function') {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}


function isDefined(str){
	if(typeof(str) == "function") return true;
	return eval("typeof(" + str + ") != 'undefined'");
}
function isArray(obj){
	if( typeof(obj) == "undefined" || obj == null ) return false;
	return (typeof(obj) == "array") || ( (typeof(obj) == "object") && (typeof(obj.push) == "function") );
}
function isDate(obj){
	//if(obj == null) return false;
	return (obj instanceof Date);
}

function isDomNode(arg){
	return(arg && arg.nodeName && arg.nodeType);
	
}



// **************************************************************************
// Copyright 2007 - 2009 Tavs Dokkedahl
// Contact: http://www.jslab.dk/contact.php
//
// This file is part of the JSLab Standard Library (JSL) Program.
//
// JSL is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// any later version.
//
// JSL is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// ***************************************************************************

// Return the name of a function
Function.prototype.getName =
  function() {
    var m = this.toString().match(/^function\s(\w+)/);
    return m ? m[1] : "anonymous";
  };
  
  




//_________________________________________________________________________________
//===========================================================  Native js extensions



////////////// NATIVE EXTENSIONS --- ARRAY OBJECT /////////////////
Array.isArray = function(obj){
	if( typeof(obj) == "undefined" || obj == null ) return false;
	//if(obj==null)return false;
	//debug.comment(obj,typeof(obj));
	return (typeof(obj) == "array") || ( (typeof(obj) == "object") && (typeof(obj.push) == "function") );
}

Array.prototype.clone = function(){
	return Array.clone(this);
}
Array.clone = function(arr){
	var newArr = [];
	var obj;
	var objNew = new Object();
	for(var i = 0; i < arr.length; i++){
		obj = arr[i];
		if(typeof obj == "object" || typeof obj == "array"){
			newArr.push($O(obj).clone())
		}
		else{
			newArr.push(obj);
		}
	}
	return newArr;
}

//Array.move: moves an element from oldIndex to newIndex
Array.prototype.move = function(oldIndex,newIndex){
	this._moving = true;
	//debug.comment("moving",oldIndex,newIndex);
	
	if(oldIndex != newIndex && oldIndex < this.length){
		//debug.print(this);
		var arr = this.splice(oldIndex,1);
		//debug.print(this);
		
		if(newIndex > this.length - 1){
		//	debug.comment("pushing");
			this.push(arr[0]);
		}
		else if(newIndex < 0){
		//	debug.comment("unshifting");
			this.unshift(arr[0]);
		}
		else{
		//	debug.comment("splicing");
		//	debug.print(arr[0]);
			this.splice(newIndex,0,arr[0]);
		}
		//debug.print(this);
	}
	
	this._moving = false;
}


// Array.locateMember,hasMember,getMember,removeMember are all overloaded in this way:
// OVERLOADS:
// (attribute,value) returns index of first member with [attribute]==value
// (value) returns index of the first member with member==value
// (func()) returns index of the first member with func(member)==true
Array.prototype.locateMember = function(arg0,arg1){
	var ix=-1;
	if(typeof(arg1) == "undefined"){
		if(typeof(arg0) == "function"){
			ix = this._locateFunc(arg0);
		}
		//elseif(typeof(arg0)==
		else{
			ix = this._locateScalar(arg0);
		}
	}
	else {//if(arguments.length==2){
		ix = this._locateObject(arg0,arg1);
	}
	return ix;
} 
Array.prototype.hasMember = function(arg0,arg1){
	//console.log("hasMember");
	//debug.comment("hasMember",arg0, arg1);
	return this.locateMember(arg0,arg1) > -1;
}
Array.prototype.getMember = function(arg0,arg1){
	var ix = this.locateMember(arg0,arg1);
	if(ix>-1){
		return this[ix];
	}
	else{
		return null;
	}
}
Array.prototype.removeMember = function(arg0,arg1){
	var ix = this.locateMember(arg0,arg1);
	if(ix>-1) this.splice(ix,1);
}

Array.prototype._locateScalar = function(value){
	//debug.comment("locateScalar")
	for(var i = 0; i < this.length; i++){
		//debug.comment(i,this[i],value,this[i]==value);
		if(this[i] == value) return i; //return this[i];
	}
	return -1;//null;
}
Array.prototype._locateFunc = function(func){
	for(var i = 0; i < this.length; i ++){
		if(func(this[i]))return i;
	}
	return -1;
}
Array.prototype._locateObject = function(attribute,value){
	//debug.comment("locateObject");
	for(var i = 0; i < this.length; i ++){
		var v = $O(this[i]).getFieldValue(attribute);
	//debug.comment(v, value, v == value, v === value);
		
		if(v == value)return i;
	}
	return -1;//null;
}


Array.prototype.search = function(){
	// input arguments must be one of the following:
	// (a) arg0 = fieldname, arg1 = value (e.g. customer.ID, 1234)
	// (b) arg0 = function(row){return row.customer.ID == 1234}
	// returns a new array matching the criteria provided
	
	var arg0 = arguments[0];
	var fn = (arguments.length == 1);
	var arg1;
	if(!fn)arg1 = arguments[1];
	
	var res = [];
	for(var i=0;i<this.length;i++){
		if(fn){
			if(arg0(this[i])) res.push(this[i]);
		}
		else{
			if($O(this[i]).getFieldValue(arg0) == arg1) res.push(this[i]);
		}
	}
	return res;
}



/*
Array.extSort:
Sorts an array of objects by multiple fields.

Changes:
01/03/07 -- rj
	Initial version.
7/22/07 -- csh
	Re-wrote to make fewer calls to $O().getFieldValue, and to fix a sorting bug (was not working with more than one sort)

Usage:
[<array> = ]<array>.extSort([params]);

Params:
Array containing objects of the form {field:"field", dir:"a"||"d"}
OR
Any number of objects of the form {field:"field", dir:"a"||"d"}
*/
Array.prototype.extSort = function() {
	var arr = arguments[0];
	if(!arr.length) {
		arr = [];
		for(var i = 0; i < arguments.length; i ++) {
			arr.push(arguments[i]);
		}
	}

	var s = []; // builder for the sort function
	var d; // direction
	
	s.push("sortFunction = function(a, b) {\n");
	if(arr.length > 0) {
		for(var i = 0; i < arr.length; i ++) {
			var arg = arr[i];
			
			d = (arg.dir && arg.dir.toLowerCase()[0] == "d") ? "DESC" : "ASC";
			
			// get values for a and b. 
			s.push("var va = $O(a).getFieldValue('" + arg.field + "');\n");
			s.push("var vb = $O(b).getFieldValue('" + arg.field + "');\n");
			
			// convert undefined's to null. 
			s.push("if(typeof(va) == 'undefined')va = null;\n");
			s.push("if(typeof(vb) == 'undefined')vb = null;\n");
			
			// if ignoreCase==true and stringtype, convert to lowercase
			if(arg.ignoreCase){
				s.push("if(typeof(va) == 'string')va = va.toLowerCase();\n");
				s.push("if(typeof(vb) == 'string')vb = vb.toLowerCase();\n");
			}
			
			// if statement (first pass should be "if", then "else if" from there on)
			// sort null values to.. ?
			s.push("if(va == null || vb == null){\n");
				s.push("if(va == null && vb == null){}\n"); // do nothing if both null
				s.push("else if(va == null){return " + ((d == "ASC") ? "-1" : "1") + "}\n" );
				s.push("else {return " + ((d == "ASC") ? "1" : "-1") + "}\n" );
			s.push("}else{\n");
				s.push( "if(va > vb) return " + ((d == "ASC") ? "1" : "-1") + "\n" );
				s.push( "else if(va < vb) return " + ((d == "ASC") ? "-1" : "1") + ";\n" );
			s.push("}\n");
		}
		// still here? objects are equal.. return 0
		s.push("return 0;\n");
	}
	else {
		s.push("return 0;\n");
	}
	s.push("}");
	
	//alert(s.join(""));
	//$("root").innerHTML=(s.join(""));
	
	var sortFunction;
	eval(s.join(""));
	
	return this.sort(sortFunction);
}
Array.prototype.sortCaseInsensitive = function(){
	this.sort(function(x,y){ 
      var a = String(x).toUpperCase(); 
      var b = String(y).toUpperCase(); 
      if (a > b) return 1;
      if (a < b) return -1;
      return 0; 
    }); 
}

//Event.extend(Object);

Object._nextID = 1;
//Object.makeID=function(){return Object._nextID++}

Object.prototype.getID = function(){
	if(!this._ID){
		this._ID = Object._nextID ++;
	}
	return this._ID;
}

Object.clone = function(obj){
	var newObj = {};
	var o;
	for(var k in obj){
		o = obj[k];
		if(o == null){
			newObj[k] = null;
		}
		else if(isDate(o)){
			newObj[k] = o;
		}
		else if(typeof(o) == "object" || typeof(o) == "array"){
			newObj[k] = $O(o).clone();
		}
		else{
			newObj[k] = o;
		}
	}
	return newObj;
}
/*
Object.prototype.clone = function(){
	if(typeOf(this) == "array"){
		return Array.clone(this);
	}
	else{
		return Object.clone(this);
	}
}
*/


Object.getChanges=function(before,after){
	//This will compare two objects for the differences between them.
	// with arrays, this method will only recognize newly added members. Members that have merely changed will not be included.
	// ** NOTE ** If elements are deleted from the orignal array, or if the array is re-sorted after new elements are added, this method will fail.
	
	// PARAMETERS:
	// before is the object in its original state
	// after is a clone of before which has been altered after cloning
	
	// RETURN VALUE:
	// [object] -- the changes, or null if there are no changes
	
	
	// this method returns a third object which contains any property value which has changed and any array elements which have been added.
	// iterate all the elements in the after object and compare them to the before object
	// update any scalar values that have changed
	// add any array elements that do not exist in the previous object
	
	var changes={};
	var changed=false;
	var beforeType,afterType;
	
	for(var k in after){
		beforeType=typeof(before[k]);
		afterType=typeof(after[k]);
		
		if(beforeType=="undefined"){
			if(afterType=="object"){
				changed = true;
				changes[k] = $O(after[k]).clone();
			}
			else if(afterType == "array"){
				changed = true;
				changes[k] = $O(after[k]).clone();
			}
			else{
				changed = true;
				changes[k] = after[k];
			}
		}
		else if(afterType=="object" || afterType=="array"){
			if(Array.isArray(after[k])){
				if(Array.isArray(before[k])){
					var beforeLength=before[k].length;
					var afterLength=after[k].length;
					//debug.comment(beforeLength, afterLength);
					if(afterLength>beforeLength){
						changed=true;
						changes[k]=[];
						for(var i=0;i<afterLength-beforeLength;i++){
							
							var val=after[k][beforeLength+i];
							//debug.comment(i,beforeLength+i,val);
							if(typeof(val)=="object" || typeof(val)=="array"){
								//debug.comment("cloning");
								changes[k].push(val.clone());
							}
							else{
								//debug.comment("scalar");
								changes[k].push(val);
							}
						}
					}
				}
				else{
					changed=true;
					changes[k]=after[k].clone();
				}
			}
			else if(Date.isDate(after[k])){
				if(Date.isDate(before[k])){
					if(before[k].valueOf()!=after[k].valueOf()){
						changed=true;
						changes[k]=new Date(after[k]);
					}
				}
				else{
					changed=true;
					changes[k]=new Date(after[k]);
				}
			}
			else{
				var chg=Object.getChanges(before[k],after[k]);
				if(chg){
					changed=true;
					changes[k]=chg;
				}
			}
		}
		else{
			if(before[k]!=after[k]){
				changed=true;
				changes[k]=after[k];
			}
		}
	}
	
	if(changed){
		return changes;
	}
	else{
		return null;
	}
}


//Object.getFieldValue: Returns the value of fieldName
//fieldName: a string containing the attribute name (may contain dots to refer to a subobject)
//future extension: support array indexing also!!

function $O(arg){
	return {
		getFieldValue:function(fieldName){
			if(typeof(fieldName) != "string")return null;

			var s = fieldName;
			if(s.indexOf("[") > -1){
				// convert [] to dot, e.g. [0] to .0
				s = s.replace(/\[/g, ".");
				s = s.replace(/\]/g, "");
			}
			if(s.indexOf(".") == -1){
				// no dots. 
				return this._O[s];
			}
			else{
				// evaluate dots
				var arr = s.split(".");
				//debug.print(arr);
				var v = this._O;
				for(var i = 0; i < arr.length ; i ++){
					if( typeof(v) == "undefined" ){
						return null;
					}
					else{
						v = v[arr[i]];
					}
				}
				return v;
			}
		},
		
		setFieldValue:function(fieldName,value){
			var s = fieldName;
			if(s.indexOf("[") > -1){
				// convert [] to dot, e.g. [0] to .0
				s=s.replace(/\[/g, ".");
				s=s.replace(/\]/g, "");
			}
			if(s.indexOf(".") == -1){
				// no dots. 
				this._O[s] = value;
			}
			else{
				// evaluate dots
				var arr = s.split(".");
				var obj = this._O;
				for(var i = 0; i < (arr.length - 1); i ++){
					if(!obj[arr[i]]) obj[arr[i]] = {};
					obj = obj[arr[i]];
				}
				obj[arr[arr.length - 1]] = value;
			}
		},
		
		clone:function(){
			if(isArray(this._O)){
				//typeOf(this) == "array"){
				return Array.clone(this._O);
			}
			else{
				return Object.clone(this._O);
			}
		},
		
		_O : arg
	}
}

/*
Object.prototype.getFieldValue=function(fieldName){
	if(typeof(fieldName)!="string")return null;

	var s=fieldName;
	if(s.indexOf("[")>-1){
		// convert [] to dot, e.g. [0] to .0
		s=s.replace(/\[/g,".");
		s=s.replace(/\]/g,"");
	}
	if(s.indexOf(".")==-1){
		// no dots. 
		return this[s];
	}
	else{
		// evaluate dots
		var arr=s.split(".");
		//debug.print(arr);
		var v=this;
		for(var i=0; i<arr.length ;i++){
			if( typeof(v)=="undefined" ){
				return null;
			}
			else{
				v=v[arr[i]];
			}
			//}
			//catch(e){
			//	return null;
			//}
			//debug.comment(v);
		}
		return v;
	}
	
	///// EASY BUT SLOOOOW METHOD JAN 2007
	//eval("t=this."+fieldName);
}
Object.prototype.setFieldValue=function(fieldName,value){
	this.setFieldValue_object(fieldName,value);
}

Object.prototype.setFieldValue_object=function(fieldName,value){
	var s=fieldName;
	if(s.indexOf("[")>-1){
		// convert [] to dot, e.g. [0] to .0
		s=s.replace(/\[/g,".");
		s=s.replace(/\]/g,"");
	}
	if(s.indexOf(".")==-1){
		// no dots. 
		this[s]=value;
	}
	else{
		// evaluate dots
		var arr=s.split(".");
		var obj=this;
		for(var i=0;i<(arr.length-1);i++){
			if(!obj[arr[i]])obj[arr[i]]={};
			obj=obj[arr[i]];
		}
		obj[arr[arr.length-1]]=value;
	}
	this.raiseEvent(new Event({
		name:"setFieldValue",
		source:this,
		field:fieldName,
		value:value
	}));
}

*/

////////////// NATIVE EXTENSIONS --- DATE OBJECT /////////////////
//var DAYFACTOR = 86400000;
Date.DAYFACTOR = 86400000;
Date.HOURFACTOR = 3600000;
Date.MINUTEFACTOR = 60000;

Date.isDate = function(obj){
	if ( typeof(obj) == "undefined" || obj == null ) return false;
	return (typeof(obj) == "object") && (typeof(obj.getFullYear) == "function");
}
Date.isValidDate = function(obj){
	return Date.isDate(obj) && !isNaN(obj);
}

Date.prototype.getStrMDY = Date.prototype.getStr = function(){
	//var s=""+this.getFullYear();
	return ( this.getMonth() + 1 ) + '/' + this.getDate() + '/' + this.getFullYear();
	
	//s; //.substr(2,2);
	/*
	var m=this.getMonth()+1;
	if(m<10)m="0"+m;
	var d=this.getDate();
	if(d<10)d="0"+d;
	

	
	return this.getFullYear()+"-"+m+"-"+d;
	*/
}
Date.prototype.getStrMDYHM = function(){
	return this.getStr() + " " + this.getStrHM();
}

Date.prototype.getStrHM = function() {
	var h = this.getHours();
	if(h < 10)h = "0" + h;
	var m = this.getMinutes();
	if(this.getSeconds() >= 30)m += 1;
	if(m < 10)m = "0" + m;
	return h + ":" + m;
}
Date.prototype.getStrHMS = function() {
	var h = this.getHours();
	if(h < 10)h = "0" + h;
	var m = this.getMinutes();
	if(m < 10)m = "0" + m;
	var s = this.getSeconds();
	if(s < 10)s = "0" + s;
	return h + ":" + m + ":" + s;
}

Date.prototype.getTimeStr = function() {
	var arr = this.toLocaleTimeString().split(":");
	var arr2 = arr[2].split(" ");
	return arr[0] + ":" + arr[1] + " " + arr2[1];
}

Date.prototype.getStrYMD=function(){
	//return (this.getMonth()+1)+'/'+this.getDate()+'/'+this.getFullYear();
	
	var m=this.getMonth()+1;
	if(m<10)m="0"+m;
	var d=this.getDate();
	if(d<10)d="0"+d;
	

	
	return this.getFullYear()+"-"+m+"-"+d;
	
}

//alert(Date.prototype.getStr);

Date.prototype.getStrYMDHM=function(){
	var m=this.getMonth()+1;
	if(m<10)m="0"+m;
	var d=this.getDate();
	if(d<10)d="0"+d;
	var h=this.getHours();
	if(h<10)h="0"+h;
	var min=this.getMinutes();
	if(this.getSeconds()>=30)min+=1;
	if(min<10)min="0"+min;
	//var s=this.getSeconds();
	//if(s<10)s="0"+s;
	
	//alert(s);
	
	return this.getFullYear()+"-"+m+"-"+d+" "+h+":"+min;
}

Date.prototype.getStrYMDT=function(){
	var m=this.getMonth()+1;
	if(m<10)m="0"+m;
	var d=this.getDate();
	if(d<10)d="0"+d;
	var h=this.getHours();
	if(h<10)h="0"+h;
	var min=this.getMinutes();
	if(this.getSeconds()>=30)min+=1;
	if(min<10)min="0"+min;
	var s=this.getSeconds();
	if(s<10)s="0"+s;
	
	//alert(s);
	
	return this.getFullYear()+"-"+m+"-"+d+" "+h+":"+min+":"+s;
		
		//("0"+this.getMonth()+1).substring(
		//)+'/'+this.getDate()+'/'++" "+this.getHours()+":"+this.getMinutes();
}

Date.prototype.isSameDayAs = function(d){
	return (this.getFullYear() == d.getFullYear())
	&& (this.getMonth() == d.getMonth())
	&& (this.getDate() == d.getDate());
}
Date.dayNames = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
Date.prototype.getDayName=function(){
	var arr=Date.dayNames;
	return arr[this.getDay()];
}
Date.prototype.getShortDayName = function(){
	return Date.dayNames[this.getDay()].substr(0,3);
}
Date.monthNames = ["January","February","March","April","May","June","July","August","September","October","November","December"];
Date.prototype.getMonthName = function(){
	return Date.monthNames[this.getMonth()];
}

Date.prototype.addDays = function(pDays){
	return new Date(this.valueOf() + (pDays * Date.DAYFACTOR));
}


Date.prototype.clone = function(){
	return new Date(this);
}

Date.prototype.getDaysBetween = function(d){
	// get the number of days relative to the given date. 
	// normalze both to 0 hours, and then compare them
	var da = new Date(""+(this.getMonth()+1)+"/"+(this.getDate())+"/"+this.getFullYear());

	if(!d)d = new Date();
	var db =  new Date(""+(d.getMonth()+1)+"/"+(d.getDate())+"/"+d.getFullYear());
	
	return Math.round((da.valueOf() - db.valueOf())/Date.DAYFACTOR);
}

Date.prototype.getRelativeDescriptor = function(d){
	if(!d) d = new Date(); // d is the date to compare to; default is the current date. 
	var n = this.getDaysBetween(d);
	if(n == 0)return "TODAY";
	var dy = d.getDay();
	var weekAdjust;
	if(n > 0){
		// future date
		if(n == 1)return "Tomorrow";
		switch(dy){
			case 1: // Monday
				if(n < 7)return "In "+n+" days";
				weekAdjust = 7;
				break;
			case 2: // Tuesday
				if(n < 6)return "In "+n+" days";
				weekAdjust = 6;
				break;
			case 3: // Wednesday
				if(n < 5)return "In "+n+" days";
				weekAdjust = 5;
				break;
			case 4: // Thursday
				if(n < 4)return "In "+n+" days";
				weekAdjust = 4;
				break;
			case 5: // Friday
				if(n < 3)return "In "+n+" days";
				weekAdjust = 3;
				break;
			case 6: // Saturday
				weekAdjust = 2;
				break;
			case 0: // Sunday
				weekAdjust = 1;
				break;
		}
	
		var weeks = Math.floor((n - weekAdjust)/7) + 1;
		//debug.comment(this,d,dy,"n",n,"weekAdjust",weekAdjust,"weeks",weeks);
		if(weeks == 1) return "Next week";
		return "In "+weeks+" weeks";
	}
	else{
		// past date
		n = Math.abs(n);
		if(n == 1)return "Yesterday";
		//return (-1 * n)+" days ago"
			// future date
		switch(dy){
			case 1: // Monday
				weekAdjust = 1;
				break;
			case 2: // Tuesday
				weekAdjust = 2;
				break;
			case 3: // Wednesday
				if(n < 3)return n + " days ago";
				weekAdjust = 3;
				break;
			case 4: // Thursday
				if(n < 4)return n + " days ago";
				weekAdjust = 4;
				break;
			case 5: // Friday
				if(n < 5)return n + " days ago";
				weekAdjust = 5;
				break;
			case 6: // Saturday
				if(n < 6)return n + " days ago";
				weekAdjust = 6;
				break;
			case 0: // Sunday
				if(n < 7)return n + " days ago";
				weekAdjust = 7;
				break;
		}
	
		var weeks = Math.floor((n - weekAdjust)/7) + 1;
		//debug.comment(this,d,dy,"n",n,"weekAdjust",weekAdjust,"weeks",weeks);
		if(weeks == 1) return "Last week";
		return weeks+" weeks ago";
	}
	return n;
}

/////////////// NATIVE EXTENSIONS --- STRING OBJECT /////////////////
//convert cr-lf to <br>
String.prototype.toBreak=function(){
	return this.replace(/\r?\n/gi,"<br>");
	
	//s=s.replace(//gi,"");
	//return s;
}
//convert <br> to cr-lf
String.prototype.toCrLf=function(){
	return this.replace(/<br>/gi,String.fromCharCode(13,10));
}
//convert html to text
String.prototype.htmlToText=function(){
	//change existing breaks to cr's
	var str=this.replace(/<br>/gi,String.fromCharCode(13,10));
	//un-escape tag characters
	str=str.replace(/&gt;/gi,">");
	str=str.replace(/&lt;/gi,"<");
	return str;
}
//convert text to HTML
String.prototype.textToHtml=function(){
	//first escape out tag characters
	var str=this.replace(/>/gi,"&gt;");
	str=str.replace(/</gi,"&lt;");
	//change cr's to breaks
	str=str.replace(/\r\n/gi,"<br>");
	return str;
}

	
//startswith and endswith functions (thanks to Michael Schwarz --- http://weblogs.asp.net/mschwarz/)
String.prototype.endsWith=function(s){
	//debug.comment(this+" "+s+" "+this.length+" "+s.length+" "+this.substr(this.length-s.length));
	
	return (this.substr(this.length - s.length) == s);
}
String.prototype.startsWith=function(s){
	return (this.substr(0, s.length) == s);
}
String.prototype.contains=function(s){
	var re=new RegExp(s,"i");
	return re.test(this);
}
	
//trim functions
String.prototype.ltrim=function(){
    return this.replace(/^\s*/g,'');
}
String.prototype.rtrim=function(){
    return this.replace(/\s*$/g,'');
}
String.prototype.trim=function(){
    return this.replace(/^\s*|\s*$/g,'');
}

//this version is deprecated..
String.prototype.rTrim=function(){
	var re=/ +$/;
	return this.replace(re,"");
}

//format: (thanks to Michael Schwarz --- http://weblogs.asp.net/mschwarz/)
String.prototype.format=function(){
	var s=this;
	for(var i=0; i<arguments.length; i++) {
		s = s.replace("{" + (i) + "}", arguments[i]);
	}
	return s;
}
String.format=function(s){
	//var s=this;
	for(var i=1; i<arguments.length; i++) {
		s = s.replace("{" + (i-1) + "}", arguments[i]);
	}
	return s;
}
String.prototype.formatA = function() {
	var s = this;
	for(var i=0; i<arguments[0].length; i++) {
		s = s.replace("{" + (i) + "}", arguments[0][i]);
	}
	return s;
}
String.formatA = function(s) {
	for(var i=0; i<arguments[1].length; i++) {
		s = s.replace("{" + (i) + "}", arguments[1][i]);
	}
	return s;
}
//// Regular expression helpers
String.prototype.escapeRegExp=function(){
	var re=/(\$|\(|\)|\*|\+|\.|\[|\]|\?|\\|\/|\^|\{|\}|\|)/g;
	return this.replace(re,"\\"+"$1");
}

String.prototype.toCapitalized = function() {
	var s = this.substr(0,1);
	var e = this.substring(1);
	return (s.toUpperCase() + e);
}



///////////////////////////////////////////////////////////////////////////////
/////////////// HANDY CLASSES /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function Position(left,top,width,height){
	this.left=left;
	this.top=top;
	this.width=width;
	this.height=height;
}





///////////////////////////////////////////////////////////////////////////////
//////////////// SERIALIZER IS DEPRECATED -- USE JSON class! //////////////////
///////////////////////////////////////////////////////////////////////////////

SERIALIZER_UNIT_DELIMITER=String.fromCharCode(31);
SERIALIZER_RECORD_DELIMITER=String.fromCharCode(30);
SERIALIZER_GROUP_DELIMITER=String.fromCharCode(29);
SERIALIZER_FILE_DELIMITER=String.fromCharCode(28);

String.prototype.serialize=function(){
	//accepts any number of string arguments, OR an array argument
	//returns a serialized string
	
	//serialize all of the arguments using a temporary delimiter
	var tempDelim=String.fromCharCode(255); //temporary placeholder delimiter
	var outStr=""; //to hold the output string
	var x; //counter
	
	var arr; 
	if(typeof(arguments[0])=="object"&&arguments[0].length){
		arr=arguments[0];
	}
	else{
		arr=arguments;
	}
	//append all but the last argument
	for(x=0;x<arr.length-1;x++){
		outStr=outStr+arr[x]+tempDelim;
	}
	//append the last argument
	outStr = outStr + arr[x];
	
	//scan the string for existing delimiters, starting with the lowest-level delimiter. 
	//replace the temp delimiter with the lowest-level delimiter that is not found in the string
	//unit delimiter 31
	//record delimiter 30
	//group delimiter 29
	//file delimiter 28
	var re; //to hold test regular expression
	var matched=false;
	var delim;
	for(x=31;x>27;x--){
		if(outStr.indexOf(String.fromCharCode(x))==-1){
			re=new RegExp(String.fromCharCode(255),"g");
			outStr=outStr.replace(re,String.fromCharCode(x));
			matched=true;
			break;
		}
	}
	//String.fromCharCode(29);
	
	return outStr;

}

String.prototype.deSerialize=function(){
	//accepts a string (or if no string then deserialize the instance string)
	
	var s;
	if(arguments.length==1){
		s=arguments[0];
	}
	else{
		s=this;
	}
	
	//returns a string array
	
	//scan the string for delimiters, 
	//starting with the highest-level delimiter (ascii 28)
	var i;
	var delim;
	for(i=28;i<32;i++){
		delim=String.fromCharCode(i);
		//alert(i)
		//alert(pStr.indexOf(delim));
		if(s.indexOf(delim)>-1){
			return s.split(delim);
		}
	}
	//no delimiter was found.
	//return single-element array
	return s.split(delim);
}





///////////////////////////////////////////////////////////////////////
//////////// FormObject is deprecated.. use AJAX, man!! ///////////////
///////////////////////////////////////////////////////////////////////
function FormObject(){
	this.params = new Object();
	
	this.addParam = function(nam,val){
		//adds a complex object OR simple param to this.params
		var str = nam;
		if(typeof(val).toLowerCase == "object" && val != null){
			if(val.length){
				for(var i = 0; i < val.length; i ++){
					str += this.addParam(nam + '_' + i,val[i]);
				}
			}
			else{
				for(var e in val){
					str += this.addParam(nam + '_' + e,val[e]);
				}
			}
		}
		else{
			this.params[nam] = val;
		}
		return nam;
	}
	this.submitForm = function(url,doc){
		//Submits this.params to the specified url, 
		//via the specified document (or document, if not specified)
		if(!doc)doc = document;
		var frm = doc.createElement("form");
		frm.action = url;
		frm.method = 'post';
		var inp;
		for (var oItem in this.params){
			//alert(oItem);
			//alert(typeof(this.params[oItem]));
			if(typeof(this.params[oItem]) != "function"){
				//alert(oItem+' '+this.params[oItem]);
				inp = doc.createElement("input");//<input type='hidden'>");
				inp.type = "hidden";
				//inp=document.createElement("<input>");
				inp.name = oItem;
				inp.value = this.params[oItem];
				frm.appendChild(inp);
			}
		}
		doc.body.appendChild(frm);
		frm.submit();
	}
	this.getQueryString = function(url){
		//Builds a querystring by appending the values in this.params
		//to the specified URL
		//returns the querystring
		var str = url + "?";
		for (el in this.params){
			if(typeof(this.params[el]) != "function"){
				str += el + "=" + this.params[el] + "&";
			}
		}
		return str;
	}
}


