/* purpose: returns TRUE if string s is empty, otherwise FALSE.
 * parameter: s - string
 * return - boolean
 */
(function($){
	$.isEmpty = function(s) { return ((s == null) || (s.length == 0)); }
})(jQuery);

/* purpose: returns TRUE if string s is empty or whitespace characters only, otherwise FALSE.
 * parameter: s - string
 * return - boolean
 */
(function($){
	$.isWhitespace = function(s) { var regexpWhitespace = /^\s+$/; return ($.isEmpty(s) || regexpWhitespace.test(s)); }
})(jQuery);

/* purpose: returns true if string s contains only alphabets.
 * parameter: s - string
 * return - boolean
 */
(function($){
	$.isAlphabet = function(s) { var regexpAlphabet = /^[a-zA-Z]+$/; return (!$.isWhitespace(s) && regexpAlphabet.test(s)); }
})(jQuery);

/* purpose: returns true if string s contains only alphanumeric.
 * parameter: s - string
 * return - boolean
 */
(function($){
	$.isAlphanumeric = function(s) { var regexpAlphanumeric = /^[a-zA-Z0-9]+$/; return (!$.isWhitespace(s) && regexpAlphanumeric.test(s)); }
})(jQuery);

/* purpose: returns true if string s contains only numbers.
 * parameter: s - string
 * return - boolean
 */
(function($){
	//$.isNumeric = function(s) { var regexpNumeric = /-*^[0-9]+$/; return (!$.isWhitespace(s) && regexpNumeric.test(s)); }
	$.isNumeric = function(s) { return (!$.isWhitespace(s) && !isNaN(s*1) && isFinite(s)); }
})(jQuery);

/* purpose: returns true if string s contains valid email address.
 * parameter: s - string
 * return - boolean
 */
(function($){
	$.isEmail = function(s) { var regexpEmail = /^.+\@.+\..+$/; return (!$.isWhitespace(s) && regexpEmail.test(s)); }
})(jQuery);

/* purpose: returns true if string s is equal or exceeded minimum length.
 * parameter: s - string
 * parameter: l - minimum length
 * return - boolean
 */
(function($){
	$.metMinimumLength = function(s,l) { return (!$.isWhitespace(s) && s.length >= (l*1) ); }
})(jQuery);

/* purpose: returns true if numbers are in range
 * parameter: a - minimum number to compare
 * parameter: b - maximum number to compare
 * return - boolean
 */
(function($){
	$.inRange = function(a,b) {
		a = (!isNaN(a))?parseFloat(a):a; b = (!isNaN(b))?parseFloat(b):b;
		return ( a > b )?false:true;
	}
})(jQuery);

/* purpose: returns true if string s is postive percentage range between 0 to 100
 * parameter: s - string
 * return - boolean
 */
(function($){
	$.isPercentage = function(s) { a = (!isNaN(s))?parseFloat(s):s; return (!$.isWhitespace(s) && (!isNaN(s) && s >= 0 && s <= 100)); }
})(jQuery);

/* purpose: returns random generated password with specify length, default at 6
 * parameter: s - password length
 * return - string
 */
(function($){
	$.randomPassword = function(s) { 
		var c = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", p = "";
		var l = (s)?s:6;
		for(var x=0;x<l;x++) {
			var i = Math.floor(Math.random() * 62);
			p += c.charAt(i);
		}
		return p;
	}
})(jQuery);

/* purpose: validate form input and select tags, return false if validation fails
 * parameter: f - form selector
 * parameter: e - array of error messages {required,minlength,minvalue,maxvalue,alphabet,alphanumeric,email,percentage}
 * return - boolean
 */
(function($){
	$.validateForm = function(f,e) { 
		if( !f ) return false;
		var v = true; //return flag
		var m = { //default error messages
			required:"field required.",
			minlength:"minimum length not met, required ",
			minvalue:"minimum value not met.",
			maxvalue:"exceeded maximum value.",
			alphabet:"only alphabet are acceptable.",
			numeric:"only numbers are acceptable.",
			alphanumeric:"only alphanumeric is acceptable.",
			email:"email address not valid.",
			percentage:"only between 0% - 100% is acceptable.",
			invaliddate:"date or format is incorrect."
		};
		if( e ) {
			m.required = ( e.required ) ? e.required : m.required; //override default required error msg
			m.minlength = ( e.minlength ) ? e.minlength : m.minlength; //override default minlength error msg
			m.alphabet = ( e.alphabet ) ? e.alphabet : m.alphabet; //override default alphabet error msg
			m.numeric = ( e.numeric ) ? e.numeric : m.numeric; //override default numeric error msg
			m.alphanumeric = ( e.alphanumeric ) ? e.alphanumeric : m.alphanumeric; //override default alphanumeric error msg
			m.email = ( e.email ) ? e.email : m.email; //override default email error msg
			m.percentage = ( e.percentage ) ? e.percentage : m.percentage; //override default percentage error msg
			m.invaliddate = ( e.invaliddate ) ? e.invaliddate : m.invaliddate; //override default invalid date error msg
		}
		$(f+" input").each( function() { //validate input tag
			if( $(this).attr("type") == "text" || $(this).attr("type") == "password" ) { //if input type is text or password
				if( $(this).attr("required") && $.isWhitespace( $(this).val() ) ) { //validate required
					v = false; $(this).ErrorTooltip("add",m.required);
				} else if( $(this).attr("minlength") && !$.isWhitespace( $(this).attr("minlength") ) && !$.metMinimumLength( $(this).val(), ($(this).attr("minlength")*1) ) ) { //validate minimum length required
					v = false; $(this).ErrorTooltip("add",m.minlength+$(this).attr("minlength"));
				} else if( $(this).attr("minvalue") && !$.isWhitespace( $(this).attr("minvalue") ) && $(this).val()*1 < ($(this).attr("minvalue")*1) ) { //validate minimum length required
					v = false; $(this).ErrorTooltip("add",m.minvalue);
				} else if( $(this).attr("maxvalue") && !$.isWhitespace( $(this).attr("maxvalue") ) && $(this).val()*1 > ($(this).attr("maxvalue")*1) ) { //validate minimum length required
					v = false; $(this).ErrorTooltip("add",m.maxvalue);
				} else if( $(this).attr("validate") && $(this).attr("validate") == "alphabet" && !$.isAlphabet( $(this).val() ) ) { //validate only contains alphabets
					v = false; $(this).ErrorTooltip("add",m.alphabet);
				} else if( $(this).attr("validate") && $(this).attr("validate") == "numeric" && !$.isNumeric( $(this).val() ) ) { //validate only contains numbers
					v = false; $(this).ErrorTooltip("add",m.numeric);
				} else if( $(this).attr("validate") && $(this).attr("validate") == "alphanumeric" && !$.isAlphanumeric( $(this).val() ) ) { //validate only contains alphanumerics
					v = false; $(this).ErrorTooltip("add",m.alphanumeric);
				} else if( $(this).attr("validate") && $(this).attr("validate") == "email" && !$.isEmail( $(this).val() ) ) { //validate only contains valid email address
					v = false; $(this).ErrorTooltip("add",m.email);
				} else if( $(this).attr("validate") && $(this).attr("validate") == "percentage" && !$.isPercentage( $(this).val() ) ) { //validate only contains valid percentage
					v = false; $(this).ErrorTooltip("add",m.percentage);
				} else if( $(this).attr("validate") && $(this).attr("validate") == "date" && !$.isDateValid( $(this).val(),$(this).attr("separator") ) ) { //validate only contains valid date
					v = false; $(this).ErrorTooltip("add",m.invaliddate);
				}
			}
		});
		$(f+" select").each( function() { //validate select tag
			if( $(this).attr("required") && $.isWhitespace( $(this).val() ) ) { //validate required
				v = false; $(this).ErrorTooltip("add",m.required);
			}
		});
		
		return v;
	}
})(jQuery);

/* purpose: append a error tooltip beside the targeted element.
 * parameter: a - mode, add, remove, show, hide
 * parameter: m - error message to be shown on the tooltip
 */
(function($){
	$.fn.ErrorTooltip = function(a,m) { 
		if(!a) return;
		if(a=="add") {
			m = (m)?m:"";
			$(this).after("<span class=\"tooltip-error\"><span class=\"ui-icon ui-icon-alert text\"></span><em></em><span>"+m+"</span></span>");
			var l = -$(this).width()-22, t = -(($(this).next(".tooltip-error").height()/15))-$(this).height();
			$(this).next(".tooltip-error").css("margin-left",l).css("margin-top",t);
		} else if(a=="remove") {
			$(this).next(".tooltip-error").remove();
		} else if(a=="show") {
			$(this).next(".tooltip-error").show();
		} else if(a=="hide") {
			$(this).next(".tooltip-error").hide();
		}
	}
})(jQuery);

/* purpose: append a help tooltip on img element.
 */
(function($){
	$.fn.HelpTooltip = function() {
		var i,m;
		$(this).each( function() {
			i = $(this).attr("tooltip")*1;
			m = $(this).attr("tooltiptext");
			if( !isNaN(i) ) {
				$(this).after( "<span class=\"tooltip-help tooltip-help-position\" tooltip=\""+i+"\"><span class=\"tooltip-help-icon text\">&nbsp;&nbsp;</span>"+m+"</span>" );
				$(this).removeAttr("tooltiptext"); //clear original contents
				$(this).hover( function(e) {
					$(this).next().show("fade").css("display","inline");
				}, function(e) {
					$(this).next().hide("fade");
				});
			}
		})
	}
})(jQuery);


/* purpose: checks if is leap year
 * parameter: y - year
 * return - boolean
 */
(function($){
	$.isLeapYear = function(y) {
		y = (!isNaN(y))?parseInt(y,10):y;
		if(y%4==0) {
			if(y%100==0) {
				if(y%400==0) return true;
				else return false;
			} else return true;
		}
		return false;
	}
})(jQuery);
 
/* purpose: checks if month is 30 days
 * parameter: m - month
 * return - boolean
 */
(function($){
	$.isMonth30 = function(m) {
		m = (!isNaN(m))?parseInt(m,10):m;
		return(m == 4 || m == 6 || m == 9 || m == 11);
	}
})(jQuery);

/* purpose: checks if year, month, day is within valid date range
 * parameter: y - year
 * parameter: m - month
 * parameter: d - day
 * return - boolean
 */
(function($){
	$.isValidDateRange = function(y,m,d) {
		y = (!isNaN(y))?parseInt(y,10):y;
		m = (!isNaN(m))?parseInt(m,10):m;
		d = (!isNaN(d))?parseInt(d,10):d;
		if($.isLeapYear(y) && m == 2) return (d >= 1 && d <= 29);
		if(!$.isLeapYear(y) && m == 2) return (d >= 1 && d <= 28);
		if($.isMonth30(m)) return (d >= 1 && d <= 30);
		return (d >= 1 && d <= 31);
	}
})(jQuery);

/* purpose: checks if date passed is in valid yyyy-mm-dd format
 * parameter: d - date string, example:"YYYY-MM-DD"
 * parameter: s - date separator, example: "-"
 */
(function($){
	$.isDateValid = function(d,s) {
		return ( d.length == 10 && (d.substring(4,5) == s && d.substring(7,8) == s) && ($.isValidDateRange(d.substring(0,4),d.substring(5,7),d.substring(8,10))) );
	}
})(jQuery);

/* purpose: set visibility to visible
 */
(function($){
	$.fn.visibleOn = function() {
		$(this).css("visibility","visible");
	}
})(jQuery);

/* purpose: set visibility to hidden
 */
(function($){
	$.fn.visibleOff = function() {
		$(this).css("visibility","hidden");
	}
})(jQuery);

/* purpose: get today's date in yyyy-mm-dd format
 */
(function($){
	$.today = function(t1,t2) {
		var d = new Date();
		if( t1 ) $(t1).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		if( t2 ) $(t2).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		return d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate());
	}
})(jQuery);

/* purpose: get yesterday's date in yyyy-mm-dd format
 */
(function($){
	$.yesterday = function(t1,t2) {
		var d = new Date(); d.setDate( d.getDate()-1 );
		if( t1 ) $(t1).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		if( t2 ) $(t2).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		return d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate());
	}
})(jQuery);

/* purpose: get current week's date in yyyy-mm-dd format
 */
(function($){
	$.currentWeek = function(t1,t2) {
		var d = new Date(); d.setDate( d.getDate()-(((d.getDay()==0)?7:d.getDay())-1) );
		if( t1 ) $(t1).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		if( t2 ) $(t2).val( $.today() );
		return d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate());
	}
})(jQuery);

/* purpose: get last week's date in yyyy-mm-dd format
 */
(function($){
	$.lastWeek = function(t1,t2) {
		var d = new Date(); d.setDate(d.getDate()-(((d.getDay()==0)?7:d.getDay())-1)-7);
		if( t1 ) $(t1).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		d.setDate(d.getDate()+6);
		if( t2 ) $(t2).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()));
		return d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate());
	}
})(jQuery);

/* purpose: get current month's date in yyyy-mm-dd format
 */
(function($){
	$.currentMonth = function(t1,t2) {
		var d = new Date(); d.setDate(1);
		if( t1 ) $(t1).val( d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate()) );
		if( t2 ) $(t2).val($.today());
		return d.getFullYear()+"-"+(d.getMonth()+1<10?"0"+(d.getMonth()+1):d.getMonth()+1)+"-"+(d.getDate()<10?"0"+d.getDate():d.getDate());
	}
})(jQuery);

/* purpose: get last month's date in yyyy-mm-dd format
 */
(function($){
	$.lastMonth = function(t1,t2) {
		var d = new Date(); var dd = new Date(d.getFullYear(),d.getMonth()-1,1);
		if( t1 ) $(t1).val( dd.getFullYear()+"-"+(dd.getMonth()+1<10?"0"+(dd.getMonth()+1):dd.getMonth()+1)+"-"+(dd.getDate()<10?"0"+dd.getDate():dd.getDate()) );
		if( t2 ) $(t2).val( dd.getFullYear()+"-"+(dd.getMonth()+1<10?"0"+(dd.getMonth()+1):dd.getMonth()+1)+"-"+$.daysInMonth((dd.getMonth()+1),dd.getFullYear()) );
		return dd.getFullYear()+"-"+(dd.getMonth()+1<10?"0"+(dd.getMonth()+1):dd.getMonth()+1)+"-"+(dd.getDate()<10?"0"+dd.getDate():dd.getDate());
	}
})(jQuery);

/* purpose: get number of days in a month
 */
(function($){
	$.daysInMonth = function(m,y) {
		var mm = [31,28,31,30,31,30,31,31,30,31,30,31];
		if(m != 2) return mm[m - 1];
		if(y%4 != 0) return mm[1];
		if(y%100 == 0 && y%400 != 0) return mm[1];
		return mm[1] + 1;
	}
})(jQuery);

/* purpose: control result panel.
 * parameter: a - different actions, show, hide, error, success, load, info
 * parameter: b - message to be shown on error, success, load and info action
 */
(function($){
	$.resultpanel = function(p,a,b) {
		p = (p.length==0)?p:"-"+p;
		if( $("#result-panel"+p) && a ) {
			if( a=="show" ) {
				$("#result-panel"+p).show();
			} else if( a=="hide" ) {
				$("#result-panel"+p).hide();
			} else if( a=="success" ) {
				$("#result-panel"+p).attr("class","result-panel ui-state-highlight ui-corner-all");
				$("#result-icon"+p).attr("class","result-icon ui-icon ui-icon-circle-check span-text");
				$("#result"+p).text(b);
			} else if( a=="error" ) {
				$("#result-panel"+p).attr("class","result-panel ui-state-error ui-corner-all");
				$("#result-icon"+p).attr("class","result-icon ui-icon ui-icon-circle-close span-text");
				$("#result"+p).text(b);
			} else if( a=="load" ) {
				$("#result-panel"+p).attr("class","result-panel ui-corner-all");
				$("#result-icon"+p).attr("class","result-icon progress-icon");
				$("#result").text(b);
			} else if( a=="info" ) {
				$("#result-panel"+p).attr("class","result-panel ui-corner-all");
				$("#result-icon"+p).attr("class","result-icon ui-icon ui-icon-lightbulb span-text");
				$("#result"+p).text(b);
			}
		}
	}
})(jQuery);

/* purpose: blink element
 * paremter: d - element selector
 * parameter: b - true to start, false to stop
 * parameter: t - time in seconds to auto stop blinking (1s=1000)
 */
var blinktimer;
(function($){
	$.blink = function(d,b,t) {
		clearInterval(blinktimer);
		$(d).css("opacity", "1.0");
		if(b) {
			blinktimer = window.setInterval(function(){
				$(d).animate({opacity: 0.1}, "slow");
				window.setTimeout(function(){
					$(d).animate({opacity: 1.0}, "slow");
				}, 1000);
			}, 1000);
			if(t) window.setTimeout(function(){clearInterval(blinktimer);$(d).css("opacity","1.0");}, t);
		}
	}
})(jQuery);

/* purpose: format numbers
 * paremter: number - number to be formatted
 * parameter: params - parameters passed in, see sdefaults
 */
(function($){
	$.numberFormat = function(number, params) {
		var sdefaults = {			
			numberOfDecimals: 2,
			decimalSeparator: ",",
			thousandSeparator: ".",
			symbol: ""
		};
 		var options = $.extend(sdefaults, params);
		var decimals = options.numberOfDecimals;
		var dec_point = options.decimalSeparator;
		var thousands_sep = options.thousandSeparator;
		
		var exponent = "";
		var eindex = number.toString().indexOf ("e");
		if(eindex > -1) {
			exponent = numberstr.substring(eindex);
			number = parseFloat(number.toString().substring(0,eindex));
		}
		if(decimals != null) {
			var temp = Math.pow(10, decimals);
			number = Math.round(number * temp) / temp;
		}
		var sign = (number < 0) ? "-" : "";
		var integer = (number > 0) ? Math.floor(number).toString() : Math.abs(Math.ceil(number)).toString();
		var fractional = number.toString().substring(integer.length + sign.length);
		dec_point = (dec_point != null) ? dec_point : ".";
		fractional = (decimals != null && decimals > 0 || fractional.length > 1) ? (dec_point + fractional.substring(1)) : "";
		if(decimals != null && decimals > 0) {
			for(var i = fractional.length - 1, z = decimals; i < z; ++i) fractional += "0";
		}
		thousands_sep = (thousands_sep != dec_point || fractional.length == 0) ? thousands_sep : null;
		if(thousands_sep != null && thousands_sep != "") {
			for (var i = integer.length - 3; i > 0; i -= 3) integer = integer.substring(0,i) + thousands_sep + integer.substring(i);
		}
		if(options.symbol == "") {
			return sign + integer + fractional + exponent;
		} else {
			return options.symbol + " " + sign + integer + fractional + exponent;
		}
	}
})(jQuery);

/* purpose: queue ajax request
 */
var ajaxQueue = $({});
(function($){
	$.ajaxQueue = function(ajaxOpts) {
		// hold the original complete function
		var oldComplete = ajaxOpts.complete;
		// queue our ajax request
		ajaxQueue.queue(function(next) {
			// create a complete callback to fire the next event in the queue
			ajaxOpts.complete = function() {
				// fire the original complete if it was there
				if (oldComplete) oldComplete.apply(this, arguments);
	        	next(); // run the next query in the queue
	    	}
		// run the query
		$.ajax(ajaxOpts);
    	});
	}
})(jQuery);

/* purpose: clear ajax queue
 */
(function($){
	$.clearAjaxQueue = function() {
		ajaxQueue.clearQueue();
	}
})(jQuery);

/* scroll events
 */
(function(){    
    var special = jQuery.event.special,
        uid1 = 'D' + (+new Date()),
        uid2 = 'D' + (+new Date() + 1);
    special.scrollstart = {
        setup: function() {
            var timer,
                handler =  function(evt) {
                    var _self = this,
                        _args = arguments;
                    if (timer) {
                        clearTimeout(timer);
                    } else {
                        evt.type = 'scrollstart';
                        jQuery.event.handle.apply(_self, _args);
                    }
                    timer = setTimeout( function(){
                        timer = null;
                    }, special.scrollstop.latency);
                };
            jQuery(this).bind('scroll', handler).data(uid1, handler);
        },
        teardown: function(){
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
        }
    };
    special.scrollstop = {
        latency: 300,
        setup: function() {
            var timer,
                    handler = function(evt) {
                    var _self = this,
                        _args = arguments;
                    if (timer) {
                        clearTimeout(timer);
                    }
                    timer = setTimeout( function(){
                        timer = null;
                        evt.type = 'scrollstop';
                        jQuery.event.handle.apply(_self, _args);
                    }, special.scrollstop.latency);
                };
            jQuery(this).bind('scroll', handler).data(uid2, handler);
        },
        teardown: function() {
            jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
        }
    };
})();
