//////////
// Adding additional methods to Global object
//

function isset(v) {
	return v !== undefined && v !== null;
}
function defined(v) {
	return v !== undefined;
}

function isArray(v) {
	return typeof v === 'array';
}

function isBool(v) {
	return typeof v === 'boolean';
}
isBoolean = isBool;

function isCallable(v) {
	return typeof v === 'function';
}
isFunction = isCallable;

function isNumber(v) {
	return typeof v === 'number';
}
isNumeric = isNumber;

function isFloat(v) {
	return typeof v === 'number' && (v - Math.round(v) != 0);
}
isDouble = isFloat;
isReal = isFloat;

function isInt(v) {
	return typeof v === 'number' && (v - Math.round(v) == 0);
}
isInteger = isInt;
isLong = isInt;

function isNull(v) {
	return v === null;
}

function isObject(v) {
	return typeof v === 'object';
}

function isScalar(v) {
	var t = typeof v;
	return t === 'string' || t === 'number' || t === 'boolean';
}

function isString(v) {
	return typeof v === 'string';
}

function empty(v) {
	var t = typeof v;
	if (t === 'string') {
		return v === '';
	} else if (t === 'number') {
		return v === 0;
	} else if (t === 'boolean') {
		return v === false;
	} else if (t === 'array') {
		return v === [];
	} else if (t === 'object') {
		return v === {};
	} else if (v === null || v === undefined) {
		return true;
	} else {
		return Boolean(v);
	}
}



//////////
// Adding additional methods to Math object
//

Math.hex = function (num, len) {
	if (! len) {
		len = 0;
	}
	var x = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
	var h = '';
	var v = num, s = v < 0, t;
	if (s) {
		v = Math.abs(v);
	}
	while (v > 0) {
		t = v % 16;
		v = Math.floor(v / 16);
		h = x[t] + h;
	}
	while (h.length < len) {
		h = '0' + h;
	}
	if (s) {
		h = '-' + h;
	}
	return h;
}



//////////
// Adding additional methods to String object
//

String.prototype.toInt = function () {
	var r = 0;
	for (var i = 0; i < this.length; i++) {
		var c = this.charAt(i);
		if (c < '0' || c > '9') {
			return r;
		}
		r = r * 10 + (c - '0');
	}
	return r;
}

String.prototype.toNumber = function () {
	return Number(this);
}

String.prototype.trim = function () {
	return this.replace(new RegExp('^\\s*([^\\s]*)\\s*$'), '$1');
}



//////////
// Adding additional methods to RegExp object
//

RegExp.quote = function (str) {
	// . \\ / + * ? [ ^ ] $ ( ) { } = ! < > | :
	return str.replace(new RegExp('([\\.\\+\\*\\?\\[\\]\\^\\$\\(\\)\\{\\}\\=\\!\\<\\>\\|\\:\\/\\\\])', 'g'), '\\$1');
}



/////////
// Adding additional methods to Array object
//

Array.prototype.inArray = function (value, strict) {
	for (var i = 0, n = this.length; i < n; i++) {
		if (strict ? (this[i] === value) : (this[i] == value)) {
			return true;
		}
	}
	return false;
}

Array.prototype.search = function (value, strict) {
	for (var i = 0, n = this.length; i < n; i++) {
		if (strict ? (this[i] === value) : (this[i] == value)) {
			return i;
		}
	}
	return false;
}



//////////
// Adding additional Date object
//

Date.prototype.isLeap = function () {
	var y = this.getFullYear();
	if (y % 4) {
		return false;
	}
	if (y % 100) {
		return true;
	}
	if (y % 400) {
		return false;
	}
	return true;
}

Date.__md = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

Date.prototype.daysPerMonth = function () {
	var y = this.getFullYear(), m = this.getMonth();
	var d = Date.__md[m];
	if (m == 1 && this.isLeap()) {
		d++;
	}
	return d;
}

Date.prototype.getWeek = function () {
	var m = this.getMonth(), d = 0;
	for (var i = 0; i < m; i++) {
		d += Date.__md[i];
		if (i == 1 && this.isLeap()) {
			d++;
		}
	}
	var dd = new Date(this.getFullYear(), 0, 1), wd = dd.getDay();
	if (! wd) {
		wd = 7;
	}
	wd -= 1; d += wd + 1;
	return Math.ceil(d / 7);
}

Date.prototype.toISOString = function (time) {
	if (isNaN(this)) return NaN;
	if (! isset(time)) time = true;
	var s = this.getFullYear(), t;
	
	t = this.getMonth() + 1;
	if (t < 10) {
		t = "0" + t;
	}
	s += "-" + t;
	
	t = this.getDate();
	if (t < 10) {
		t = "0" + t;
	}
	s += "-" + t;
	
	if (time) {
		t = this.getHours();
		if (t < 10) {
			t = "0" + t;
		}
		s += " " + t;
		
		t = this.getMinutes();
		if (t < 10) {
			t = "0" + t;
		}
		s += ":" + t;
		
		t = this.getSeconds();
		if (t < 10) {
			t = "0" + t;
		}
		s += ":" + t;
	}
	
	return s;
}



//////////
// Adding additional Time object
//

/**
 * Constructor
 */
function Time(time) {
	this.setTime(time);
}

/**
 * Sets time
 */
Time.prototype.setTime = function (time) {
	if (typeof time == 'string') {
		var a = time.split(new RegExp('[^\\d]+'), 3);
		this.timestamp = 0;
		this.timestamp += new Number(a.length > 0 ? a[0] : 0);
		this.timestamp *= 60;
		this.timestamp += new Number(a.length > 1 ? a[1] : 0);
		this.timestamp *= 60;
		this.timestamp += new Number(a.length > 2 ? a[2] : 0);
	} else if (typeof time == 'number') {
		this.timestamp = 0 + new Number(time);
	} else if (time instanceof Time) {
		this.timestamp = time.timestamp;
	} else {
		this.timestamp = NaN;
	}
}

/**
 * Returns time
 */
Time.prototype.getTime = function () {
	return this.timestamp;
}

/**
 * Compares time agains given time
 */
Time.prototype.compareTo = function (time) {
	if (! time instanceof Time) return NaN;
	return this.timestamp > time.timestamp ? 1 :
		this.timestamp < time.timestamp ? -1 :
		this.timestamp == time.timestamp ? 0 : NaN;
}

/**
 * Returns time representaton
 */
Time.prototype.toString = function (short) {
	if (isNaN(this.timestamp)) return NaN;
	var t = this.timestamp, d = t % 60, s = '' + d;
	if (d < 10) s = '0' + s;
	s = short ? '' : ':' + s;
	t = (t - d) / 60; d = t % 60; s = '' + d + s;
	if (d < 10) s = '0' + s;
	t = (t - d) / 60; s = '' + t + ':' + s;
	return s;
}

Time.prototype.add = function (time) {
	if (time instanceof Time) {
		if (isNaN(this.timestamp) || isNaN(time.timestamp)) {
			this.timestamp = NaN;
		} else {
			this.timestamp += time.timestamp;
		}
	}
}

Time.prototype.subtract = function (time) {
	if (time instanceof Time) {
		if (isNaN(this.timestamp) || isNaN(time.timestamp)) {
			this.timestamp = NaN;
		} else {
			this.timestamp -= time.timestamp;
			// Can't hold negative timestamps
			if (this.timestamp < 0) {
				this.timestamp = NaN;
			}
		}
	}
}

