/**
 *@Autor Samuel Herrmann
 *@Patterns
 *  - Sempre ser? utilizado o caracter "_" em fun??es que n?o devem ser usadas fora do escopo do js
 *  - Em variaveis que o escopo seja apenas da fun??o o nome da variavel ser? "nomeVariavel_nomeFun?ao"
 */  

	/**
	 * Variaveis Globais que ser?o utilizadas pelo ajax
	 */
 	//Array com o idName dos construtores do ActiveXObject
	var ajaxObjectTypes = ["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
	//Utilizado para codificar/descodificar string no formato base64
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	
	//Erros
	var exception_create = "N?o foi poss?vel criar o objeto ActiveXObject";
	var exception_callBack = "A propriedade \"callBack\" n?o pode ser nulla";
	var exception_url = "A propriedade \"url\" n?o pode ser nulla";

	/**
	 *Construtor do objeto Ajax uníco
	 *@param <B>url</B> endere?o que deseja fazer a requisi??o
	 *@param <B>callBack</B> nome da fun??o que receber? o retorno da requisi??o. ex: "NomeFuncao_cb"
	 *@param <B>data</B> dados a serem enviados
	 *@param <B>method</B> method que deseja enviar os dados (GET ou POST)
	 *@return <B>Ajax<B>
	 */
	function AjaxSamples(url,callBack,data,method) {
		//Variaveis
		this.method = method;
		this.url = url;
		this.data = data;
		this.callBack = callBack;
		this.isMultiple = false;
		//Methods Getters & Setters
		this.setMethod = _ajaxSamples_setMethod;
		this.setUrl = _ajaxSamples_setUrl;
		this.setData = _ajaxSamples_setData;
		this.setCallBack = _ajaxSamples_setCallBack;
		this.getMethod = _ajaxSamples_getMethod;
		this.getUrl = _ajaxSamples_getUrl;
		this.getData = _ajaxSamples_getData;
		this.getCallBack = _ajaxSamples_getCallBack;
		
		
		//Implementa??o da fun??o send
		this.send = function () {
			var ajaxObject_send = _createActiveXObject(ajaxObjectTypes);
			if (this.method == undefined || (this.method.toUpperCase() != "POST"
				&& this.method.toUpperCase() != "GET"))
					this.method = "GET";
			if (this.url == undefined) {
				alert(exception_url);
				return;
			}
			if (this.callBack == undefined) {
				alert(exception_callBack);
				return;
			}
			var ajaxSamples = this;
			ajaxObject_send.open(this.method,this.url,true);
			ajaxObject_send.onreadystatechange = function() {
					if (ajaxObject_send.readyState == 4)
						if (ajaxSamples.isMultiple)
							eval("_ajaxMultiple_callBack_cb(decode64(ajaxObject_send.responseText),ajaxSamples.callBack);");
						else
							eval(ajaxSamples.callBack + "_cb(decode64(ajaxObject_send.responseText));");
				}
			//Convers?es para o envio dos dados, se houver dados
			if (this.data != undefined && this.data != null) {
				if (typeof this.data == "string")
					ajaxObject_send.send(encode64(this.data));	
				else if (typeof this.data == "object") {
				
				}
			}else
				ajaxObject_send.send(null);
		}
	}

	var _ajaxMultiple_sunAjaxSamples = 0;
	var _ajaxMultiple_endOfProcess;

	function AjaxMultiple() {
		//Variaveis
		this.arrayAjax = new Array();
		this.endOfProcess;
		//Methods Getters & Setters
		this.getEndOfProcess = _ajaxMultiple_getEndOfProcess;
		this.setEndOfProcess = _ajaxMultiple_setEndOfProcess;
		this.addAjax = function (ajaxSamples) {
			this.arrayAjax[this.arrayAjax.length] = ajaxSamples;
			ajaxSamples.isMultiple = true;
		}
		this.removeAll = function () {
			for(x = this.arrayAjax.length - 1; x >= 0; x--)
				this.arrayAjax[x] = null;
			this.arrayAjax.length = 0;
		}
		this.sendAll = function () {
			_ajaxMultiple_sunAjaxSamples = this.arrayAjax.length;
			_ajaxMultiple_endOfProcess = this.endOfProcess;
			for(x = this.arrayAjax.length - 1; x >= 0; x--)
				this.arrayAjax[x].send();
		}
	}

	function _ajaxMultiple_callBack_cb(responseData,callBackSelected) {
		eval(callBackSelected + "_cb(responseData)");
		_ajaxMultiple_sunAjaxSamples--;
		if (_ajaxMultiple_sunAjaxSamples == 0)
			eval(_ajaxMultiple_endOfProcess + "()");
	}

	/**
	 *Cria uma instancia do ActiveXObject utilizando um dos construtores informados
	 *@param <B>idNames</B> array com os idNames dos construtores
	 *@return <B>ajax</B> nova instancia do ActiveXObject
	 *@escopo PRIVATE
	 */
	function _createActiveXObject(idNames) {
		var ajaxReturn__createActiveXObject = null;
		if (window.XMLHttpRequest) {
	        ajaxReturn__createActiveXObject = new XMLHttpRequest();
		} else if (window.ActiveXObject)
			for (var x__createActiveXObject = idNames.length - 1; x__createActiveXObject > - 1; x__createActiveXObject--) {
				try {
					ajaxReturn__createActiveXObject = new ActiveXObject(idNames[x__createActiveXObject]);
					break;			
			}catch(e) { }
		}
		if (ajaxReturn__createActiveXObject == null) 
			alert(exception_create);
		return ajaxReturn__createActiveXObject;
	}
	/**
	 * Methods GETTERS & SETTERS do objeto AjaxSamples
	 */
	function _ajaxSamples_setMethod(method) {
		this.method = method;
	}
	function _ajaxSamples_getMethod() {
		return this.method;
	}
	function _ajaxSamples_setUrl(url) {
		this.url = url;
	}
	function _ajaxSamples_getUrl() {
		return this.url;
	}
	function _ajaxSamples_setData(data) {
		this.data = data;
	}
	function _ajaxSamples_getData() {
		return this.data;
	}
	function _ajaxSamples_setCallBack(callBack) {
		this.callBack = callBack;
	}
	function _ajaxSamples_getCallBack() {
		return this.callBack;
	}
	/**
	 * Methods GETTERS & SETTERS do objeto AjaxMultiple
	 */
	function _ajaxMultiple_setEndOfProcess(endOfProcess) {
		this.endOfProcess = endOfProcess;
	}
	function _ajaxMultiple_getEndOfProcess() {
		return this.endOfProcess;
	}
	/** Fun??o que converte uma String em Base64
	 *@param <B>input</B> String que voc? deseja converter
	 *@return <B>base64</B> Retorna a string em seu novo formato 
	 */

	function encode64(input) {
	   var output = "";
	   var chr1, chr2, chr3;
	   var enc1, enc2, enc3, enc4;
	   var i = 0;
	
	   do {
	      chr1 = input.charCodeAt(i++);
	      chr2 = input.charCodeAt(i++);
	      chr3 = input.charCodeAt(i++);
	
	      enc1 = chr1 >> 2;
	      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
	      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
	      enc4 = chr3 & 63;
	
	      if (isNaN(chr2))
	         enc3 = enc4 = 64;
	      else if (isNaN(chr3))
	         enc4 = 64;
	
	      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + 
	      keyStr.charAt(enc3) + keyStr.charAt(enc4);
	   }while (i < input.length);
	   return output;
	}
	/** Fun??o que descodifica uma String em Base64
	 *@param <B>input</B> String que voc? deseja desconverter
	 *@return <B>base64</B> Retorna a string em seu novo formato
	 */
	
	function decode64(input) {
	   var output = "";
	   var chr1, chr2, chr3;
	   var enc1, enc2, enc3, enc4;
	   var i = 0;
	
	   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	
	   do {
	      enc1 = keyStr.indexOf(input.charAt(i++));
	      enc2 = keyStr.indexOf(input.charAt(i++));
	      enc3 = keyStr.indexOf(input.charAt(i++));
	      enc4 = keyStr.indexOf(input.charAt(i++));
	
	      chr1 = (enc1 << 2) | (enc2 >> 4);
	      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
	      chr3 = ((enc3 & 3) << 6) | enc4;
	
	      output = output + String.fromCharCode(chr1);
	
	      if (enc3 != 64)
	         output = output + String.fromCharCode(chr2);
	      if (enc4 != 64)
	         output = output + String.fromCharCode(chr3);
	   } while (i < input.length);
	   return output;
	}
