/*********** STRING ************/

String.prototype.ucfirst = function() {
	return this.substr(0, 1).toUpperCase() + this.substr(1);
};
String.prototype.excerpt = function(nLen) {
	return this.truncate(nLen-1, '\u2026');
};

String.prototype.trim = String.prototype.strip;


Date.now = function() {
	return (new Date()).getTime();
}

Element.GCScheduler = {
	cache: Prototype.getElementCache(),
	timer: null,
	batch: 50,
	batchDelay: 100,
	elements: [],
	eventsToClear: ['onclick', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'onkeydown', 'onkeypress'],

	scheduleToClear: function (elements) {
		if (!elements) return;
		if (!Object.isArray(elements)) {
			elements = [elements];
		}
		this.elements.push.apply(this.elements, elements);
		if (!this.timer) {
			this.timer = window.setInterval(Element.GCScheduler._gc, this.batchDelay);
		}
	},
	_gc: function () {
		var i, limit = Element.GCScheduler.batch,
			elements = Element.GCScheduler.elements,
			len = elements.length,
			_this = Element.GCScheduler;

		for (i=0; i<len && limit; i++, limit--) {
			_this.purge(elements[i]);
			elements[i] = null;
		}
		if (limit !== 0 || i === len) {
			_this.elements = [];
			window.clearInterval(_this.timer);
			_this.timer = null;
		} else {
			_this.elements.splice(0, _this.batch);
		}
	},
	purge: function (element) {

		if (!element) return;
		if (element._prototypeUID && this.cache[element._prototypeUID[0]]) {
			element.stopObserving();
			this.cache[element._prototypeUID[0]] = null;
			delete this.cache[element._prototypeUID[0]];
		}
		if (element.nodeName && element.nodeName.toUpperCase() == 'IMG') {
			element.src = 'about:blank';
		}
		var ev;

		for (var i=0, len=this.eventsToClear.length; i<len; i++ ) {
			try {
				ev = this.eventsToClear[i];
				element[ev] && (element[ev] = null);
			} catch (e) {
				return;
			}
		}
	}
};

Element.addMethods({
	update: Element.update.wrap(
		function (proceed, element, content) {
			var descendants = element.descendants();
			if (descendants.length > 0) { 
				Element.GCScheduler.scheduleToClear(descendants);
			}
			return proceed(element, content);
		}
	),
	replace: Element.replace.wrap(
		function (proceed, element, content) {
			Element.GCScheduler.scheduleToClear(element);
			return proceed(element, content);
		}
	)
});

Element.addMethods({
	getAbsoluteOffsets: function (element) {
		element = $(element);
		var offset = element.cumulativeOffset();
		var scrolls = {top:0, left:0};
		element.ancestors().each(function (el) {
			scrolls.top += el.scrollTop;
			scrolls.left += el.scrollLeft;
			if (el.style.position == 'fixed') {
				throw $break;
			}
		});
		offset[0] = offset.left = offset.left - scrolls.left; 
		offset[1] = offset.top = offset.top - scrolls.top;
		return offset;
	},
	getTrueZ: function (element) {
		return parseInt(element.ancestors().inject(0, function (acc, el) {
			return el.getStyle('z-index') || acc;
		}), 10);
	},
	getTrueVisibility: function (element) {
		return !element.ancestors().some(function (el) {
			return el.getStyle('visibility') == 'hidden' || el.getStyle('display') == 'none';
		});
	},
	setWidth: function(element, w){
		var borderRightWidth = parseInt(element.getStyle("border-right-width") || 0) || 0;
		var borderLeftWidth = parseInt(element.getStyle("border-left-width") || 0) || 0;
		var paddingRight = parseInt(element.getStyle("padding-right") || 0) || 0;
		var paddingLeft = parseInt(element.getStyle("padding-left") || 0) || 0;

		element.setStyle({'width': (w - borderRightWidth - borderLeftWidth - paddingRight - paddingLeft) + 'px'});
		return element;
	},
	setHeight: function(element, h){
		var borderTopWidth = parseInt(element.getStyle("border-top-width") || 0) || 0;
		var borderBottomWidth = parseInt(element.getStyle("border-bottom-width") || 0) || 0;
		var paddingTop = parseInt(element.getStyle("padding-top") || 0) || 0;
		var paddingBottom = parseInt(element.getStyle("padding-bottom") || 0) || 0;

		element.setStyle({'height': (h - borderTopWidth - borderBottomWidth - paddingTop - paddingBottom) + 'px'});
		return element;
	},
	isInDOMTree: function (element) {
		return [
			element.ownerDocument.documentElement, 
			element.ownerDocument, 
			element.ownerDocument.body
		].include(element.ancestors().last());
	}
});

/**
 *	Example:
 *
 *  Sample HTML Element: <span id='_buffer_1'></span>
 *
 *	Ajax.advancedUpdater({
 *		element: "_buffer_1",
 *		url: "google.com",
 *		frequency: 10,
 *		// optional parameters
 *		method: 'post',
 *		maxFrequency: 100,
 *		maxRequests: 200,
 *		decay: 1
 *	});
 */

Ajax.advancedUpdater = function(options){
	var element = $(options.element);
	var url = options.url;
	var frequency = options.frequency;

	var method = options.method || 'post';
	var maxFrequency = options.maxFrequency || Infinity;
	var maxRequests = options.maxRequests || Infinity;
	var decay = options.decay || 1;

	var counter = 0;
	var timer;

	var makeRequest = function(){
		return new Ajax.Request( url, {
			method: method,
			onSuccess: function(transport){
                try{
                    element.update(transport.responseText);
                } catch (e) {

                }
			}
		});
	};

	var updateFrequency = function(){
		frequency = frequency * decay;
		if(frequency > maxFrequency){
			frequency = maxFrequency;
		}
		return frequency;
	}

	var callFunction = function(){
		counter++;
		if(counter > maxRequests){
			clearTimeout(timer);
			return;
		}
		updateFrequency();
		makeRequest();
        timer = setTimeout(callFunction, frequency * 1000);
	}

	callFunction();

    return {
    	getTimer: function(){
        	return timer;
        },
        getCount: function(){
        	return count;	
        },
        getDecay: function(){
        	return decay;	
        }
    }
};


/************/
String.prototype.toXML = function () {
	if (window.DOMParser) {
	   var parser = new DOMParser();
	   var parsed = parser.parseFromString(this,"text/xml");
	   return parsed.firstChild || parsed;
	} else {
	   xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
	   xmlDoc.async = "false";
	   xmlDoc.loadXML(this);
	   return xmlDoc.firstChild || xmlDoc;
	}	
}

String.prototype.toXMLDoc = function () {
    if (window.DOMParser) {
       var parser = new DOMParser();
       var parsed = parser.parseFromString("<root>" + this + "</root>","text/xml");
       return parsed.firstChild || parsed;
    } else {
       xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
       xmlDoc.async = "false";
       xmlDoc.loadXML("<root>" + this + "</root>");
       return xmlDoc.firstChild || xmlDoc;
    }   
}
