
jQuery.htmlspecialchars = function(value) {
	return this('<div/>').text(value).html().replace('"', '&quot;').replace("'", '&apos;');
}

jQuery.cleanSpace = function(value) {
	return this.trim(value.replace(/\s+/, ' '));
}

jQuery.zeroPad = function(number, width) {
	if (width === undefined)
		width = 2;
	number += '';
	while (number.length < width)
		number = '0' + number;
	return number;
}
       
jQuery.fn.reverse = function() {
	return this.pushStack(this.get().reverse());
};

jQuery.fn.inputDisable = function(disable) {
	if (disable === undefined)
		disable = true;
	else
		disable = !!disable;
	return this.each(function () {
		if ($(this).is(':input, option'))
			this.disabled = disable;
	});
};

//log jQuery objects without breaking function chain e.g. $('#some-div').cLog().find('span').cLog().each(...);
jQuery.fn.cLog = function() {
	if (typeof console !== 'undefined' && console.log)
		console.log(this);
	return this;
};

jQuery.fn.hasAncestor = function(selector) {
	return this.filter(function() {
		return !!$(this).closest(selector).length;
	});
};

jQuery.fn.delay = function(time, callback){
    // Empty function:
    jQuery.fx.step.delay = function(){};
    // Return meaningless animation, (will be added to queue)
    return this.animate({delay:1}, time, callback);
}

function three_ajax(module, action, data, callback, error, noDataSubitem, sync) {
	var post;
	if (noDataSubitem)
		post = $.extend({}, data, {module: module, action: action});
	else
		post = {module: module, action: action, data: data};
	jQuery.ajax({
		type: 'POST',
		async: !sync,
		url: location.pathname.replace(/\badmin(\/.*)?$/, '') + '?/m/ajax',
		data: post,
		success: callback,
		error: error
	});
}

//can we delete this? only post works in core
function three_get(module, action, data, callback, error) {
	var get = {module: module, action: action, data:data};
	jQuery.ajax({
		url: location.pathname.replace(/\badmin(\/.*)?$/, '') + '?/m/ajax',
		data: get,
		success: callback,
		error: error
	});
}

//oDate1 gets modified!
jQuery.dateDiffCustom = function (oDate1, oDate2, resLow, resHigh) {
	var interval, temp, factor,
		intervals = {
			year: 0,
			month: 0,
			day: 0,
			hour: 0,
			minute: 0,
			second: 0,
			millisecond: 0
		};
	if (resLow) {
		if (!intervals.hasOwnProperty(resLow))
			return;
		for (interval in intervals)
			if (intervals.hasOwnProperty(interval)) {
				if (interval == resLow)
					break;
				delete intervals[interval];
			}
	}
	else
		resLow = 'year';
	if (resHigh) {
		if (!intervals.hasOwnProperty(resHigh))
			return;
		var found = false;
		for (interval in intervals)
			if (intervals.hasOwnProperty(interval)) {
				if (!found) {
					if (interval == resHigh)
						found = true;
					continue;
				}
				delete intervals[interval];
			}
	}
	else
		resHigh = 'millisecond';
	
	intervalLoop: for (interval in intervals)
		if (intervals.hasOwnProperty(interval))
			while (oDate1 < oDate2) {
				factor = 1;
				switch (interval) {
					case 'hour':
						factor *= 60;
					case 'minute':
						factor *= 60;
					case 'second':
						factor *= 1000;
						temp = oDate2 - oDate1;
						temp -= temp % factor;
						if (temp) {
							oDate1.setTime(oDate1.getTime() + temp);
							intervals[interval] = temp / factor;
						}
						continue intervalLoop;
					case 'millisecond':
						temp = oDate2 - oDate1;
						if (temp) {
							oDate1.setTime(oDate2.getTime());
							intervals[interval] = temp;
						}
						continue intervalLoop;
				}
				switch (interval) {
					case 'day':
						temp = [
							oDate1.getDate(),
							daysInMonth(oDate1.getMonth(), oDate1.getFullYear())
						];
						oDate1.setDate(temp[0] < temp[1] ? temp[0] + 1 : 1);
						if (temp[0] < temp[1])
							break;
					case 'month':
						temp = oDate1.getMonth();
						oDate1.setMonth((temp + 1) % 12);
						if (temp < 11)
							break;
					case 'year':
						oDate1.setFullYear(oDate1.getFullYear() + 1);
						break;
				}
				if (oDate1 > oDate2) {
					temp = {//have to alter largest first to prevent out of range errors
						_month: null,
						_day: null
					};
					switch (interval) {
						case 'day':
							temp._day = [
								oDate1.getDate(),
								daysInMonth((oDate1.getMonth() + 11) % 12, oDate1.getFullYear())
							];
							temp.day = temp._day[0] > 1 ? temp._day[0] - 1 : temp._day[1];
							if (temp._day[0] > 1)
								break;
						case 'month':
							temp._month = oDate1.getMonth();
							temp.month = (temp._month + 11) % 12;
							if (temp._month > 0)
								break;
						case 'year':
							oDate1.setFullYear(oDate1.getFullYear() - 1);
							break;
					}
					if (temp.hasOwnProperty('month'))
						oDate1.setMonth(temp.month);
					if (temp.hasOwnProperty('day'))
						oDate1.setDate(temp.day);
					break;
				}
				intervals[interval]++;
			}
	
	if (oDate1 < oDate2)//want lower resolution than Date object
		switch (resHigh) {
			case 'second':
				if (intervals.second < 59 || resLow == 'second') {
					intervals.second++;
					break;
				}
				intervals.second = 0;
			case 'minute':
				if (intervals.minute < 59 || resLow == 'minute') {
					intervals.minute++;
					break;
				}
				intervals.minute = 0;
			case 'hour':
				if (intervals.hour < 23 || resLow == 'hour') {
					intervals.hour++;
					break;
				}
				intervals.hour = 0;
			case 'day':
				//get days in prev month
				temp = (oDate2.getMonth() + 11) % 12;
				temp = daysInMonth(temp, oDate2.getFullYear());
				if (intervals.day < temp || resLow == 'day') {
					intervals.day++;
					break;
				}
				intervals.day = 0;
			case 'month':
				if (intervals.month < 12 || resLow == 'month') {
					intervals.month++;
					break;
				}
				intervals.month = 0;
			case 'year':
				intervals.year++;
		}
	return intervals;
}

Date.prototype.setUTCTime = function(UTCTimestamp) {
	var UTCDate = new Date(UTCTimestamp);
	this.setUTCFullYear(UTCDate.getFullYear(), UTCDate.getMonth(), UTCDate.getDate());
	this.setUTCHours(UTCDate.getHours(), UTCDate.getMinutes(), UTCDate.getSeconds(), UTCDate.getMilliseconds());
	return this.getTime();
}
function isLeapYear(year) {
	return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
function daysInMonth(month, yearOfFeb) {
	switch (month) {
		case 1:
			return 28 + isLeapYear(yearOfFeb);
			break;
		case 3:
		case 5:
		case 8:
		case 10:
			return 30;
			break;
		default:
			return 31;
	}
}

function isISODate(text) {
	return /^\d{4}-(1[0-2]|0[1-9])-(3[01]|[12]\d|0[1-9])$/.test(''+text) && !isNaN(Date.parse(text));
}

function parseTime(time) {
	var pm = /p/i.test(time), am = !pm && /a/i.test(time);//only explicit
	
	time = time.split(/\D+/);
	if (time.length && time[0] === '')
		time.shift();
	if (time.length && time[time.length - 1] === '')
		time.pop();
	if (time.length == 1) {
		if (time[0].length > 4)
			return '';
		if (time[0].length < 3)
			time = [time[0], 0];
		else
			time = [time[0].slice(0, -2), time[0].slice(-2)];
	}
	else if (time.length != 2)
		return '';
	var h = parseInt(time[0], 10), m = parseInt(time[1], 10);
	if (m > 60)
		m = '00';
	else
		m = $.zeroPad(m);
	if (pm) {
		if (h < 12 && h > 0)
			h += 12;
	}
	else if (am && h == 12)
		h = 0;
	h %= 24;
	return h + ':' + m;
}

