
/**
* Alguns mtodos destas classes foram baseados nos métodos do YUI,
* com melhoras e atualizaes.
*/

if (typeof ICore == 'undefined') {
	ICore = { };
}

/**
 * Se a página já carregou.
 */
ICore.pageLoaded = false;

/**
 * Método que trata de herdar uma classe da outra
 * @param {Function} subc
 * @param {Function} superc
 * @param {Object} overrides
 */
ICore.extend = function(subc, superc, overrides) {
	if (!superc||!subc) {
		throw new Error("Erro, classes não definidas.");
	}
	var F = function() {};
	F.prototype=superc.prototype;
	subc.prototype=new F();
	subc.prototype.constructor=subc;
	subc.superclass=superc.prototype;
	if (superc.prototype.constructor == Object.prototype.constructor) {
		superc.prototype.constructor=superc;
	}

	if (overrides) {
		for (var i in overrides) {
			subc.prototype[i]=overrides[i];
		}
		if (ICore.nav.isIE) {
			var add=["toString", "valueOf"];
			for (i=0;i<add.length;i=i+1) {
				var fname=add[i],f=overrides[fname];
				if (ICore.util.isFunction(f) && f!=Object.prototype[fname]) {
					subc.prototype[fname]=f;
				}
			}
		}
	}
};

/**
 * Objeto que trata a de diferenciar os navegadores.
 * @type {Object}
 */
ICore.nav = {
	isIE: (navigator.userAgent.indexOf('MSIE') > -1),
	isIE55: (navigator.userAgent.indexOf('MSIE 5.5') > -1),
	isIE6: (navigator.userAgent.indexOf('MSIE 6') > -1),
	isFF: (navigator.userAgent.indexOf('Firefox') > -1),
	isOpera: (navigator.userAgent.indexOf('Opera') > -1)
};

/**
 * Constantes com os eventos.
 * @type {Object}
 */
ICore.events = {
	LOAD: 'load',
	UNLOAD: 'unload',
	CLICK: 'click',
	DBLCLICK: 'dblclick',
	MOUSEDOWN: 'mousedown',
	MOUSEUP: 'mouseup',
	MOUSEMOVE: 'mousemove',
	MOUSEOVER: 'mouseover',
	MOUSEOUT: 'mouseout',
	KEYDOWN: 'keydown',
	KEYUP: 'keyup',
	KEYPRESS: 'keypress'
};

/**
 * Coleção de exeções do sistema.
 */
ICore.exceptions = {
	abort: function () { }
};

/**
 * Objeto que trata da interação e implementação de operações com os elementos.
 * 
 * @type {Object}
 */
ICore.dom = {
	/**
	* Faz uma busca no documento por um elemento com o ID informado.
	*
	* @param {String} id ID que ser buscado.
	*/
	get: function (id) {
		return document.getElementById(id);
	},

	/**
	* Faz uma busca no documento por um elemento com a TagName igual
	* ao parametro passado.
	*
	* Retorna um array de HTMLElement.
	*
	* @param {String} tagname
	* @return {HTMLElement[]}
	*/
	getByTag: function (tagname, parent) {
		if (!parent) {
			parent = document;
		}
		return parent.getElementsByTagName(tagname);
	},

	/**
	* Faz uma busca no documento por um elemento que
	* contenha a classe informada no parametro em sua
	* lista.
	*
	* Retorna uma lista de HTMLElement.
	*
	* @param {String} classname
	* @return {HTMLElemet[]}
	*/
	getByClass: function (classname, parent) {
		if (ICore.util.isUndefined(parent)) {
			parent = document;
		}
		var me = this;
		return this.findChild(parent, function (el) {
			return me.findClassName(classname, el);
		});
	},

	/**
	* Cria um elemento.
	*
	* @param {String} tname
	* @return {HTMLElement}
	*/
	createEl: function (tagname) {
		return document.createElement(tagname);
	},

	/**
	* Adiciona uma elemento dentro de outro criado.
	*
	* @param {HTMLElement} el Elemento pai no qual o parametro child deve ser inserido.
	* @param {HTMLElement} child Filho que ser inserido.
	* @return {HTMLElement}
	*/
	appendChild: function (el, child) {
		return el.appendChild(child);
	},

	/**
	* Cria um elemento de texto e o insere no objeto.
	*
	* @param {HTMLElement} el
	* @param {String} text
	*/
	appendText: function (el, text) {
		var child = document.createTextNode(text);
		return this.appendChild(child);
	},

	/**
	* Remove um elemento dentro de outro.
	*
	* @param {HTMLElement} el Elemento pai.
	* @param {HTMLElement} child Elemento que ser removido.
	* @return {HTMLElement}
	*/
	removeChild: function (el, child) {
		return el.removeChild(child);
	},

	/**
	* Altera a opacidade de um elemento.
	*
	* @param {HTMLElement} el
	* @param {Float} opacity Valor entre 0 (zero) e 1 (um).
	*/
	setOpacity: function (el, opacity) {
		if (ICore.nav.isIE) { // IE First by more navigators
			el.style.filter = 'filter:alpha(opacity='+(opacity*100)+')';
		} else if (ICore.nav.isFF) {
			el.style.mozOpacity = opacity;
		} else {
			el.style.opacity = opacity;
		}
	},

	/**
	* Esta classe verifica se uma classe (do css) está aplicada a um
	* elemento.
	*
	* @param {String} classname
	* @param {String} classes
	* @return {Integer}
	*/
	findClassName: function (classname, classes) {
		if (typeof classes != 'string') {
			classes = classes.className;
		}
		if (classes) {
			var c = classes.split(' ');
			return (c.indexOf(classname) > -1);
		} else {
			return false;
		}
	},

	/**
	* Adiciona uma classe na lista de classes de um objeto.
	*
	* @param {HTMLObject} obj
	* @param {String} class
	*/
	addClass: function (obj, c) {
		var cls;
		if (obj.className) {
			cls = obj.className.split(' ');
		} else {
			cls = [];
		}
		if (cls.indexOf(c) == -1) {
			obj.className = obj.className + (obj.className === ''?'':' ') + c;
		}
	},

	/**
	* Remove uma classe na lista de classes de um objeto.
	*
	* @param {HTMLObject} obj
	* @param {String} class
	*/
	removeClass: function (obj, c) {
		var cls = obj.className.split(' ');
		var i = cls.indexOf(c);
		if (i > -1) {
			cls.splice(i, 1);
			obj.className = cls.join(' ');
		}
	},
	
	/**
	 * Lista de funções listeners de eventos.
	 * 
	 * @type {Array}
	 */
	listeners: [],
	
	/**
	 * Busca no array {ICore.dom.listeners} se um elemento já está inserido. 
	 * 
	 * @param {HTMLElement} el Elemento ao qual o evento será adicionado
	 * @param {String} event Evento que será adicionado
	 * @param {Function} fnc Função que será chamada
	 * @param {Object} obj Objeto que será o "this" na função chamada.
	 */
	findListener: function (el, event, fnc, obj) {
		var l;
		for (var i = 0; i < this.listeners.length; i++) {
			l = this.listeners[i];
			if ((l.el == el) && (event == l.event) && (fnc == l.fnc) && (obj == l.obj)) {
				return i;
			}
		}
		return -1;
	},

	/**
	* Adicionar a função para ser chamada quando o evento for disparado.
	*
	* @param {HTMLElement} el
	* @param {String} event
	* @param {Function} fnc
	* @param {obj} obj Objeto que será o "this" na função chamada, caso não especificado será o proprio el
	*/
	addListener: function (el, event, fnc, obj) {
		el = ICore.util.object(el);
		if (obj) {
			wfnc = function (e) {
				e = e || event; // Fix para algum problema de versão do IE.
				fnc.call(obj, e);
			};
			this.listeners.push({el:el, event:event, fnc:fnc, obj:obj, wfnc: wfnc});
			this.addListener(el, event, wfnc);
		} else {
			if (el) {
				if (el.attachEvent) { // Pelo o IE ser mais usado;
					el.attachEvent('on' + event, fnc);
				} else {
					el.addEventListener(event, fnc, false);
				}
			} else {
				throw new Error('Objeto não encontrado.');
			}
		}
	},

	/**
	* Remove a função da lista de chamadas quando o evento for disparado.
	*
	* @param {HTMLElement} el
	* @param {String} event
	* @param {Function} fnc
	*/
	removeListener: function (el, event, fnc, obj) {
		if (typeof el == "string") {
			el = this.get(el);
		}
		if (obj) {
			var i = this.findListener(el, event, fnc, obj);
			if (i > -1) {
				this.removeListener(el, event, this.listeners[i].wfnc);
				delete this.listeners[i].wfnc;
				delete this.listeners[i];
				this.listeners.deleteItem(i);
			}
		} else {
			if (el) {
				if (el.attachEvent) { // Pelo o IE ser mais usado;
					el.detachEvent('on' + event, fnc);
				} else {
					el.removeEventListener(event, fnc, false);
				}
			} else {
				throw new Error('Objeto nÃ£o encontrado.');
			}
		}
	},

	/**
	* Faz um loop buscando entre os "pais" do elemento.
	* Ele chama uma função, passada por parametro, para avaliar
	* a busca, e ao encontrar e retorna a referência do objeto
	* encontrado.
	*
	* @param {HTMLElement} el
	* @param {Function} fnc
	* @return {HTMLElement}
	*/
	findParent: function (el, fnc) {
		while (el.parentNode && !(fnc(el.parentNode))) {
			el = el.parentNode;
		}
		return el.parentNode;
	},

	/**
	* Faz um loop buscando entre os "filhos" do element.
	* Ela chama uma função, passada por parametro, para avaliar
	* a busca e ao finalizar retorna um array com os elementos
	* encontrados.
	*
	* @param {HTMLElement} el
	* @param {Function} fnc
	* @return {HTMLElement[]}
	*/
	findChild: function (el, fnc) {
		var c, r;
		r = [];
		for (var i = 0; i < el.childNodes.length; i++) {
			c = el.childNodes[i];
			if (fnc(c)) {
				r.push(c);
			}
			r = r.concat(this.findChild(c, fnc));
		}
		return r;
	},
	
	/**
	 * Retorna o X e Y do elemento de acordo com o parent dado. 
	 * 
	 * @param {Object} obj Objeto que será avaliado
	 * @param {Object} parent Objeto que será o teto da busca
	 * @return {Object}
	 */
	getXYRelative: function (obj, parent) {
		var x = 0, y = 0;
		while (obj && (obj != parent)) {
			y += obj.offsetTop;
			x += obj.offsetLeft;
			obj = obj.offsetParent;
		}
		return {x:x, y:y};
	},
	
	/**
	 * Retorna apenas Y do elemento de acordo com o parent dado.
	 * 
	 * @param {Object} obj Objeto que será avaliado
	 * @param {Object} parent Objeto que será o teto da busca
	 * @return {Integer}
	 */
	getTop: function (obj, parent) {
		if (!parent) {
			parent = document;
		} 
		var r = 0;
		while (obj && (obj != parent)) {
			r += obj.offsetTop;
			obj = obj.offsetParent;
		}
		return r;
	},
	
	/**
	 * Retorna apenas X do elemento de acordo com o parent dado.
	 * 
	 * @param {Object} obj Objeto que será avaliado
	 * @param {Object} parent Objeto que será o teto da busca
	 * @return {Integer}
	 */
	getLeft: function (obj, parent) {
		if (!parent) {
			parent = document;
		} 
		var r = 0;
		while (obj) {
			r += obj.offsetLeft;
			obj = obj.offsetParent;
		}
		return r;
	}
};

ICore.util = {
/*	maskObj: null,
	showMask: function () {
		if (!this.maskObj) {
			this.maskObj = ICore.dom.get('mask');
		}
		this.maskObj.style.top = this.maskObj.style.left = '0px';
		this.maskObj.style.display = '';

		this.maskObj.style.height = document.body.parentNode.scrollHeight + 'px';
		this.maskObj.style.width = document.body.parentNode.scrollWidth + 'px';
	},

	hideMask: function () {
		this.maskObj.style.display = 'none';
	},
*/

	/**
	 * Se o parâmetro o for uma String ele tentará retornar um HTMLObject com ID igual a obj
	 * senão retorna o próprio obj.
	 * @param {String} obj
	 */
	object: function (obj) {
		if (this.isString(obj)) {
			return ICore.dom.get(obj);
		} else {
			return obj;
		}
	},

	/**
	 * Retorna se o parâmetro informado é uma função ou não.
	 * @param {Object} f
	 */
	isFunction: function (f) {
		return (typeof f == 'function');
	},

	/**
	 * Retorna se o parâmetro informado é um Array ou não.
	 * @param {Object} a
	 */
	isArray: function (a) {
		return (a instanceof Array);
	},

	/**
	 * Retorna se o parâmetro informado é uma String ou não. 
	 * @param {Object} s
	 */
	isString: function (s) {
		return (typeof s == 'string');
	},
	
	/**
	 * Retrona se o parâmetro informado é um número ou não.
	 * @param {Object} n
	 */
	isNumber: function (n) {
		return (typeof n == 'number');
	},

	/**
	 * Retorna se o parâmetro informado é indefinido ou não.
	 * @param {Object} o
	 */
	isUndefined: function (o) {
		return (typeof o == 'undefined');
	}
};

if (!Array.prototype.indexOf) {
	/**
	 * Definindo método não implementado no IE.
	 * 
	 * @param {Object} el
	 */
	Array.prototype.indexOf = function (el) {
		for (var i = 0; i < this.length; i++) {
			if (this[i] == el) {
				return i;
			}
		}
		return -1;
	};
}

/**
 * Busca um elemento no vetor e o remove.
 * 
 * @param {Object} el
 * @return {Integer} Retorna o índice do elemento que foi removido
 */
Array.prototype.remove = function (el) {
	var i = this.indexOf(el);
	if (i > -1) {
		this.deleteItem(i);
	}
	return i;
};

/**
 * Remove um único item do vetor.
 * 
 * @param {Object} index
 */
Array.prototype.deleteItem = function (index) {
	this.splice(index, 1);
};

/**
 * Limpa o vetor.
 */
Array.prototype.clear = function () {
	this.splice(0, this.length);
};

/**
 * Insere um elemento no meio do array.
 */
Array.prototype.insert = function (idx, el) {
	this.splice(idx, 0, el);
};

