/**
 * @author Wellington Tadeu dos Santos
 * @version 1.00
 * @release ABR/2009
 * @charset "iso-8859-1"
 */


var core = window.core || {};
var $ = window.$;

if (!core.internal){
	core.internal = {
	    threads: [],
	    caller: null,
		loaded: 0, 
	    debug_info: {source: null, message: null}
	};


/**
 * obtém parametro do request feito via GET
 */
core.getParameter = function(parameterName, defaultValue, queryString) {

  var parameterName = parameterName + "=";
  var result = defaultValue;
  var begin;
  var end;

  queryString = queryString || this.window.top.location.search.substring(1);
  
  if (queryString.length > 0) {
      begin = queryString.indexOf(parameterName);
      
      if (begin != -1) {
          begin += parameterName.length;
          end = queryString.indexOf("&", begin);
          
          if (end == -1) {
              end = queryString.length;
          }
          result = unescape(queryString.substring(begin, end));
      }
  }
  return result;
};
	

/**
 * interompe execução por N mili-segundos
 * @param millis
 */
core.sleep = function(millis) {
    var date = new Date();
    var curDate = new Date();
    while((curDate-date) < millis) {
		delete curDate;
        curDate = new Date();
    }
	delete date;
};


/**
 * construtor da classe Thread
 */
core.Thread = function(){
    var threadId = core.internal.threads.length;
    core.internal.threads[threadId] = this;
    
    // Constantes Publicas //
    
    this.STOPPED = 0;
    this.STARTED = 1;
    this.RUNNING = 2;
    this.FINISHED = 3;
    this.ERROR = 4;

    // Atributos Publicos //

    this.threadId = threadId;
    this.onExecute = null;
    this.timeout = 10;
    this.error = null;

    // Atributos Privados //

    this._state = this.STOPPED;
    
    /**
     * Método responsável por executar a thread
     */
    this.start = function (){
        if (!this.onExecute){
            core.debug("core.Thread().invoke: o evento onExecute não foi definido!");
            return;
        }
        if (this._state == this.RUNNING){
            // a thread já está sendo executada //
            return;
        }
        if (this._state == this.STARTED){
            // a thread está pendente //
            return;
        }
        this.threadId = threadId;
        core.internal.threads[threadId] = this;
        this._state = this.STARTED;
        if (!this.timeout || this.timeout <= 0){
            this.timeout = 1;
            this._process();
        } else {
            window.setTimeout(this._process, this.timeout);
        }
    }
    
    /**
     * Método responsável por parar a Thread
     */
    this.stop = function(){
        this._state = this.FINISHED;
        core.internal.threads[threadId] = undefined;
    }
    
    /**
     * Função Privada
     */
    this._process = function (){
        var self = core.internal.threads[threadId];
        if (core.isNull(self))
            return;
        if (self._state == self.STARTED){
            self._state = self.RUNNING;
            try {
                self.onExecute();
                if (self._state == self.RUNNING){
                    self._state = self.STARTED;
                    window.setTimeout(self._process, self.timeout);
                }
            } catch (ex) {
                self.stop();
                self._state = self.ERROR;
                self.error = ex;
                core.debug("Exception: " + ex.name + ", " + ex.message, "core.Thread._process");
                throw ex;
            }
        }
    }
};


/**
 * Método responsável por buscar um elemento
 * pela ID que esteja dentro de um objeto pai
 */
core.findChildById = function(parent, id){
    if (!parent.childNodes){
        return null;
    }
	
    for (var i=0; i<parent.childNodes.length; i++){
        if (parent.childNodes[i].id == id){
            return parent.childNodes[i];
        }
    }

    for (var i=0; i<parent.childNodes.length; i++){
        var item = core.findChildById(parent.childNodes[i], id);
        if (item)
            return item;
    }
    return null;
};


/**
 * Método responsável por buscar um elemento
 * pelo NAME que esteja dentro de um objeto pai
 */
core.findChildByName = function(parent, name){
    if (!parent.childNodes){
        return null;
    }
	
    for (var i=0; i<parent.childNodes.length; i++){
        if (parent.childNodes.item(i).name == name){
            return parent.childNodes.item(i);
        }
    }
	
    for (var i=0; i<parent.childNodes.length; i++){
        var item = core.findChildByName(parent.childNodes.item(i), name);
        if (item)
            return item;
    }
    return null;
};


/**
 * Método responsável por buscar um elemento
 * pelo ID ou pelo NAME que esteja dentro de um objeto pai
 */
core.findChild = function(parent, idName){
    var result = core.findChildById(parent, idName);
    if (!result) result = core.findChildByName(parent, idName);
    return result;
};


/**
 * Método responsável por buscar um elemento pela ID
 */
if (document.getElementById) {
    core.findById = function() {
        var elements = new Array();
        for (var i = 0; i < arguments.length; i++) {
            var element = arguments[i];
            if (typeof element == 'string') {
                element = document.getElementById(element);
            }
            if (arguments.length == 1) {
                return element;
            }
            elements.push(element);
        }
        return elements;
    };
}
else
if (document.all) {
    core.findById = function() {
        var elements = new Array();
        for (var i = 0; i < arguments.length; i++) {
            var element = arguments[i];
            if (typeof element == 'string') {
                element = document.all[element];
            }
            if (arguments.length == 1) {
                return element;
            }
            elements.push(element);
        }
        return elements;
    };
}
else {
    core.findById = function() {
        var elements = new Array();
        for (var i = 0; i < arguments.length; i++) {
            var element = arguments[i];
            if (typeof element == 'string') {
                element = core.findChildById(element);
            }
            if (arguments.length == 1) {
                return element;
            }
            elements.push(element);
        }
        return elements;
    };
}


/**
 * Método responsável por buscar um elemento pelo NAME
 */
core.findByName = function(){
    var elements = new Array();
    for (var i = 0; i < arguments.length; i++) {
        var element = arguments[i];
        if (typeof element == 'string') {
            element = document.getElementsByName(element);
            if (!element || element.length == 0)
                element = null;
            else
                element = element[0];
        }
        if (arguments.length == 1) {
            return element;
        }
        elements.push(element);
    }
    return elements;
};


/**
 * Método responsável por buscar um elemento pelo ID ou NAME
 */
core.find = function(){
    var elements = new Array();
    for (var i = 0; i < arguments.length; i++) {
        var element = arguments[i];
        if (typeof element == 'string') {
            var temp = core.findById(element);
            if (temp)
                element = temp;
            else {
                element = document.getElementsByName(element);            
                if (!element || element.length == 0)
                    element = null;
                else
                    element = element[0];
            }
        }
        if (arguments.length == 1) {
            return element;
        }
        elements.push(element);
    }
    return elements;
};


/**
 * Função Privada
 */
core.internal.find = function(ele, source) {
    var orig = ele;
    ele = core.find(ele);
    if (ele == null)
        core.debug(source + " não encontrou o elemento: " + orig + ".");
    return ele;
};


/**
 * Método responsável por obter as dimensoes
 * reais em tempo de execução de um objeto
 */
core.getElementBounds = function(element){
    var rect = {};
    
    if (!element){
        rect.left = 0;
        rect.top = 0;
        rect.right = 0;
        rect.bottom = 0;
    } 
    else
    if (element.getBoundingClientRect){
        rect = element.getBoundingClientRect();
    } 
    else 
    {
        var parentRect = core.getElementBounds(element.offsetParent);
        rect.left = element.offsetLeft + parentRect.left;
        rect.top = element.offsetTop + parentRect.top;		
        rect.right = element.offsetWidth + rect.left;
        rect.bottom = element.offsetHeight + rect.top;
    }
    return rect;
};


/**
 * Método responsável por obter somente 
 * o texto do conteudo de um elemento
 */
core.getText = function(ele){
    ele = core.internal.find(ele, "getText()");
    if (ele == null) return null;
    
    if (!core.isHTMLElement(ele, "select")) {
        return core.getValue(ele, true);
    }

    var sel = ele.selectedIndex;
    if (sel != -1)
        return ele.options[sel].text;
    else
        return "";
};


/**
 * Método responsável por inserir conteudo  
 * como somente texto no elemento
 */
core.setText = function(ele, val){
    core.setValue(ele, val, true);
};


/**
 * Método responsável por obter o value de um elemento
 */
core.getValue = function(ele, onlyText) {
  var orig = ele;
  if (typeof ele == "string") {
    ele = core.findById(ele);
    if (ele && ele.id != orig) ele = null;
  }
  var nodes = null;
  if (ele == null) {
    nodes = document.getElementsByName(orig);
    if (nodes.length >= 1) ele = nodes.item(0);
  }
  if (ele == null) {
    core.debug("core.getValue() não encontrou elemento: " + orig + ".");
    return "";
  }

  if (core.isHTMLElement(ele, "select")) {
    if (ele.type == "select-multiple") {
      var reply = new Array();
      for (var i = 0; i < ele.options.length; i++) {
        var item = ele.options[i];
        if (item.selected) {
          var valueAttr = item.getAttributeNode("value");
          if (valueAttr && valueAttr.specified) {
            reply.push(item.value);
          }
          else {
            reply.push(item.text);
          }
        }
      }
      return reply;
    }
    else {
      var sel = ele.selectedIndex;
      if (sel != -1) {
        var item = ele.options[sel];
        var valueAttr = item.getAttributeNode("value");
        if (valueAttr && valueAttr.specified) {
          return item.value;
        }
        return item.text;
      }
      else {
        return "";
      }
    }
  }

  if (core.isHTMLElement(ele, "input")) {
    if (ele.type == "radio") {
      if (nodes && nodes.length >= 1) {
        for (var i = 0; i < nodes.length; i++) {
          var node = nodes.item(i);
          if (node.type == ele.type) {
            if (node.checked) return node.value;
          }
        }
      }
      return ele.checked;
    }
    if (ele.type == "checkbox") {
      if (nodes && nodes.length >= 1) {
        var reply = [];
        for (var i = 0; i < nodes.length; i++) {
          var node = nodes.item(i);
          if (node.type == ele.type) {
            if (node.checked) reply.push(node.value);
          }
        }
        return reply;
      }
      return ele.checked;
    }
    return ele.value;
  }

  if (core.isHTMLElement(ele, "textarea")) {
    return ele.value;
  }

  if (onlyText) {
    if (ele.textContent) return ele.textContent;
    else if (ele.innerText) return ele.innerText;
  }
  
  return ele.innerHTML;
};


/**
 * Método responsável por definir o valor de um elemento
 */
core.setValue = function(ele, val, onlyText) {
  if (val == null) val = "";

  var orig = ele;
  if (typeof ele == "string") {
    ele = core.findById(ele);
    if (ele && ele.id != orig) ele = null;
  }
  var nodes = null;
  if (ele == null) {
    nodes = document.getElementsByName(orig);
    if (nodes.length >= 1) ele = nodes.item(0);
  }

  if (ele == null) {
    core.debug("setValue() não encontrou elemento: " + orig + ".");
    return;
  }

  //core.highlight(ele);

  if (core.isHTMLElement(ele, "select")) {
    if (ele.type == "select-multiple" && core.isArray(val)) core.internal.selectListItems(ele, val);
    else core.internal.selectListItem(ele, val);
    return;
  }

  if (core.isHTMLElement(ele, "input")) {
    if (ele.type == "radio" || ele.type == "checkbox") {
      if (nodes && nodes.length >= 1) {
        for (var i = 0; i < nodes.length; i++) {
          var node = nodes.item(i);
          if (node.type != ele.type) continue;
          if (core.isArray(val)) {
            node.checked = false;
            for (var j = 0; j < val.length; j++)
              if (val[j] == node.value) node.checked = true;
          }
          else {
            node.checked = (node.value == val);
          }
        }
      }
      else {
        ele.checked = (val == true);
      }
    }
    else ele.value = val;

    return;
  }

  if (core.isHTMLElement(ele, "textarea")) {
    ele.value = val;
    return;
  }

  if (val.nodeType) {
    if (val.nodeType == 9 /*Node.DOCUMENT_NODE*/) val = val.documentElement;
    val = core.internal.importNode(ele.ownerDocument, val, true);
    ele.appendChild(val);
    return;
  }

  if (onlyText)
    ele.innerHTML = core.escapeHTML(val);
  else
    ele.innerHTML = val;
};


/**
 * Função Privada
 */
core.internal.selectListItems = function(ele, val) {
  var found  = false;
  var i;
  var j;
  for (i = 0; i < ele.options.length; i++) {
    ele.options[i].selected = false;
    for (j = 0; j < val.length; j++) {
      if (ele.options[i].value == val[j]) {
        ele.options[i].selected = true;
      }
    }
  }

  if (found) return;

  for (i = 0; i < ele.options.length; i++) {
    for (j = 0; j < val.length; j++) {
      if (ele.options[i].text == val[j]) {
        ele.options[i].selected = true;
      }
    }
  }
};


/**
 * Função Privada
 */
core.internal.selectListItem = function(ele, val) {
  var found = false;
  var i;
  for (i = 0; i < ele.options.length; i++) {
    if (ele.options[i].value == val) {
      ele.options[i].selected = true;
      found = true;
    }
    else {
      ele.options[i].selected = false;
    }
  }

  if (found) return;

  for (i = 0; i < ele.options.length; i++) {
    ele.options[i].selected = (ele.options[i].text == val);
  }
};


/**
 * Função Privada
 */
core.internal.importNode = function(doc, importedNode, deep) {
  var newNode;

  if (importedNode.nodeType == 1 /*Node.ELEMENT_NODE*/) {
    newNode = doc.createElement(importedNode.nodeName);

    for (var i = 0; i < importedNode.attributes.length; i++) {
      var attr = importedNode.attributes[i];
      if (attr.nodeValue != null && attr.nodeValue != '') {
        newNode.setAttribute(attr.name, attr.nodeValue);
      }
    }

    if (typeof importedNode.style != "undefined") {
      newNode.style.cssText = importedNode.style.cssText;
    }
  }
  else if (importedNode.nodeType == 3 /*Node.TEXT_NODE*/) {
    newNode = doc.createTextNode(importedNode.nodeValue);
  }

  if (deep && importedNode.hasChildNodes()) {
    for (i = 0; i < importedNode.childNodes.length; i++) {
      newNode.appendChild(core.internal.importNode(doc, importedNode.childNodes[i], true));
    }
  }

  return newNode;
};


/**
 * Método responsável por retornar o texto de
 * um elemento SELECT a partir do valor
 */
core.getSelectTextForValue = function(value, ele){
    ele = core.internal.find(ele);
    if (ele == null) return "";
    
    if (!core.isHTMLElement(ele, "select")){
        core.debug("core.getSelectTextForValue() só pode ser usado com elemento SELECT.");
        return "";
    }
    
    for (var i=0; i<ele.options.length; i++){
        var item = ele.options[i];
        var valueAttr = item.getAttributeNode("value");
        
        if (valueAttr && valueAttr.specified && value == item.value) {
            return core.parseString(item.text);
        }    
    }
    
    return "";
};


/**
 * obtém valores dos elementos com NAME de um FORM
 * @param form
 */
core.getFormValues = function(form){
	var values = {};
	form = core.internal.find(form, "core.getFormValues");
	if (form) core._getFormValues(form.elements, values);
	return values;
};


/**
 * Função Privada
 */
core._getFormValues = function(nodes, values){
	var item;
	var name;
	for (var i=0; i<nodes.length; i++){
		item = nodes[i];
		name = item.name;
		if (name && values[name] === undefined)
			values[name] = item.value;
		/*if (item.childNodes)
			core._getFormValues(item.childNodes, values);*/
	}
};


/**
 * seta valores nos elementos de um form pelo name
 * @param form
 * @param values - valores a serem setados
 * @param autocreate - {Boolean} criar elementos se não existirem 
 */
core.setFormValues = function(form, values, autocreate){
	form = core.internal.find(form, "core.setFormValues");
	if (!form) return;
	var done = {};
	//TODO ....
	if (!autocreate){
		throw "Não implementado: core.setFormValues para substituição";
	}
	var input;
	if (autocreate) {
		for (var x in values) {
			if (!done[x]) {
				input = core.document.createElement("input");
				input.name = x;
				input.value = values[x];
				form.appendChild(input);
			}
		}
	}
	delete done;
};


/**
 * obtém parametros de uma url e seta dentro de "params"
 * @param url
 * @param params - recebe os parametros
 * @return String - url sem os parametros
 */
core.getParamsFromURL = function(url, params){
	var j = url.indexOf("?");
	var m;
	if (j != -1) {
		var items = url.substring(j + 1).split("&");
		for (var i=0; i<items.length; i++){
			m = items[i].split("=");
			if (m[0]) params[m[0]] = m[1];
		}
		return url.substring(0, j);
	}
	return url;
};


/**
 * Método responsável por verificar se o 
 * elemento é um tipo específico de Tag HTML
 */
core.isHTMLElement = function(ele, nodeName) {
    if (ele == null || typeof ele != "object" || ele.nodeName == null)
        return false;

    if (nodeName != null) {
        var test = ele.nodeName.toLowerCase();
        if (typeof nodeName == "string")
            return test == nodeName.toLowerCase();
        
        if (core.isArray(nodeName)) {
            var match = false;
            for (var i = 0; i < nodeName.length && !match; i++) {
                if (test == nodeName[i].toLowerCase())
                    match =  true;
            }
            return match;
        }
        core.debug("argumento inválido para core.isHTMLElement()");
        return false;
    }
    return true;
};


/**
 * Método responsável por verificar se o objeto é um Array
 */
core.isArray = function(it) {
  return it && (it instanceof Array || typeof it == "array");
};


/**
 * Método responsável por substituir 
 * caracteres HTML por caracteres comuns
 */
core.escapeHTML = function(value) {
    return core.parseString(value).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
};


/**
 * Método responsável por comparar 2 números armazenados como strings 
 * retorna valor negativo se o primeiro for menor,
 * retorna zero se identicos
 * retorna valor positivo se o primeiro for maior,
 */
core.compareNumberStr = function(item1, item2){
   
    var len1 = item1.length;
    var len2 = item2.length;
    
    var result = len1 - len2;
    if (result != 0 || len1 == 0) return result < 0 ? -1 : result > 0 ? 1 : 0;
    
    for (var i=0; i<len1; i++){
        result = item1.charCodeAt(i) - item2.charCodeAt(i); 
        if (result != 0){
            return result < 0 ? -1 : 1;
        }
    }
    
    return 0;
};


/**
 * Método responsável por verificar se um valor é numérico
 */
core.isNumeric = function(value) {
    return core.masks.Float.test(value) || core.masks.Currency.test(value);
};


/**
 * Método responsável por transformar um string em número decimal
 */
core.parseDecimal = function(value){
    value = core.parseString(value);
    value = value.replace(/\s/g, "");
    value = value.replace(/^\+/, "");
    if (core.isNumeric(value)){
        value = value.replace(/\./g, "");
        value = value.replace(/^0*/, "");
        if (value == "") value="0";
        if (value.charAt(0) == ",") value = "0" + value;
        return value.replace(",", ".");
    }else
        return null;
};


/**
 * Método responsável por transformar um valor em string
 */
core.parseString = function(value){
    if (value){
        return ("").concat(value);
    }else
        return "";
};


/**
 * Método responsável por remover espaços em branco a direita e a esquerda
 */
core.trim = function(value){
    return core.parseString(value).replace(core.masks.LTrim,"")
                                  .replace(core.masks.RTrim,"");
};


/**
 * Método responsável por remover espaços em branco a esquerda
 */
core.ltrim = function(value){
    return core.parseString(value).replace(core.masks.LTrim,"");
};


/**
 * Método responsável por remover espaços em branco a direita
 */
core.rtrim = function(value){
    return core.parseString(value).replace(core.masks.RTrim,"");
};


/**
 * Método responsável por somar duas dimensões
 */
core.addDimension = function(a, b){
    return parseInt(a) + parseInt(b);
};


/**
 * Método responsável por validar se o valor não é vazio
 */
core.isEmpty = function(value){
    if (value)
        return core.trim(value) == "";
    else
        return true;
};


/**
 * Método responsável por validar se
 * um objeto é null ou undefined
 */
core.isNull = function(obj){
    if (obj) return false;
    if (obj == undefined) return true;
    if (obj == null) return true;
    return false;
};


/**
 * Método responsável por clonar um objeto
 */
core.cloneObject = function(obj){
    var res = {};
    for (var prop in obj){
        res[prop] = obj[prop];
    }
    return res;
};


/**
 * Retorna true e for IE com a versão requerida
 */
core.isMSIE = function(version){
    if (version)
        return this.isIE && this.isIE >= version;
    else
        return this.isIE; 
};


/**
 * Retorna o elemento alvo do evento
 */
core.getEventTarget = function(evt) {
    return evt.target ? evt.target : evt.srcElement;
};


/**
 * Método responsável por cancelar um evento de teclado
 */
core.cancelKeyEvent = function(evt){
    if (evt.preventDefault) {
        // Firefox
        evt.preventDefault();
        var newEvent = document.createEvent("KeyEvents");
        newEvent.initKeyEvent("keypress", true, true, document.defaultView,
                              evt.ctrlKey, evt.altKey, evt.shiftKey, evt.metaKey, 0, 0);
        evt.target.dispatchEvent(newEvent);
    } else {
        // IE
        evt.returnValue = false;
    }
};


/**
 * remove todos elementos filhos e deleta
 * @param ele - elemento
 */
core.deleteElementChildren = function(ele){
	ele = core.internal.find(ele, "core.deleteElementChildren");
	if (!ele || !ele.childNodes || !ele.childNodes.length) return;
	var item = ele.childNodes[0];
	var next;
	while (item){
		next = item.nextSibling;
		ele.removeChild(item);
		delete item;
		item = next;
	}
};


/**
 * Função Utilitária
 */
core.dump = function(x, include, exclude){
    if (!x) return x;
    var z = "{\n";
	var v;
    for (var a in x){
	    if (include && !include.test(a))
	        continue;
	    if (exclude && exclude.test(a))
	        continue;
		try {
			v = x[a];
		} catch (ex){
			v = "Erro: " + ex.message;
		}
        z += a + "=";
        if (v && typeof v == "function") 
            z += "(function)";
        else	
            z += "".concat(v);
        z += "\n";
    }
    return z + "}\n"; 
}


/**
 * Função Utilitária
 */
core.dumpFull = function(x, include, exclude){
    if (!x) return x;
    var z = "{<br>\n";
    var def;
    for (var a in x){
        if (include && !include.test(a))
            continue;
        if (exclude && exclude.test(a))
            continue;
        var v = x[a];
        z += a + "=";
        def = true;
        if (v){
            if (typeof v == "function"){ 
                z += "(function)";
                def = false;
            }
            else
            if (typeof v == "object"){ 
                z += core.dumpFull(v);
                def = false;
            }
        }
        if (def)
            z += "".concat(v);
        z += "<br>\n";
    }
    return z + "}<br>\n"; 
}


/**
 * Função Utilitária
 */
core.dumpEx = function(x, include){
    return dump(x, include, /^_.*/);
}


/**
 * Método responsável por fazer log de debug
 */
core.debug = function(msg){
    core.internal.debug_info.message = msg;
    core.internal.debug_info.args = arguments;

	if (console && (console.debug || console.log)) {
		if (console.debug)
			console.debug.apply(console, arguments);
		else
			console.log.apply(console, arguments);
	} else {
        for (var i = 0; i < arguments.length; i++) {
			core.debug(arguments[i]);
		}
	}

    return msg;
};


/**
 * Função Privada
 */
core._debug = function(msg){
    var debug = core.findById("core-debug");
    
    if (!debug)
        debug = core.findById("dwr-debug");
    
    if (debug) {
		var contents = ("").concat(msg) + "<br/>" + debug.innerHTML;
		if (contents.length > 2048) contents = contents.substring(0, 2048);
		debug.innerHTML = contents;
    }
};


/**
 * registra uma chamada remota no Core
 * e declara uma variavel no escopo
 * com o nome especificado
 * @param fullName
 * @param config
 */
core.declareCall = function (fullName, config, context){
	return core.setObject(fullName, this.registerCall(fullName, config), context);
};


/**
 * registra uma chamada remota no Core
 * @param fullName
 * @param config
 */
core.registerCall = function (fullName, config){
	config = core.mixin({}, config);
	config.core = core;
	config.fullName = fullName;
	if (!config.sync) config.sync = false;
	if (!config.method) config.method = "POST";
	if (!config.params) config.params = [];
	if (!config.invoke) config.invoke = core._noInvokeToCall;

	if (!config.procedure) {
		config.procedure = fullName;
		var i = config.procedure.lastIndexOf(".");
		if (i != -1) config.procedure = config.procedure.substring(i+1);
	}
	
	var func = function(params, handler){
		var args = config.core._toArray(arguments);
		var hdl = args.pop();
		if (!hdl.callback) hdl.callback = function (){};
		if (!hdl.onError) hdl.onError = hdl.exceptionHandler;
		if (!hdl.onError) hdl.onError = config.core.tratarErroAjax;
		hdl.exceptionHandler = hdl.onError;
		args.unshift(config, hdl);
		return config.invoke.apply(this || config.core, args);
	};
	
	core.mixin(func, {
		config: config,
		toString: function(){
			var str = "\nfunction " + this.config.procedure + "(";
			for (var i=0; i<this.config.params.length; i++)
				str += this.config.params[i] += ", ";
			return str + "handler) {\n    [native code]\n}\n";
		}
	});
	
	core.calls[fullName] = func;
	return func;
};


/**
 * Função Privada
 */
core._noInvokeToCall = function(config, handler, args){
	try {
		throw "Chamada remota indisponível ou não suportada: " + config.fullName;
	} catch (ex){
		handler.onError(ex.message, ex);
	}
};


/**
 * Função Privada
 */
core._toArray = function(){
	var res = [];
	var args;
	for (var j = 0; j < arguments.length; j++) {
		args = arguments[j];
		for (var i = 0; i < args.length; i++) {
			res.push(args[i]);
		}
	}
	return res;
};


/**
 * obtém um arquivo carregado remotamente
 * @param method
 * @param args
 * @param hasBody
 * @return dfd
 */
core.xhr = function(method, args, hasBody){
	if (dojo && dojo.xhr)
		return dojo.xhr(method, args, hasBody);
	else
		throw "Não implementado: \"core.xhr\", requer DOJO";
};


/**
 * Método responsável por tratar exceptions
 * causadas por pesquisas com chamada remota
 */
core.tratarErroAjax = function(message, ex){
	if (!message)
		message = ex.message;
    if (!message)
        message = "Ocorreu um erro interno no servidor.";
    else 
    if (message.indexOf && message.indexOf("0x80040111") != -1) 
        message = "Ocorreu um erro interno durante o processamento.";	// exception interna de JavaScript //
    
    core.debug("Exception: " + ex.name + ", " + ex.message, core.tratarErroAjax);
    alert(message);
};


/**
 * carrega um arquivo stylesheet ou javascript se já não carregado
 * @param name
 * @param file
 * @param sync - opcional - default False
 * @param type - opcional {stylesheet|javascript}
 */
core.load = function(name, file, sync, type){
	if (arguments.length == 1) file = name;
	file = this.parseString(file);
	if (!name) name = file;
	if (this.hasResource[name]) return;
	var error = function(err){
		alert(
		//throw 
		"Não foi possível carregar o módulo: " + name + "\n" + (err && err.message ? err.message : err)
		);
	};
	var ext;
	switch (type | ""){
		case "stylesheet":
			ext = "css";
			break;
		case "javascript":
			ext = "js";
			break;
		default:
			var ext = file.lastIndexOf(".");
			ext = ext != -1 ? file.substring(ext+1) : "";
	}
	ext = ext.toLowerCase();
	switch (ext){
		case "css":
			if (!sync)
			try {
				var style = document.createElement("link");
				style.type = "text/css";
				style.rel = "stylesheet";
				style.href = file;
				var target = document.getElementsByTagName("head")[0];
				if (!target) target = document.getElementsByTagName("body")[0];
				if (!target) target = document.getElementsByTagName("html")[0];
				target.appendChild(style);
				return;
			} catch (ex){
				error(ex);
			}
			type = "stylesheet";
			break;
		case "js":
			if (!sync)
			try {
				var script = document.createElement("script");
				script.type = "text/javascript";
				script.src = file;
				var target = document.getElementsByTagName("head")[0];
				if (!target) target = document.getElementsByTagName("body")[0];
				if (!target) target = document.getElementsByTagName("html")[0];
				target.appendChild(script);
				return;
			} catch (ex){
				error(ex);
			}
			type = "javascript";
			break;
		default:
			error("Tipo de arquivo desconhecido");
	}

	var xhr = {};
	xhr.core = this;
	xhr.window = window;
	xhr.load = function(data){
		try {
			switch (type) {
				case "stylesheet":
					var style = document.createElement("style");
					style.type = "text/css";
					style.innerHTML = data;
					var target = document.getElementsByTagName("head")[0];
					if (!target) target = document.getElementsByTagName("body")[0];
					if (!target) target = document.getElementsByTagName("html")[0];
					target.appendChild(style);
					break;
				case "javascript":
					xhr.window.eval(data);
					break;
			}
			xhr.core.hasResource[name] = true;
		} catch (ex){
			xhr.destroy();
			error(ex);
		}
		xhr.destroy();
		return data;
	};
	xhr.request = {
		url: file,
		handleAs: "text",
		sync: true,
		load: xhr.load,
		error: function(err){
			xhr.destroy();
			error(err);
		}
	};
	xhr.destroy = function(){
		delete xhr.dfd;
		delete xhr.request;
		delete xhr;
	};	
	xhr.dfd = this.xhr("GET", xhr.request);
};


/**
 * carrega um arquivo stylesheet ou javascript se já não carregado
 * relativo ao diretório das Libs
 * @param file
 * @param sync - opcional - default False
 * @param type - opcional {stylesheet|javascript}
 */
core.loadLib = function(file, sync, type){
	if (arguments.length == 1)
		return this.load(this.libURL + arguments[0]);
	else
		return this.load(null, this.libURL + file, sync, type);
};


/**
 * carrega um arquivo stylesheet ou javascript
 * se já não carregado de forma sincrona 
 * @param name
 * @param file
 * @param type - opcional {stylesheet|javascript}
 */
core.require = function(name, file, type){
	if (arguments.length == 1)
		return this.load(null, arguments[0], true, null);
	else
		return this.load(name, file, true, type);
};


/**
 * carrega um arquivo stylesheet ou javascript se já não carregado
 * de forma sincrona relativo ao diretório das Libs
 * @param file
 * @param type - opcional {stylesheet|javascript}
 */
core.requireLib = function(file, type){
	if (arguments.length == 1)
		return this.loadLib(arguments[0], true, null);
	else
		return this.loadLib(file, true, type);
};


/**
 * Função Privada
 */
core._getProp = function(_1c, _1d, _1e){
    var obj = _1e || this.window;
    for (var i = 0, p; obj && (p = _1c[i]); i++) {
        obj = (p in obj ? obj[p] : (_1d ? obj[p] = {} : undefined));
    }
    return obj;
};


/**
 * Função Utilitária
 */
core.setObject = function(name, value, context){
    var a = name.split("."), p = a.pop(), obj = this._getProp(a, true, context);
    return obj && p ? (obj[p] = value) : undefined;
};


/**
 * Função Utilitária
 */
core.getObject = function(name, create, context){
    return this._getProp(name.split("."), create, context);
};


/**
 * Função Utilitária
 */
core.exists = function(_2b, obj){
    return !!this.getObject(_2b, false, obj);
};


/**
 * Função Utilitária
 */
core.mixin = function(obj, _19){
    for (var i = 1, l = arguments.length; i < l; i++) {
        this._mixin(obj, arguments[i]);
    }
    return obj;
};


/**
 * Função Privada
 */
core._mixin = function(obj, model){
    var a = {};
    for (var x in model) {
        if (a[x] === undefined || a[x] != model[x]) {
            obj[x] = model[x];
        }
    }
    if (this.isIE && model) {
        var p = model.toString;
        if (typeof p == "function" && p != obj.toString && p != a.toString && p != "\nfunction toString() {\n    [native code]\n}\n") {
            obj.toString = model.toString;
        }
    }
    return obj;
};


/**
 * Função Privada
 */
core._setup = function(){
	if (this.window.location) {
		this.baseURL = (this.window.location.pathname || "");
		var m = this.baseURL.lastIndexOf("/");
		if (m != -1) this.baseURL = this.baseURL.substring(0, m + 1);
		this.coreURL = this.baseURL;
		this.libURL = "/lib/";
	}
	
    if (this.document.getElementsByTagName) {
        var tags = this.document.getElementsByTagName("script");
        var coreName = /(^|\/)core\.js(\W|$)/i;
        for (var i = 0; i < tags.length; i++) {
            var src = tags[i].getAttribute("src");
            if (!src) continue;
			var m = src.match(this.masks.CoreFileName);
            if (m) {
                this.coreURL = src.substring(0, m.index) + "/";
				this.libURL = this.coreURL + "../";
                break;
            }
        }
    }
	
    var n = navigator;
    var dua = n.userAgent;
    var dav = n.appVersion;
    var tv = parseFloat(dav);
    if (dua.indexOf("Opera") >= 0) {
        this.isOpera = tv;
    }
    var _84 = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
    if (_84) {
        this.isSafari = parseFloat(dav.split("Version/")[1]) || (parseFloat(dav.substr(_84 + 7)) > 419.3) ? 3 : 2;
    }
    if (dua.indexOf("AdobeAIR") >= 0) {
        this.isAIR = 1;
    }
    if (dav.indexOf("Konqueror") >= 0 || this.isSafari) {
        this.isKhtml = tv;
    }
    if (dua.indexOf("Gecko") >= 0 && !this.isKhtml) {
        this.isMozilla = this.isMoz = tv;
    }
    if (this.isMoz) {
        this.isFF = parseFloat(dua.split("Firefox/")[1]) || undefined;
    }
    if (this.document.all && !this.isOpera) {
        this.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
    }
	
	if (this.isIE) this.docClass += " isIE isIE_" + this.isIE;
	if (this.isMozilla) this.docClass += " isMozilla isMozilla_" + this.isMozilla;

	var html = this.document.getElementsByTagName("html")[0];	
	html.className = this.ltrim(html.className + core.docClass);

	this.internal.loaded = 0;	
	this.window.setTimeout(function(){
		core.internal.loaded++;
		if (core.document.body) {
			if (core.onload)
				core.onload();
		} else { 
			if (core.internal.loaded < 10 || (core.onload && core.internal.loaded < 50)) 
				this.window.setTimeout(arguments.callee, 0);
		}
	},0);
};


/**
 * atribuições de inicialização
 */
(function (){
	core.mixin(core, {
		hasResource: {core: true},
		window: window,
		document: document,
		baseURL: "",
		coreURL: "",
		docClass: "",
		noError: function(){},
		onload: function(){},
		calls: {},
		masks: {
			Quote: /"/g,
		    LTrim: /^\s+/,
		    RTrim: /\s+$/,
		    Float: /^-{0,1}\d*\,{0,1}\d+$/,
		    Currency: /^-{0,1}\d{1,3}(\.\d\d\d)+\,{0,1}\d+$/,
			CoreFileName: /(^|\/)core\.js(\W|$)/i
		}
	});	
	
	$ = core.find;
	if (window.dwr && window.dwr.engine){
	    window.dwr.engine.setErrorHandler(core.tratarErroAjax);
	}
	
	core._setup();
})();}