
/****************************************************************************
//	SECTION::Shortcuts
*/

window[Browser.Engine.name] = window[Browser.Engine.name + Browser.Engine.version] = true;

window.ie = window.trident;
window.ie6 = window.trident4;
window.ie7 = window.trident5;

var $E = function(selector, filter){
	return ($(filter) || document).getElement(selector);
};

var $ES = function(selector, filter){
	return ($(filter) || document).getElements(selector);
};


Element.implement({

	getText: function(){
		return this.get('text');
	},

	setText: function(text){
		return this.set('text', text);
	},

	setHTML: function(){
		return this.set('html', arguments);
	},
	
	getHTML: function(){
		return this.get('html');
	},

	getTag: function(){
		return this.get('tag');
	},
	
	highlight: function(start, end){
		if (!end){
			end = this.retrieve('highlight:original', this.getStyle('background-color'));
			end = (end == 'transparent') ? '#fff' : end;
		}
		
		var newDiv = new Element('div');
		newDiv.setStyle('position', 'absolute');
		$(document.body).adopt(newDiv);
		var position = this.getPosition()
		var size = this.getSize();
		newDiv.setStyles({
			left:		position.x,
			top:		position.y,
			width:		size.x,
			height: 	size.y,
			opacity:	.7,
			'background-color' : (start || '#ffff88')});
		
		newDiv.setStyle('z-index', 10000000);  // fixes unseen in IE when this.position=fixed
		
		var tween = new Fx.Tween(newDiv, {transition: 'Circ', duration: 500 });
		tween.start('opacity', .7, 0).chain(function(){
			newDiv.dispose();
			tween.callChain();
			tween = null;
		}.bind(this));
		return this;
	},

	getFormElements: function(){
		return this.getElements('input, textarea, select');
	}

});



Element.implement({

	replaceWith: function(el){
		el = $(el);
		this.parentNode.replaceChild(el, this);
		return el;
	},
	
	removeElements: function(){
		return this.dispose();
	}

});




String.implement({

	endsWith: function(theEnding) {
		if(theEnding.length > this.length) return false;
		return this.substring(this.length - theEnding.length) == theEnding;
	},
	
	trimTrailing: function(suffix) {
		return this.endsWith(suffix) ? this.substring(0, this.length-suffix.length) : this.toString();
	}
});

/*
//	End SECTION::Shortcuts
****************************************************************************/



/****************************************************************************
//	SECTION::AJAX Script Handling
	
	Let's make the execution of scripts delay a little as a general rule:
*/
	
Request.implement({
	
	processScripts: function(text){
	//	dbug.log('lag version processing of scripts!');
		
		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
		
		var scriptText = '';
		var scriptFreeText = text.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
			scriptText += arguments[1] + '\n';
			return '';
		});
		
		if(this.options.evalScripts)
			$exec.delay(this.options.scriptDelay || 50, null, scriptText);
		
		return scriptFreeText;
	}

});
/*
//	End SECTION::AJAX Script Handling
****************************************************************************/



/****************************************************************************
//	SECTION::Ajax eval scripts onFailure
*/
Request.HTML = Class.refactor(Request.HTML, { 
    options: { 
        onFailure: function() {
        	hideLoad();
			this.xhr.responseText.stripScripts(true); // eval what we got as if script
		}
    } 
});
/*
//	End SECTION::Ajax eval scripts onFailure
****************************************************************************/




/****************************************************************************
//	SECTION::OuterClick Event
*/
(function() {
	var events;
	var check = function(e) {
		var target = $(e.target);
		var parents = target.getParents();
		events.each(function(item) {
			var element = item.element;
			if(element != target  &&  !parents.contains(element))
				item.fn.call(element, e);
		});
	};
	Element.Events.outerClick = {
		onAdd: function(fn) {
			if(!events) {
				document.addEvent('click', check);
				events = [];
			}
			events.push({element: this, fn: fn});
		},
		onRemove: function(fn) {
			events = events.filter(function(item) {
				return item.element != this  ||  item.fn != fn;
			}, this);
			if(!events.length) {
				document.removeEvent('click', check);
				events = null;
			}
		}
	};
})();

/*
//	End SECTION::OuterClick Event
****************************************************************************/

	
/****************************************************************************
//	SECTION::Number Formatting
*/
Number.implement({

	/*
	Property: numberFormat
		Format a number with grouped thousands.

	Arguments:
		decimals, optional - integer, number of decimal percision; default, 2
		dec_point, optional - string, decimal point notation; default, '.'
		thousands_sep, optional - string, grouped thousands notation; default, ','

	Returns:
		a formatted version of number.

	Example:
		>(36432.556).numberFormat()  // returns 36,432.56
		>(36432.556).numberFormat(2, '.', ',')  // returns 36,432.56
	*/

	XXnumberFormat : function(decimals, dec_point, thousands_sep) {
		decimals = Math.abs(decimals) + 1 ? decimals : 2;
		dec_point = dec_point || '.';
		thousands_sep = thousands_sep || ',';
	
		var matches = /(-)?(\d+)(\.\d+)?/.exec((isNaN(this) ? 0 : this) + ''); // returns matches[1] as sign, matches[2] as numbers and matches[3] as decimals
		var remainder = matches[2].length > 3 ? matches[2].length % 3 : 0;
		return (matches[1] ? matches[1] : '') + (remainder ? matches[2].substr(0, remainder) + thousands_sep : '') + matches[2].substr(remainder).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep) + 
				(decimals ? dec_point + (+matches[3] || 0).toFixed(decimals).substr(2) : '');
	}

/*
//	End SECTION::Number Formatting
****************************************************************************/
});




/****************************************************************************
//	SECTION::Element Effect Shortcuts
*/
Element.implement({
	appear: function() {
		var currentOpacity = this.getStyle('opacity');
		var currentDisplay = this.getStyle('display');
		var currentVisibility= this.getStyle('visibility');
		
		if(currentOpacity == 1  && 
		   currentDisplay != 'none'  &&
		   currentVisibility == 'visible')
			return; // is already appeared!
		
		if(currentDisplay == 'none'  ||  currentVisibility == 'hidden') {
			this.setStyle('opacity', 0);
			currentOpacity = 0;
			this.setStyle('display', $pick(this.originalDisplay, this.tagName.toLowerCase()=='span' ? 'inline' : 'block'));
			this.setStyle('visibility', 'visible');
		}
		
		// Now we're ready to show:
		this.tween('opacity', currentOpacity, 1);
	},
	
	
	fadeX: function() {
		var currentOpacity = this.getStyle('opacity');
		var currentDisplay = this.getStyle('display');
		var currentVisibility= this.getStyle('visibility');
		dbug.nog('fade', currentOpacity, currentDisplay, currentVisibility);
		this.originalDisplay = currentDisplay; // save to preserve on re-appear!
		if(currentOpacity == 0  || 
		   currentDisplay == 'none'  ||
		   currentVisibility == 'hidden')
			return; // is already invisible!
		
		// Now we're ready to fade:
		this.tween('opacity', currentOpacity, 0);
	},
	
	
	evaporate: function() {
		this.fade('out');
		this.store('slide:options', {duration: 1000 });
		this.slide();
		this.getParent().dispose.delay(1000, this.getParent());  // slide makes a wrapper
	}

});
/*
//	End SECTION::Element Effect Shortcuts
****************************************************************************/




/****************************************************************************
//	SECTION::Element Spatial Computation Shortcuts
*/
Element.implement({
	getNonContentHeight: function() {
		return 0 +
			parseInt(this.getStyle('border-top-width')) +
			parseInt(this.getStyle('border-bottom-width')) +
			parseInt(this.getStyle('margin-top')) +
			parseInt(this.getStyle('margin-bottom')) +
			parseInt(this.getStyle('padding-top')) +
			parseInt(this.getStyle('padding-bottom'));
	}
	
});
/*
//	End SECTION::Element Spatial Computation Shortcuts
****************************************************************************/





/****************************************************************************
//	SECTION::Drag that can handle resetting limits of an element that
//	changes shape when being dragged.
*/

Drag.Move.implement({

	resetLimits: function(event) {
		if (this.container){
			var el = this.element, cont = this.container, ccoo = cont.getCoordinates(el.offsetParent), cps = {}, ems = {};

			['top', 'right', 'bottom', 'left'].each(function(pad){
				cps[pad] = cont.getStyle('padding-' + pad).toInt();
				ems[pad] = el.getStyle('margin-' + pad).toInt();
			}, this);

			var width = el.offsetWidth + ems.left + ems.right, height = el.offsetHeight + ems.top + ems.bottom;
			var x = [ccoo.left + cps.left, ccoo.right - cps.right - width];
			var y = [ccoo.top + cps.top, ccoo.bottom - cps.bottom - height];

			this.options.limit = {x: x, y: y};
			dbug.log('resetLimits to ')
			dbug.log(this.options.limit);
		}
		
		// reset this.value.now:
		var limit = this.options.limit;
		this.limit = {'x': [], 'y': []};
		for (var z in this.options.modifiers){
			if (!this.options.modifiers[z]) continue;
			if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
			else this.value.now[z] = this.element[this.options.modifiers[z]];
			if (this.options.invert) this.value.now[z] *= -1;
			this.mouse.pos[z] = event.page[z] - this.value.now[z];
			if (limit && limit[z]){
				for (var i = 2; i--; i){
					if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
				}
			}
		}
	}
});


/*
//	End SECTION::Drag that can handle % in addition to px in position styling
****************************************************************************/
