
/** ==================================================
  * Transforma um mapa em uma String para ser usada em uma url
  * @param vars Array|Object Mapa de valores
  * @return String
  ==================================================  */

function urlEncode(vars) {
	var query = ""
	var first = true
	for(var i in vars) {
		if(first) {
			first = false
		}else{
			query += "&"
		}
		var key = escape(i)
		var value = escape(vars[i])
		query += key + "=" + value
	}
	return query
}


/** ==================================================
 * Cria um objeto nativo XMLHttpRequest dependento do browser
 * @return Objeto XMLHttpRequest Para a versão do browser | null se não conseguir criar
 * @internal O HttpRequest pode ser usado apenas uma vez,
 * para executar outra requisição, basta criar um novo.
================================================== */

function HttpRequest() {
	try {
		return new ActiveXObject("Msxml2.XMLHTTP")
	} catch (e) {}

	try {
		return new ActiveXObject("Microsoft.XMLHTTP")
	} catch (e) {}

	try {
		return new XMLHttpRequest()
	} catch (e) {}

	return null
}


/** ==================================================
 * classe Ajax
 @methods
	clearHeaders()
	clearParams()
	setRequestHeader(name, value)
	setParam(name, value)
	get()
	post(data)
	abort()
	getResponseHeader(name)
	getAllResponseHeaders()
================================================== */

function Ajax(url, onResult, onAbort) {
	this.url = new String(url == undefined ? "" : url)
	// Aborta a requisição automaticamente após 15 segundos
	this.timeOutLimit = 15000
	// timeOut callback
	this.timeOut = null
	// Objeto XMLHttpRequest
	this.request = null

	if (onAbort instanceof Function)
		this.onAbort = onAbort

	if (onResult instanceof Function)
		this.onResult = onResult

	this.clearParams()
	this.clearHeaders()
}

/**
 * Limpa os cabecalhos atribuidos
 */
Ajax.prototype.clearHeaders = function() {
	this.headers = {};
}

/**
 * Limpa os parametros atribuidos
 */
Ajax.prototype.clearParams = function() {
	this.params = {};
}

/**
 * virtual function que deve ser substituida por uma funcao customizada
 * @param req Objeto request
 * @param timer Objeto timer com o timestamp da requisicao, final e elapse
 */
Ajax.prototype.onResult = function(req, timer) {}
Ajax.prototype.onAbort = function(req, timer) {}

Ajax.prototype.setRequestHeader = function(name, value) {
	this.headers[name] = value
}

Ajax.prototype.setParam = function(name, value) {
	this.params[name] = value
}

/**
 * Executa a requisição utilizando o método HTTP GET
 * @internal O objeto XmlHttpRequest pode ser usado apenas uma vez.
 * por isso ele é criado a cada requisição get ou post
 * @internal Todoa requisição faz um abort na requisição anterior
**/
Ajax.prototype.get = function() {
	this.abort()
	this.request = AJAX.get(this.url, this.onResult, this.params, this.headers)
	this.setTimeOut()
}

/**
 * Executa a requisição utilizando o método HTTP POST
 * @internal O objeto XmlHttpRequest pode ser usado apenas uma vez.
 * por isso ele é criado a cada requisição get ou post
 * @internal Todoa requisição faz um abort na requisição anterior
**/
Ajax.prototype.post = function(data) {
	this.abort()
	data = data == undefined ? null : data
	this.request = AJAX.post(this.url, this.onResult, data, this.headers)
	this.setTimeOut()
}

/**
 * Cancela uma requisição e dispara o evento onAbort
**/
Ajax.prototype.abort = function() {
	if(this.request && this.request.readyState != 4) {
		this.request.onreadystatechange = function(){};
		this.request.abort();
		this.onAbort(this)
		this.request = null;
	}
	this.clearTimeOut()
}

/**
 * @pattern Adapter para o método interno do XmlHttpRequest
 */
Ajax.prototype.getResponseHeader =  function(name) {
	return this.request.getResponseHeader(name)
}

/**
 * @pattern Adapter para o método interno do XmlHttpRequest
 * @return string exatamente como o cabeçalho HTTP
 */
Ajax.prototype.getAllResponseHeaders = function() {
	return this.request.getAllResponseHeaders()
}

/**
 * @access private
**/
Ajax.prototype.setTimeOut = function() {
	if(this.timeOutLimit > 0) {
		var parent = this
		this.timeOut = setTimeout(function() { parent.abort() }, this.timeOutLimit)
	}
}

/**
 * @access private
**/
Ajax.prototype.clearTimeOut = function() {
	if(this.timeOut)
		clearTimeout(this.timeOut)
	this.timeOut = null
}

/** ==================================================
 * AjaxBind
================================================== */

function AjaxBind(url, src, dest, trigger, event) {
	var ajax = new Ajax(url)

	var s = $(src)
	var d = $(dest)
	var t = $(trigger)

	this.exec = function() {
		ajax.params[s.name] = s.value
		ajax.get()
	}

	ajax.onResult = function(req, timer) {
		if(d.value === undefined)
		{
			d.innerHTML = req.responseText;
		}
		else
		{
			d.value = req.responseText
		}
	}

	$addEvent(t, event, this.exec)
}


/** ==================================================
 * Funcoes para uso estatico
================================================== */

function AJAX() {}

AJAX.create = function(onResult, timer) {
	var req = new HttpRequest()
	timer = timer == undefined ? {} : timer
	timer.startTime = 0
	timer.stopTime = 0
	timer.elapsedTime = 0
	timer.toString = function() {
		return "[" + this.startTime + ", " + this.stopTime + ", " + this.elapsedTime + "]"
	}
	/*
	0 UNINITIALIZED open() has not been called yet.
	1 LOADING send() has not been called yet.
	2 LOADED send() has been called, headers and status are available.
	3 INTERACTIVE Downloading, responseText holds the partial data.
	4 COMPLETED Finished with all operations.
	*/
	req.onreadystatechange = function() {
		// status não existe no IE, até readyState for igual à 4
		try {
			if (req.readyState == 4 && req.status == 200) {
				timer.stopTime = new Date().getTime()
				timer.elapsedTime = timer.stopTime - timer.startTime
				if (onResult) onResult(req, timer)
			}
		} catch(e) {}
	}
	return req
}

AJAX.generateUID = function() {
	return "ajaxUID=" + new String(new Date().getTime()) + new String(Math.random())
}

AJAX.get = function(url, onResult , vars, headers) {
	var timer = {}
	var req = AJAX.create(onResult, timer)

	var query = urlEncode(vars)
	if (query != "") {
		url += "?" + query
	}

	timer.startTime = new Date().getTime()

	var uid = AJAX.generateUID();
	url += (url.indexOf("?") == -1) ? "?" + uid : "&" + uid

	req.open("GET", url, true)

	AJAX.setHeaders(req, headers) // precisa ser depois do open

	req.send(null)
	return req
}

AJAX.post = function(url, onResult, data, headers) {
	var timer = {}
	var req = AJAX.create(onResult, timer)

	timer.startTime = new Date().getTime()

	var uid = AJAX.generateUID();

//	url += (url.indexOf("?") == -1) ? "?" + uid : "&" + uid
	req.open("POST", url, true)

	AJAX.setHeaders(req, headers) // precisa ser depois do open

	timer.startTime = new Date().getTime()

	req.send(data)
	return req
}

AJAX.setHeaders = function(req, headers) {
	if (! headers) return false

	for(var name in headers) {
		var value = headers[name]
		req.setRequestHeader(name, value)
	}
	return true
}

AJAX.setInnerHtml = function(url, id, params)
{
	function onResult(req)
	{
		var d = $(id)
		if(d.value === undefined)
		{
			d.innerHTML = req.responseText
		}
		else
		{
			d.value = req.responseText
		}
	}
	var ajax = new Ajax(url, onResult)
	ajax.params = typeof params == "object" ? params : {}
	ajax.get()
	return ajax
}