/* Object */

Object.prototype.toString = Array.prototype.toString = Object.prototype.ToString = Array.prototype.ToString = function() {
	var cont = [];
	for (var k in this) {
		if (cont.length) cont[cont.length-1] += ",";
		var v = this[k];
		var vs = '';
		if (typeof(v) != 'undefined') {
			if (v != null) {
				if (typeof(v.constructor) != 'undefined') {
					try{
					if (v.constructor == String) {
						s = v.split('\\').join('\\\\').split('"').join('\\"');
						vs = '"'+s + '"';
					} else {
						vs = v.toString();
					}
					}
					catch(err)
					{
					}
					switch (typeof(v)) {
						case 'function':
							n = vs.indexOf(')')+1;
							vs = vs.substr(0, n);
							break;
						default:
							break;
					}
					if (this.constructor == Array) {
						//if (typeof(v) != 'function') {
						if (!isNaN(parseInt(k))) {
							cont[cont.length] = k + ": " + vs;
						}
					} else {
						cont[cont.length] = k + ": " + vs;
					}
				} else {
					cont[cont.length] = k+' (undefined constructor)';
				}
			} else {
				cont[cont.length] = 'null';
			}
		} else {
			cont[cont.length] = 'undefined';
		}
	}
	// Здесь тоже нельзя делать replace()! 
	cont = "  " + cont.join("\n").split("\n").join("\n  ");
	var s = cont;
	if (this.constructor == Array) {
		s = "[\n"+cont+"\n]";
	} else {
		s = "{\n"+cont+"\n}";
	}
	return s;
}


/* Function */

Object.extend(Function.prototype, {

	// http://laurens.vd.oever.nl/weblog/items2005/closures/
	closure: function(obj) {
		// Init object storage.
		if (!window._objList) {
			window._objList = [];
			window._fnList = [];
		}
		// For symmetry and clarity.
		var fn = this;
		// Make sure the object has an id and is stored in the object store.
		var objId = obj._objId;
		if (!objId)
			_objList[objId = obj._objId = _objList.length] = obj;
		// Make sure the function has an id and is stored in the function store.
		var fnId = fn._fnId;
		if (!fnId)
			_fnList[fnId = fn._fnId = _fnList.length] = fn;
		// Init closure storage.
		if (!obj._closures)
			obj._closures = [];
		// See if we previously created a closure for this object/function pair.
		var closure = obj._closures[fnId];
		if (closure)
			return closure;
		// Clear references to keep them out of the closure scope.
		obj = null;
		fn = null;
		// Create the closure, store in cache and return result.
		return _objList[objId]._closures[fnId] = function () {
			return _fnList[fnId].apply(_objList[objId], arguments);
		};
	}
	/* Using
	function attach() {
		var element = document.getElementById("my-element");
		element.attachEvent("onclick", function()
			{
				alert("Clicked: " + this.innerHTML);
			}.closure(element));
	}
	*/

});



/* Array */

Object.extend(Array.prototype, {

	sortBubble: function() {
		var tmp;
		for (var i=0; i<this.length-1; i++) {
			for (var j=i; j<this.length; j++) {
				if (this[j] < this[i]) {
					tmp = this[j];
					this[j] = this[i];
					this[i] = tmp;
				}
			}
		}
		return this;
	},
	
	sortShell: function() {
		var c; // bool c;
		var e; // int e;
		var g; // int g;
		var i; // int i;
		var j; // int j;
		var tmp; // double tmp;
		var r = this;
		n = r.length;
		n--;
		g = Math.floor((n+1)/2);
		do {
			i = g;
			do {
				j = i-g;
				c = true;
				do {
					if (r[j] <= r[j+g]) {
						c = false;
					} else {
						tmp = r[j];
						r[j] = r[j+g];
						r[j+g] = tmp;
					}
					j = j-1;
				} while((j>=0) && (c));
				i = i+1;
				window.status = g;
			} while(i <= n);
			g = Math.floor(g/2);
		} while(g > 0);
		return r;
	},
	
	push: function (v) {
		var i = 0, b = this.length, a = arguments;
		for (i; i<a.length; i++) this[b+i] = a[i];
		return this.length; 
	},

	pop: function (t) {
		t = t || 'bottom';
		var i = (t == 'bottom') ? this.length-1 : 0;
		var r = this[i];
		this.splice(i, 1);
		return r;
	},

	splice: function(start, count) {
		for (var z=start; z<this.length-count; z++) {
			this[z] = this[z+count];
		}
		this.length = this.length - count;
	}

});


/* Number */

Object.extend(Number.prototype, {

	// http://xpoint.ru/forums/programming/javascript/misc/thread/33499.xhtml
	toFixed: function(e) {
		var y = Math.round(this*Math.pow(10,e))/Math.pow(10,e);
		var i = e-y.toString().length+y.toString().indexOf('.')+1;
		if(e > 0){
			if (y.toString().indexOf('.')<0) {
				return y+'.'+Math.pow(10,e).toString().substring(1);
			}
			else if (i>0) {
				return y+Math.pow(10,i).toString().substring(1);
			} else {
				return y;
			}
		} else {
			return y;
		}
	},
	/* Using
	(String*1).toFixed(e);
	Number.toFixed(e);
	*/

	toHex: function() {
		return this.toString(16).toUpperCase();
	},
	toBinary: function() {
		return this.toString(2).toUpperCase();
	},
	toOctal: function() {
		return this.toString(8).toUpperCase();
	}

});
