/**
 * jQuery CFJS plugin
 * version 1.0.5a (04/23/2007)
 * @requires jQuery (http://jquery.com)
 
 * Copyright (c) 2007 Christopher Jordan
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Modified by Christopher Jordan (cjordan@placs.net) from
 * code originally written (except where noted) by 
 * Randy Anderson (randerson@leftcorner.com), and published
 * as-is and without license as LeftCorner.js
 * LeftCorner - http://www.leftcorner.com
 *
 * I'd like to thank Randy for the work he put in on the library as
 * it was when I started working on it. 
 *
 * Thanks Randy. :o)
 *
 * IMPORTANT NOTICE:
 * Quite a few methods depend on other methods. Be careful if you 
 * remove/rename a method!
 *
 * Description:
 *   JavaScript equivilants of useful ColdFusion functions. 
 *   The methods are designed to behave like their ColdFusion 
 *   counterparts. Of course, don't forget that JavaScript
 *   (unlike ColdFusion) is case sensitive!
 
 * Please see the changelog for more information and credits, including
 * the entire function list. These comments were getting too big so I moved
 * all of that to the changelog.
 *
 * The changelog can be found in the SVN repository on RIA Forge
 * at http://cfjs.riaforge.org. 
 *
 * The function list can also be found at http://cjordan.us
 *
 * Usage:
 *  General:
 *    In general all functions are accessed like so:
 *
 *      $.funcName(args);
 *		
 *  Examples:
 *    // this example assumes that myArray and ColumnDetailStruct are defined.
 *    // check to see if the structure in the array element is defined and if so 
 *    // check to see that the key, "columnnamesort" exists, behaive accordingly...
 *    if($.IsDefined(myArray[myArray.length - 1]) && $.StructKeyExists(myArray[myArray.length - 1], "columnnamesort")){
 *        ColumnDetailStruct.columnnamesort = (myArray[myArray.length -1].columnnamesort) + 10;
 *    }
 *    else{ // the key, "columnnamesort" did not exist... so create it and set it to 10.
 *        ColumnDetailStruct.columnnamesort = 10;
 *    } 
 *
 *   -OR-
 *
 *    This example shows how one could replace what would normally be a long string similar to:
 *     if(a == value || a == value2 || a == value3 || a == valueN.......){
 *         // do something cool if the above is true
 *     } 
 *    ... into the following much shorter code ... 
 * 
 *    // this example assumes that a variable ThisReportType has already been defined
 *    var myList = "Daily Needs,Fill Rate,Spend Recap";
 *    if($.ListFindNoCase(myList, ThisReportType)){
 *        //do something special for these types of reports
 *    }
 *
 */
jQuery.extend({
	_CommaForThousands: function(n){
		var c = n.length; // loop count
		var p = n.indexOf('.'); // position
		var r = "";
		if(p > -1) n = n.slice(0,p); // if a decimal was provided... slice it off.
		for (var i = 1; i <= c; i++){
			r = this.Right(n, 1) + r;
			n = n.slice(0,-1);
			if(i%3 == 0 && c > 3){
				r = "," + r;
			}
		}
		return r;
	},
	Abs: function(n){
		return Math.abs(n);
	},	
	ArrayAppend: function(a, v){
		return a.push(v);
	},
	ArrayPrepend: function(a, v){
		return a.unshift(v);
	},
	ArraySort: function(a,st,so){
		var _so;
		if (st.toUpperCase() == 'TEXTNOCASE'){ 
			if(!so || so.toUpperCase() != "DESC"){
				_so = function(a, b) {a = a.toUpperCase(); b = b.toUpperCase(); if (a < b){return -1;} else if(a > b){return 1;} else {return 0;}};
			} else {
				_so = function(a, b) {a = a.toUpperCase(); b = b.toUpperCase(); if (a > b){return -1;} else if(a < b){return 1;} else {return 0;}};
			}		
		} else if (st.toUpperCase() == 'TEXT'){ 
			if(!so || so.toUpperCase() != "DESC"){
				_so = function(a, b) {if (a < b){return -1;} else if(a > b){return 1;} else {return 0;}};
			} else {
				_so = function(a, b) {if (a > b){return -1;} else if(a < b){return 1;} else {return 0;}};
			}		
		} else if (st.toUpperCase() == 'NUMERIC'){
			if(!so || so.toUpperCase() != "DESC"){
				_so = function(a,b) {return a - b;};
			} else {
				_so = function(a,b) {return b - a;};
			}			
		}
		return a.sort(_so);
	},
	ArrayToList: function(a,d){
		if(!d){d = ",";}
		var re = /[,]/gi;
		return a.toString().replace(re, d);
	},
	ArrayLen: function(a){		
		return a.length;		
	},	
	Ceiling: function(n){
		return Math.ceil(n);
	},
	Compare: function(s1,s2){
		if (s1 == s2) {return 0;}
		if (s1 > s2) {return 1;}	
		else {return -1;}
	},
	CompareNoCase: function(s1,s2){
		return this.Compare(s1.toUpperCase(),s2.toUpperCase());
	},
	DateDiff: function(dp,d1,d2){
		var dt1 = new Date(d1);
		var dt2 = new Date(d2);
		var iDiffMS = dt2.valueOf() - dt1.valueOf();
		var dtDiff = new Date(iDiffMS);
		var nYears  = dt2.getUTCFullYear() - dt1.getUTCFullYear();
		var nMonths = dt2.getUTCMonth() - dt1.getUTCMonth() + (nYears!==0 ? nYears*12 : 0);
		var nQuarters = nMonths / 3;		
		var nMilliseconds = iDiffMS;
		var nSeconds = iDiffMS / 1000;
		var nMinutes = nSeconds / 60;
		var nHours = nMinutes / 60;
		var nDays  = nHours / 24;
		var nWeeks = nDays / 7;
		var iDiff = 0;		
		switch(dp.toLowerCase()){
			case "yyyy": return nYears;
			case "q": return nQuarters;
			case "m": return nMonths;
			case "y": return nDays;
			case "d": return nDays;
			case "w": return nDays;
			case "ww":return nWeeks;		
			case "h": return nHours;
			case "n": return nMinutes;
			case "s": return nSeconds;
			case "ms":return nMilliseconds;
			default: return "invalid interval: '" + dp + "'";
		}
	},
	DateFormat: function (_date, _mask){
	    /********************************************************
	    *   Valid Masks:
	    *   mmmm = Long month (eg. January)
	    *   mmm = Short month (eg. Jan)
	    *   mm = Numeric date (eg. 07)
	    *   m = Numeric date (eg. 7)
	    *   dddd = Long day (eg. Monday)
	    *   ddd = Short day (eg. Mon)
	    *   dd = Numeric day (eg. 07)
	    *   d = Numeric day (eg. 7)
	    *   yyyy = Year (eg. 1999)
	    *   yy = Year (eg. 99)
	   ********************************************************/
	
	    var intMonth = _date.getMonth();
	    var intDate = _date.getDate();
	    var intDay = _date.getDay();
	    var intYear = _date.getFullYear();
	
	    var months_long		= ['January','February','March','April','May','June','July','August','September','October','November','December'];
	    var months_short	= ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
	    var days_long		= ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
	    var days_short		= ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
	
	    var mmmm = months_long[intMonth]
	    var mmm = months_short[intMonth]
	    var mm = intMonth < 9?'0'+ (1 + intMonth) + '':(1+intMonth)+'';
	    var m = 1+intMonth+'';
	    var dddd = days_long[intDay];
	    var ddd = days_short[intDay];
	    var dd = intDate<10?'0'+intDate+'':intDate+'';
	    var d = intDate+'';
	    var yyyy = intYear;
	
	    var century = 0;
	    while((intYear-century)>=100)
	        century = century + 100;
	
	    var yy = intYear - century
	    if(yy<10)
	        yy = '0' + yy + '';
	
	    DisplayDate = new String(_mask);
	
	    DisplayDate = DisplayDate.replace(/mmmm/i,mmmm);
	    DisplayDate = DisplayDate.replace(/mmm/i,mmm);
	    DisplayDate = DisplayDate.replace(/mm/i,mm);
	    DisplayDate = DisplayDate.replace(/m/i,m);
	    DisplayDate = DisplayDate.replace(/dddd/i,dddd);
	    DisplayDate = DisplayDate.replace(/ddd/i,ddd);
	    DisplayDate = DisplayDate.replace(/dd/i,dd);
	    DisplayDate = DisplayDate.replace(/d/i,d);
	    DisplayDate = DisplayDate.replace(/yyyy/i,yyyy);
	    DisplayDate = DisplayDate.replace(/yy/i,yy);
	
	    return DisplayDate;
	},
	DecimalFormat: function(n){ 
		var r = n.toFixed(2);
		var bp = this._CommaForThousands(r.slice(0, r.indexOf('.') + 1));
		var ap = this.Right(r,2);
		r = bp + '.' + ap;
		return r;
	},
	DollarFormat: function(n) {
		var _n = n.toString().replace(/\$|\,/g,'');
		_n = _n.toString().replace('(','-');
		_n = _n.toString().replace(')','');
		if(isNaN(_n)){
			_n = 0;
		}
		var	sign = (_n == (_n = Math.abs(n)));
			_n = Math.floor(_n*100+0.50000000001);
		var	cents = _n%100;
			_n = Math.floor(_n/100).toString();		
		if(cents < 10){
			cents = "0" + cents;
		}
		_n = this._CommaForThousands(_n);
		return (((sign)?'':'(') + '$' + _n + '.' + cents + ((sign)?'':')'));
	},
	Find: function(sb,s){
		 return s.toString().indexOf(sb) + 1;
	},
	FindNoCase: function(sb,s){		
		return this.Find(sb.toUpperCase(),s.toUpperCase());
	},
	Insert: function(sb,s,p){
		return s.slice(0, p) + sb + s.slice(p, s.length);
	},
	IsArray: function(a){
		if(a.constructor == Array){
			return true;
		}
		return false;
	},
	IsBoolean: function(v){
		if(v.constructor == Boolean){
			return true;
		}
		return false;
	},
	IsDate: function(d){
		var datePat 	= /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
		var matchArray 	= d.toString().match(datePat);	
		if (matchArray === null) {
			return false;
		}	
		var month 	= matchArray[1];
		var day 	= matchArray[3];
		var year 	= matchArray[5];	
		if (month < 1 || month > 12) { 
			return false;
		}	
		if (day < 1 || day > 31) {
			return false;
		}	
		if ((month==4 || month==6 || month==9 || month==11) && day==31) {
			return false;
		}	
		if (month == 2) { 
			var isleap = (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0));
				if (day > 29 || (day==29 && !isleap)) {
					return false;
				}
		}
		return true; 
	},
	IsDefined: function(o){
		if(typeof o != "undefined"){
			return true;
		}
		return false;
	},
	IsNumeric: function(s){
		if (isNaN(s)){
			return false;
		} else {
			return true;
		}
	},
	IsStruct: function(s){
		
		if(s.constructor == Object){
			return true;
		}
		return false;
	},
	LCase: function(s){		
		return s.toLowerCase();			
	},
	Left: function(s,c){
		return s.slice(0, c);
	},	
	Len: function(s){		
		return s.length;
	},
	ListAppend: function(l, v, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		var r = ""; 
		if (this.ListLen(l)){
			r = l + d + v;
		} else {
			r = v;
		}
		return r;
	},
	ListChangeDelims: function(l, nd, od){
		l = l + ""; // cheap way to convert to a string
		if(!od){od = ",";}
		var spc = "^,$,|,.,+,*,?,\,/"
		if(this.ListFind(spc,od)){od="\\"+od;}
		var re = new RegExp(od,"gi");
		return l.replace(re,nd);
	},
	ListContains: function(l, sb, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d=",";}
		var spc = "^,$,|,.,+,*,?,\,/"
		if(this.ListFind(spc,sb)){sb="\\"+sb;}
		l = l.split(d);
		var re = new RegExp(sb,"g");
		for(var i=0; i<l.length;i++){
			if(re.test(l[i])){return i;}
		}
		return false;
	},
	ListContainsNoCase: function(l, sb, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d=",";}
		var spc = "^,$,|,.,+,*,?,\,/"
		if(this.ListFind(spc,sb)){sb="\\"+sb;}
		l = l.split(d);
		var re = new RegExp(sb,"gi");
		for(var i=0; i<l.length;i++){
			if(re.test(l[i])){return i;}
		}
		return false;
	},
	ListDeleteAt: function(l, p, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		var i,posInList;
		var posInArray = p - 1;
		var thisD 	= "";
		var r = ""; 
		for(i = 0; i < l.split(d).length; i++){
			if (i != posInArray){
				posInList = i + 1;
				if (r.length){
					thisD 	= d;
				}
				r += thisD + this.ListGetAt(l, posInList, d);
			}
		}
		return r;
	},
	ListFind: function (l,v,d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		var r = 0;
		var listToArray = l.split(d);
		for (var i=0; i < listToArray.length; i++){		
			if (listToArray[i] == v){
				r = i + 1;
				break;
			}
		}
		return r;
	},
	ListFindNoCase: function(l,v,d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		return this.ListFind(l.toUpperCase(), v.toUpperCase(), d);
	},
	ListFirst: function(l,d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		return l.split(d)[0];
	},
	ListGetAt: function (l, p, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		return l.split(d)[p - 1];
	},
	ListInsertAt: function(l, p, v, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d=",";}
		l = l.split(d);
		if(p==0){
			l.unshift(v);
		}
		else{
			var a = l.splice(p);
			l.push(v);
			l = l.concat(a);
		}
		return this.ListChangeDelims(l.toString(), d, ",");
	},
	ListLast: function(l,d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		// I don't know which of the two methods below would be preferable
		l = l.split(d);
		return l[l.length - 1];
		//return l.split(d)[l.split(d).length - 1];
	},
	ListLen: function(l,d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		if(l.length){return l.split(d).length;}
		return 0;
	},
	ListPrepend: function(l, v, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		var r = ""; 
		if (this.ListLen(l)){
			r = v + d + l;
		} else {
			r = v;
		}
		return r;
	},
	ListRest: function(l,d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d=",";}
		l = l.split(d);
		l.splice(0,1);
		l=(l.length)?this.ArrayToList(l,d):"";
		return l;
	},
	ListSetAt: function(l, p, v, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d=",";}
		l = l.split(d);
		l[p-1] = v;
		return this.ListChangeDelims(l.toString(), d, ",");
	},
	ListSort: function(l, st, so, d){
		l = l + ""; // cheap way to convert to a string
		if(!d){d=",";}
		l = l.split(d);
		l = this.ArraySort(l, st, so);
		return this.ListChangeDelims(l.toString(), d, ",");
	},
	ListToArray: function(l,d){		
		l = l + ""; // cheap way to convert to a string
		var r,a,i;			
		if(!d){d = ",";}		
		r = [];
		a = l.split(d);			
		for(i=1; i <= a.length; i++){
			r[i] = a[i - 1];
		}			
		return r;	
	},
	ListValueCount: function(l, v, d){
		var c = 0; // count
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		l = l.split(d);
		for(var i = 0; i < l.length; i++){
			if(l[i] == v){c++;}
		}		
		return c;
	},
	ListValueCountNoCase: function(l, v, d){
		var c = 0; // count
		l = l + ""; // cheap way to convert to a string
		if(!d){d = ",";}
		l = l.split(d);
		for(var i = 0; i < l.length; i++){
			if(l[i].toUpperCase() == v.toUpperCase()){c++;}
		}		
		return c;
	},
	LTrim: function(s){
		if(s.length){
			return s.toString().replace(/^\s*/, '');
		}
		else{
			return '';
		}
	},	
	Mid: function(s, start, c){
		start -= 1;
		return s.slice(start,start + c);
	},
	Replace: function(s,sb1,sb2,sc){
		if(!sc || sc.toUpperCase() != "ALL"){
			sc = "";
		} else {
			sc ="g";
		} 	
		var re = new RegExp(sb1,sc);
		return s.replace(re,sb2);
	},
	ReplaceNoCase: function(s,sb1,sb2,sc){
		if(!sc || sc.toUpperCase() != "ALL"){
			sc = "i";
		} else {
			sc ="gi";
		} 	
		var re = new RegExp(sb1,sc);
		return s.replace(re,sb2);
	},
	Reverse: function(s){
		var i = s.length;
		var r = "";	
		for (i; 0 <= i; i--){	
			r += s.charAt(i);	
		}	
		return r;
	},
	Right: function(s,c){
		return s.slice(s.length - c, s.length);
	},
	Round: function(n,p) {
		if (!isNaN(n.toFixed(p))){
			return n.toFixed(p);
		} else {
			return n;
		}
	},
	RTrim: function(s){
		if(s.length){
			return s.toString().replace(/\s*$/, '');
		}
		else{
			return '';
		}
	},
	StructKeyArray: function(s){
		var k;
		var a = [];
		for(k in s){
			a.push(k);
		}
		return a;
	},
	StructKeyExists: function(s,k){
		return !!s[k];
	},
	StructKeyList: function(s,d){
		var k;
		var a = "";
		if(arguments.length < 2){
			d = ",";
		}
		for(k in s){
			a = ListAppend(a, k, d);
		}
		return a;
	},
	TimeFormat: function(_time, _mask){
	    /********************************************************
		*	Valid Masks:
		*	h:	Hours;		no leading zero for single-digit hours (12-hour clock)
		*	hh:	Hours;		leading zero for single-digit hours (12-hour clock)
		*	H:	Hours;		no leading zero for single-digit hours (24-hour clock)
		*	HH:	Hours;		leading zero for single-digit hours (24-hour clock)
		*	m:	Minutes;	no leading zero for single-digit minutes
		*	mm:	Minutes;	a leading zero for single-digit minutes
		*	s:	Seconds;	no leading zero for single-digit seconds
		*	ss:	Seconds;	leading zero for single-digit seconds
		*
		*	t:	One-character lower-case time marker string, such as a or p
		*	tt:	Multiple-character lower-case time marker string, such as am or pm
		*	T:	One-character upper-case time marker string, such as A or P
		*	TT:	Multiple-character upper-case time marker string, such as AM or PM 
		*
		*	short:	equivalent to h:mm TT 
		*	medium:	equivalent to h:mm:ss TT 
		*	long:	medium followed by three-letter time zone; as in, 2:34:55 PM EST 
		*	full:	same as long
	   ********************************************************/
		
	    var intHour = _time.getHours();
	    var intMinute = _time.getMinutes();
	    var intSecond = _time.getSeconds();
		
		var ThisTwelveHourTime = intHour % 12;
		if(!ThisTwelveHourTime){
			ThisTwelveHourTime = ThisTwelveHourTime + 12;
		}
		
		var h = ThisTwelveHourTime + "";
		var hh = ThisTwelveHourTime < 10	? "0" + ThisTwelveHourTime		: ThisTwelveHourTime + "";
		var H = intHour + "";
		var HH = intHour < 10	? "0" + intHour		: intHour + "";
		var m = intMinute + "";
		var mm = intMinute < 10	? "0" + intMinute	: intMinute + "";
		var s = intSecond + "";
		var ss = intSecond < 10	? "0" + intSecond	: intSecond + "";
		var t = intHour < 12 ? "a" : "p";
		var tt = intHour < 12 ? "am" : "pm";
		var T = intHour < 12 ? "A" : "P";
		var TT = intHour < 12 ? "AM" : "PM";
		
		if(m.toLowerCase() == "short"){
			m = "h:mm TT";
		}
		else if(m.toLowerCase() == "medium"){
			m = "h:mm:ss TT";
		}
		else if(m.toLowerCase() == "long" || m.toLowerCase() == "full"){
			m = "h:mm:ss TT";
		}
		
	    DisplayTime = new String(_mask);
	
	    DisplayTime = DisplayTime.replace(/hh/i,	hh);
	    DisplayTime = DisplayTime.replace(/h/i,		h);
	    DisplayTime = DisplayTime.replace(/HH/i,	HH);
	    DisplayTime = DisplayTime.replace(/H/i,		H);
	    DisplayTime = DisplayTime.replace(/mm/i,	mm);
	    DisplayTime = DisplayTime.replace(/m/i,		m);
	    DisplayTime = DisplayTime.replace(/ss/i,	ss);
	    DisplayTime = DisplayTime.replace(/s/i,		s);
	    DisplayTime = DisplayTime.replace(/tt/i,	tt);
	    DisplayTime = DisplayTime.replace(/t/i,		t);
	    DisplayTime = DisplayTime.replace(/TT/i,	TT);
	    DisplayTime = DisplayTime.replace(/T/i,		T);
		
	    return DisplayTime;
	},
	Trim: function(s){
		if(s.length){
			return s.replace(/^\s*|\s*$/g,'');
		}
		else{
			return '';
		}
	},
	UCase: function(s){		
		return s.toUpperCase();			
	},
	URLDecode: function(s){
		return unescape(s);
	},	
	URLEncodedFormat: function(s){
		return encodeURI(s);
	}
});