var Activa = {};

//DOM Getters
/**
 * did - Shorcut for getElementById
 * @param	id		The element id you are looking for
 * @return			Element with matching id
 */
function did(id) {
	return document.getElementById(id);
}
/**
 * dbn - Shorcut for getElementsByName
 * @param	name	The element name you are looking for
 * @param	parent	optional;The parent item to search within
 * @return			Collection of elements
 */
function dbn(name, parent) {
	return (parent || document).getElementsByName(name);
}
/**
 * dbt - Shorcut for getElementsByTagName
 * @param	tag		The element tagName you are looking for
 * @param	parent	optional;The parent item to search within
 * @return 			Collection of elements
 */
function dbt(tag, parent) {
	return (parent || document).getElementsByTagName(tag);
}
/**
 * dbc - Shortcut for getElementsByClassName
 * @param	className	The className you are looking for
 * @param	parent		optional;The parent item to search within
 * @return				Array of elements
 */
function dbc(className, parent) {
	className = 'dev_'+className;
	//use default provided by browser if it exists otherwise use our implementation
	if ( document.getElementsByClassName ) {
		return (parent || document).getElementsByClassName(className);
	}
	var nodes = Activa.toArray(dbt('*', parent)), elms = [];
	nodes.forEach(function(node){
		if ( Activa.DOM.hasClass(node, className) ) {
			elms.push(node);
		}
	});
	return elms;
}

Activa.Exception = function activaException(message, file, line, trace, url) {
	this.message = message;
	this.file = file;
	this.line = line;
	this.trace = trace;
	this.url = url;
};

Activa.urlencode = function urlencode(string) {
	return encodeURIComponent(string).replace(/%20/g, "+");
};

Activa.NewWindow = function NewWindow(mypage, myname, w, h, scroll) {
	var winl = (screen.width - w) / 2;
	var wint = (screen.height - h) / 2;
	winprops = 'height='+h+',width='+w+',top='+wint+',left='+winl+',scrollbars='+scroll+',resizable=yes'
	win = window.open(mypage, myname, winprops)
	if ( parseInt(navigator.appVersion) >= 4 ) { 
		win.window.focus(); 
	}
	return win;
};

//Cookies
Activa.createCookie = function createCookie(name, value, days) {
	if ( days ) {
		var date = new Date();
		date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
};

Activa.getCookie = function getCookie(name) {
	var start = document.cookie.indexOf(name + "=");
	var len = start + name.length + 1;
	if ( start < 0 ) {
		return null;
	}
	if ( start == 1 ) { 
		return null; 
	}
	var end = document.cookie.indexOf(';', len);
	if ( end == -1 ) { 
		end = document.cookie.length; 
	}
	return unescape( document.cookie.substring(len, end) );
};

Activa.padString = function padString(str, len) {
	if ( typeof(str) != 'string' ) {
		str = String(str);
	}
	while ( str.length < len ) {
		str = '0'+str;
	}
	return str;
};

Activa.gaTrack = function gaTrack(str) {
	try {
		if ( typeof(pageTracker) != 'undefined' ) {
			pageTracker._trackPageview(str);
		} else if ( typeof(urchinTracker) != 'undefined' ) {
			urchinTracker(str);
		}
	} catch ( err ) {}
}

/**
 * Activa.fixEvent - Returns an event object with common properties/methods normalized for easier cross browser usage.
 * @param e		object	optional;Event object to normalize
 * @return		object	Event object after normalization
 */
Activa.fixEvent = function fixEvent(e) {
	var evnt = e || window.event;
	if ( !evnt ) { 
		return null; 
	}
	if ( !evnt.target ) { 
		evnt.target = evnt.srcElement; 
	}
	evnt.preventDefault = (evnt.preventDefault)? evnt.preventDefault : function() { this.returnValue = false; };
	evnt.stopPropagation = (evnt.stopPropagation)? evnt.stopPropagation : function() { this.cancelBubble = true; };
	var scroll = Activa.Dimensions.getScrollXY();
	if ( e.pageX === undefined ) { 
		e.pageX = e.clientX + scroll.x; 
	}
	if ( e.pageY === undefined ) { 
		e.pageY = e.clientY + scroll.y; 
	}
	if ( typeof e.layerX != 'number' ) { 
		e.layerX = e.offsetX; 
	}
	if ( typeof e.layerY != 'number' ) { 
		e.layerY = e.offsetY; 
	}
	if ( !e.relatedTarget ) {
		switch ( e.type ) {
			case 'mouseover':
			case 'mouseenter':
				e.relatedTarget = e.fromElement;
				break;
			case 'mouseleave':
			case 'mouseout':
				e.relatedTarget = e.toElement;
				break;
		}
	};
	return evnt;
};

Activa.createDelegate = function createDelegate(oObject, sMethodName, data) {
	if ( typeof(oObject[sMethodName]) != 'function' ) {
		//throw new Error("Unable to find " + sMethodName + " on " + oObject);
	}
	return function () {
		if ( data ) {
			var args = [];
			var i = 0;
			while ( arguments[i] ) {
				args[i] = arguments[i];
				i++;
			}
			args[i] = data;
			return oObject[sMethodName].apply(oObject, args);
		}
		return oObject[sMethodName].apply(oObject, arguments);
	};
};

Activa.registerEvent = function registerEvent(elem, event, callback, capture) {
	capture = Boolean(capture);
	elem = Activa.DOM.check(elem);
	
	if ( event == 'allchange' ) {
		Activa.registerEvent(elem, 'change', callback, capture);
		Activa.registerEvent(elem, 'click', callback, capture);
		Activa.registerEvent(elem, 'keyup', callback, capture);
		return;
	}
	
	function wrapCallback(e) { 
		callback(Activa.fixEvent(e));
	};
	
	if ( elem.addEventListener ) {
		elem.addEventListener(event, wrapCallback, capture);
	} else {
		elem.attachEvent('on'+event, wrapCallback); 
	}
	
	return new Activa.registeredEvent(elem, event, wrapCallback, capture);
};

Activa.unregisterEvent = function unregisterEvent(elem, event, callback, capture) {
	capture = Boolean(capture);
	elem = Activa.DOM.check(elem);
	
	if ( event == 'allchange' ) {
		Activa.unregisterEvent(elem, 'change', callback, capture);
		Activa.unregisterEvent(elem, 'click', callback, capture);
		Activa.unregisterEvent(elem, 'keyup', callback, capture);
		return;
	}
	
	if ( elem.removeEventListener ) {
		elem.removeEventListener(event, callback, capture);
	} else {
		elem.detachEvent('on'+event, callback); 
	}
}

Activa.registeredEvent = function registeredEvent(elem, event, callback, capture) {
	this.elem = elem;
	this.event = event;
	this.callback = callback;
	this.capture = capture;
	
	this.unregister = function() {
		Activa.unregisterEvent(this.elem, this.event, this.callback, this.capture);
	}
};

/**
 * Activa.toArray - Shortcut for Array.prototype.slice.call(obj, idx)
 * @param	obj		mixed		Object to call array.slice on
 * @param	start	integer		Index at which to begin slicing
 * @param	end		integer		Index at which to end slicing
 * @return			array		New array containing values from the idx to the end of the obj
 *		Note: Useful for transforming arguments object and collections into regular arrays
 *		ex.	function(){ var args = Activa.toArray(arguments); alert(args instanceof Array); }
 */

Activa.toArray = function toArray(obj, start, end) {
	var ret = obj;
	if ( window.ActiveXObject ) {
		if ( typeof obj.length == 'undefined' ) { 
			obj.length = Activa.getLength(obj); 
		}
		ret = Array.prototype.map.call(obj, function mapCall(item) { return item; });
	}
	var args = [(start || 0)];
	if ( end && !isNaN(Number(end)) ) {
		args.push(Number(end));
	}
	return Array.prototype.slice.apply(ret, args);
};


/**
 * getLength - Finds the total number of all non-function properties owned by the object (see hasOwnProperty)
 * @param obj    object    The object whose properties to count.
 * @return       int       The length of the object or 0 if obj was invalid
 */
Activa.getLength = function getLength(obj) {
    if ( !obj ) {
    	return 0; 
    }
    var i=0;
    for ( var key in obj ) {
        if ( obj.hasOwnProperty(key) && typeof obj[key] !='function' ) { 
        	i++; 
        }
    }
    return i;
};


//Prototypes
String.prototype.ltrim = function() {
	return this.replace(/^\s*/, '');
};

String.prototype.rtrim = function() {
	return this.replace(/\s*$/, '');
};

String.prototype.trim = function() {
	return this.rtrim().ltrim();
};

/**
 * Array and object functions
 */
/**
 * Array methods indexOf, forEach, map, filter
 * 		Added for browsers without native support
 */
Array.prototype.indexOf = (function() {
	var fn;
	if ( typeof Array.prototype.indexOf == 'function' ) {
		fn = Array.prototype.indexOf; 
	} else {
		fn = function indexOf(obj, start){
			var len = this.length;
			start = Number(start) || 0;
			start = (start < 0) ? Math.ceil(start) : Math.floor(start);
			if ( start < 0 ) { 
				start+= len; 
			}
			for ( ; start < len; start++ ) {
				if ( start in this && this[start] === obj ) { 
					return start; 
				}
			}
			return -1;
		}
	}
	var indexOf = null;
	return fn;
})();
Array.prototype.forEach = (function() {
	var fn;
	if ( typeof Array.prototype.forEach == 'function' ) {
		fn = Array.prototype.forEach;
	} else {
		fn = function forEach(fn /*, bind*/){
			var len = this.length;
			if ( typeof(fn) != 'function' ) { 
				throw new TypeError(); 
			}
			var bind = arguments[1];
			for ( var i = 0; i < len; i++ ) {
				if ( i in this ) { 
					fn.call(bind, this[i], i, this); 
				}
			}
		};
	}
	var forEach = null;
	return fn;
})();
Array.prototype.map = (function() {
	var fn;
	if ( typeof Array.prototype.map == 'function' ) {
		fn = Array.prototype.map;
	} else {
		fn = function map(fn /*, bind*/){
			var len = this.length;
			if ( typeof(fn) != 'function' ) { 
				throw new TypeError(); 
			}
			var ret = [], bind = arguments[1];
			for ( var i = 0; i < len; i++ ) {
				if ( i in this ) { 
					ret[i] = fn.call(bind, this[i], i, this); 
				}
			}
			return ret;
		};
	}
	var map = null;
	return fn;
})();
Array.prototype.filter = (function() {
	var fn;
	if ( typeof Array.prototype.filter == 'function' ) {
		fn = Array.prototype.filter;
	} else {
		fn = function filter(fn /*, bind*/){
			var len = this.length;
			if ( typeof(fn) != 'function' ) { 
				throw new TypeError(); 
			}
			var ret = [], bind = arguments[1], val=null;
			for ( var i = 0; i < len; i++ ) {
				if ( i in this ) {
					val = this[i];
					if ( fn.call(bind,val,i,this) ) { 
						ret.push(val); 
					}
				}
			}
			return ret;
		};
	}
	var filter = null;
	return fn;
})();
Array.prototype.every = (function() {
	var fn;
	if ( typeof Array.prototype.every == 'function' ) {
		fn = Array.prototype.every;
	} else {
		fn = function every(fn /*, bind*/) {
			return this.filter.apply(this, Activa.toArray(arguments)).length === this.length;
		};
	}
	var every = null;
	return fn;
})();
Array.prototype.some = (function() {
	var fn;
	if ( typeof Array.prototype.some == 'function' ) {
		fn = Array.prototype.some;
	} else {
		fn = function some(fn /*, bind*/) {
			return this.filter.apply(this, Activa.toArray(arguments)).length > 0;
		};
	}
	var some = null;
	return fn;
})();

Array.prototype.inArray = function(targ) {
	if ( this.indexOf(targ) != -1 ) {
		return true;
	} else {
		return false;
	}
};

Array.prototype.find = function(item) {
	for ( var i = 0; i < this.length; i++ ) {
		if ( this[i] == item ) {
			return i;
		}
	}
	return false;
};

Array.prototype.remove = function(pos) {
	if ( pos != -1 ) {
		this.splice(pos, 1);
	}	
};

Date.prototype.format = function(format) {
	var res = '';
	for ( var i = 0; i < format.length; i++ ) {
		switch ( format.charAt(i) ) {
			case 'm':
				res += Activa.padString(this.getMonth() + 1, 2);
				break;
				
			case 'd':
				res += Activa.padString(this.getDate(), 2);
				break;
				
			case 'Y':
				res += this.getFullYear();
				break;
				
			case 'H':
				res += Activa.padString(this.getHours(), 2);
				break;
				
			case 'i':
				res += Activa.padString(this.getMinutes(), 2);
				break;
				
				
			default:
				res += format.charAt(i);
				break;
				
		}
	}
	return res;
};

Function.prototype.bind = function() {
	var fn = this;
	var args = Activa.toArray(arguments);
	var reference = args.shift();
	return function binded() {
		var arglist = args.concat(Activa.toArray(arguments));
		return fn.apply(reference, arglist);
	};
};

