
/**
* 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);
};


