var autoSGSGeocode = Class.create({
	//input  = nome ou instancia do input
	//mode = 'address' , 'city' , default: address
	//container = nome ou instancia da div, que ira apresentar os candidatos, caso prefeira personalizar ou nao usar os candidatos, nao passe elemento algum.
	//startTime = tempo inicial do observer, agir, default =  0.5
	//startLength = tamanho minimo para inciar, default : 2
	//ignoreValue = valor para ignorar, default: ""
	//connectionType = 1: Ajax normal, 2: Ajax CrossDomain, 3: Gadgets Mode, default: 1
	//objName = nome da instancia do objeto, usado em conjunto ao connectioType 2, default: ""
	initialize: function(input, mode, container, startTime, startLength, ignoreValue, connectionType, objname) {
		
		if(typeof input == 'string' && input != "")
			this.input = $(input);
		else if(typeof input == 'object' && input != "")
			this.input = input;
		else {
			alert("autoSGSGeocode: input de entrada n�o est� definido.");
			return false;
		}
		
		switch(mode) {
			case 'city',"2",2:
				this.mode = 2;
			break;
			default :
				this.mode = 1;
		}

		if(typeof container == 'string' && container != "")
			this.container = $(container);
		else if(typeof container == 'object' && container != "")
			this.container = container;

		if (typeof this.container != "undefined" && this.container != "") {
			this.open = false;
			this.container.innerHTML = "";
			$(this.container).hide();
			if (this.input.attachEvent) 
		   		this.input.attachEvent("onkeydown", this.onKeyDown.bind(this));
		 	else 
				this.input.onkeydown = this.onKeyDown.bind(this);
 		}

		if(typeof startTime == 'number')
			this.startTime = startTime;
		else
			this.startTime = 0.5;

		if(typeof startLength == 'number')
			this.startLength = startLength;
		else
			this.startLength = 2;
			
		if(typeof ignoreValue == 'string' && ignoreValue != "")
			this.ignoreValue = ignoreValue;
		else
			this.ignoreValue = "";
		
		switch(connectionType) {
			case '2', 2:
				this.requestType = 2;
				if(typeof objname == 'string' && objname != "")
					this.objname = objname;
				else {
					alert("autoSGSGeocode: objname n�o est� definido em modo ajax crossdomain.");
					return false;
				} 
			break;
			case '3', 3:
				this.requestType = 3;
			break;
			default :
				this.requestType = 1;
			break;
		}
		
		
		/*** urls de chamadas ***/
		this.urlAdressSGS = URLHOST + '/memorygeocode/request?function=addsugg&v=1';
		this.urlCitySGS = URLHOST + '/memorygeocode/request?function=citysugg&v=1';
		this.urlGeocoding = URLHOST + '/memorygeocode/request?function=geo&v=1';
		/*** valores internos ***/
		this.observer = null;
		this.result = new aptAddress("","","","","","","","","","");
		this.candidates = new Array();
		this.verify = false;
		this.cityInstance = null;
		this.formatedCity = "";
		this.formatedState = "";
		this.formatedValue = "";
		this.formatedNumber = 0;
		this.wishline = 0;
		this.keyNum = 0;
		this.pars = {};
		/*Valores unicos*/
		this.firstStart = true;
		/*Atributos especiais*/
		this.defaultCity = "";
		this.defaultState = "";
		this.formatedCountry = "BR"; //martelado
		this.autoGeocode = false;
		this.autoSelection = true;
		this.autoReplaceNumber = true;
		this.trHeadStyle = { backgroundColor: "#ccc", fontWeight: "bold"};
		this.trOverBackground = "#E8EFFB";
		this.matchColor = "#FFF699";
	},
	//cityInstance, em caso de endereco, e 1 start, deve se passar a instancia da cidade, ou setar anterioramente uma cidade padrao
	start: function(cityInstance){
		//verifica cidade padrao em caso de endereco
		if(typeof cityInstance == 'object' && typeof cityInstance != "undefined" && this.firstStart && this.mode == 1) {
			this.cityInstance = cityInstance;
			this.firstStart = false;
		} else if (this.firstStart && this.mode == 1 && this.defaultCity == "" && this.defaultState == ""){
			alert("autoSGSGeocode: instancia da cidade padr�o n�o est� definida.");
			return false;
		} else
			this.firstStart = false;

		//instancia o observer
		if(this.observer == null) 
			this.observer = new Form.Element.Observer(this.input, this.startTime, this.sgs.bind(this));
		
	},
	stop: function(){
		//para o observer, se ele exisitr
		if(this.observer != null) 
			this.observer.stop();
		this.observer = null;
		this.reset(true);
	},
	//seta o valor interno em base do aptaddress da entrada, verified (boolean), se passado vai assumir o estado dele, caso contrario, true
	setValue: function(aptAddress,verified) {
		this.stop();
		this.result = aptAddress;
		switch(this.mode){
			case 2:
				this.input.value = aptAddress.toStrCityState();
			break;
			default:
				var placeValue = aptAddress.toStrStreetNum().split(",");
				try {
					var value = placeValue[0].removeAccents();
					var number = parseInt(placeValue[1]);
				} catch(e) {
					var value = placeValue[0].removeAccents();
					var number = 0;
				}
				
				if (typeof number != 'number' || isNaN(number))
					number = 0;
				this.input.value = value.trim().toString() + ", " + number;
			break;
		}
		if (typeof verified != "undefined")
			this.verify = verified;
		else
			this.verify = true;
		this.start();
	},
	//reseta as variaveis interna de controla, value (boolean) : limpa endereco tambem
	reset: function(value) {
		this.result = new aptAddress("","","","","","","","","","");
		this.formatedCity = "";
		this.formatedState = "";
		this.formatedValue = "";
		this.formatedNumber = 0;
		this.candidates = new Array();
		this.verify = false;
		this.pars = {};
		if (value) {
			this.input.value = "";
		}
		if (typeof this.container != "undefined") {
			this.open = false;
			this.container.innerHTML = "";
			$(this.container).hide();
			this.keyNum = 0;
			this.wishline = 0;
		}
		if(typeof this.callBackReset != "undefined" && this.callBackReset != '')
			this.callBackReset();
	},
	sgs: function(el,value){
		//executa o observer de change value, caso detecte que os valores interno estao diferente, executa, respectivos ajax, para obter inforamcao
		this.reset();
		this.format();
		switch(this.mode){
			case 2:
				if (value.length > this.startLength && this.result.city.trim().toString() != this.formatedCity.trim().toString() && value.trim().toString().toUpperCase() != this.ignoreValue.trim().toString().toUpperCase())
					this.ajaxSGS({cityState: this.formatedCity, country: this.formatedCountry},this.urlCitySGS,this.sgsCityEnd.bind(this));
			break;
			default:
				//verifica cidade, caso merdeado, abortCity
				if(this.formatedCity == "" && this.formatedState == "") {
					if(typeof this.callBackCityAbort != "undefined" && this.callBackCityAbort != '')
					 	this.callBackCityAbort();
				} else if (value.trim().toString().toUpperCase() != this.ignoreValue.trim().toString().toUpperCase() && value.length > this.startLength  && (this.result.street != this.formatedValue || this.result.city != this.formatedCity || this.result.state != this.formatedState))
					this.ajaxSGS({street: this.formatedValue , number: this.formatedNumber , city: this.formatedCity, state: this.formatedState, country: this.formatedCountry},this.urlAdressSGS,this.sgsAddressEnd.bind(this));
					
			break;
		}
	},
	//private
	format: function() {
		//formata as variaveis entradas, dependo do tipo da instancia
		switch(this.mode){
			case 2:
				//detecta os valores de cidade
				try {
					var placeCity = this.input.value.split(",");
					try {
						var city = placeCity[0].removeAccents();
						var state = placeCity[1].removeAccents();
					} catch(e) {
						try {
							var city = placeCity[0].removeAccents();
							var state = this.defaultState;
						} catch(e) {
							var city = this.defaultCity;
							var state = this.defaultState;
						}
					}

					if (city.trim() == "")
						city = this.defaultCity;

					if (state.trim() == "")
						state = this.defaultState;

					this.formatedCity = city.trim().toString();
					this.formatedState = state.trim().toString();
				} catch(e) {
					this.formatedCity = this.defaultCity;
					this.formatedState = this.defaultState;
				}
			break;
			default:
				//detecta os valores de cidade
				if(typeof this.cityInstance == 'object' && typeof this.cityInstance != "undefined" && this.cityInstance != null) {
					//esta por cityInstance

					//auto candidates
					if (typeof this.cityInstance.container != "undefined" && typeof this.cityInstance.container == 'object' && this.cityInstance.container != "")
						$(this.cityInstance.container).hide();

					if (this.cityInstance.verify) {
						this.formatedCity = this.cityInstance.result.city;
	   					this.formatedState = this.cityInstance.result.state;
					} else {
						this.formatedCity = "";
	   					this.formatedState = "";
					}
					
					//set
				} else {
					//esta por defaultCity
					this.formatedCity = this.defaultCity;
					this.formatedState = this.defaultState;
				}

   				//detecta os valores do endereco
   				try {
   					var placeValue = this.input.value.split(",");
   					try {
   						var value = placeValue[0].removeAccents();
   						var number = parseInt(placeValue[1]);
   					} catch(e) {
   						try {
   							var value = placeValue[0].removeAccents();
   							var number = 0;
   						} catch(e) {
   							var value = "";
   							var number = 0;
   						}
   					}
   				
   					if (typeof number != 'number' || isNaN(number))
   						number = 0;
   				
   					this.formatedValue = value;
   					this.formatedNumber = number;
   				} catch(e) {
   					this.formatedValue = "";
   					this.formatedNumber = 0;
   				}

			break;
		}
	},
	//private
	ajaxSGS: function(pars,url,objResponse) {
		if(typeof this.callBackStart != "undefined" && this.callBackStart != '')
			 this.callBackStart();
			
		switch(this.requestType) {
			case '2', 2:
				aptScript(url + '?' + Object.toQueryString(pars) + '&wt=apt&call=' + this.objname);
			break;
			case '3', 3:
				var params = {};
			  	var postdata = gadgets.io.encodeValues(pars);
			  	params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
			  	params[gadgets.io.RequestParameters.POST_DATA]= postdata;
			  	gadgets.io.makeRequest(url, objResponse, params);
			break;
			default:
		  		if (typeof this.ajaxObj != "undefined")
		  			if(this.ajaxObj.transport.readyState != 4)
		  				this.ajaxObj.transport.abort();
				this.ajaxObj = new Ajax.Request(url, { method:'get', parameters: pars, onSuccess: objResponse });
			break;
		}
	},
	//private
	sgsAddressEnd: function(response) {
		//end do sgs endereco
		if(response.responseText)
			var Holder = eval('(' + response.responseText + ')');
		else
			var Holder = response;
		if(Holder.length > 0) {
			for(var i = 0; i < Holder.length; i++)
				this.candidates[i] =  new aptAddress (this.formatedCountry, this.formatedState, this.formatedCity, Holder[i].district, Holder[i].name, this.formatedNumber, '', '', '', Holder[i].streetid);
			
			if(typeof this.callBackChanged != "undefined" && this.callBackChanged != '')
				this.callBackChanged();
		
			if (typeof this.container != "undefined" &&  this.container != "") {
				
				var table = new aptElement([
						{ tag : 'table', style: {width: "100%", border: "0"}, childs : [
							{ tag: 'tbody',  childs: [
								{ tag: 'tr',  style: this.trHeadStyle ,childs: [
									{tag: 'td', width: "60%", innerHTML: "Endere&ccedil;o "},
									{tag: 'td', width: "10%", innerHTML: "N. "},
									{tag: 'td', width: "30%", innerHTML: "Bairro "}
									]}
								]}
						]}
				]);
				for(var i = 0; i < this.candidates.length; i++) {
					var row = new aptElement([
								{ tag: 'tr', style: {cursor: 'pointer'}, 
									childs: [
									{tag: 'td',  innerHTML: this.findBackground(this.candidates[i].street)},
									{tag: 'td',  innerHTML: this.candidates[i].num},
									{tag: 'td',  innerHTML: (this.candidates[i].suburb) ? this.candidates[i].suburb : this.candidates[i].county}
									]}
					]);
					Event.observe(row.elements[0],'click',this.onClick.bind(this,i));
					Event.observe(row.elements[0],'mouseover',this.rollOver.bind(this,i));
					Event.observe(row.elements[0],'mouseout',this.rollOut.bind(this,i));
				 	table.elements[0].childNodes[0].appendChild(row.elements[0]);
				 }
				this.container.appendChild(table.elements[0]);
				$(this.container).show();
				this.open = true;
			}
		} else 
			if(typeof this.callBackNotFound != "undefined" && this.callBackNotFound != '')
				 this.callBackNotFound();
	},
	//private
	sgsCityEnd: function(response) {
		//end da sgs city
		if(response.responseText)
			var Holder = eval('(' + response.responseText + ')');
		else
			var Holder = response;

		if (Holder.length > 0) {
			for(var i = 0; i < Holder.length; i++) {
				var placeCity = Holder[i].cityState.split(",");
				var city = placeCity[0].removeAccents();
				var state = placeCity[1].removeAccents();
				this.candidates[i] =  new aptAddress (this.formatedCountry, state, city);
			}
			
			if(typeof this.callBackChanged != "undefined" && this.callBackChanged != '')
				this.callBackChanged();
			
			
			if (typeof this.container != "undefined" &&  this.container != "") {
					/* borderCollapse: "2", borderSpacing: "0"*/
				var table = new aptElement([
						{ tag : 'table', style: {width: "100%", border: "0"}, childs : [
							{ tag: 'tbody',  childs: [
								{ tag: 'tr',  style: this.trHeadStyle ,childs: [
									{tag: 'td', width: "90%", innerHTML: "Cidade"},
									{tag: 'td', width: "10%", innerHTML: "UF"}
								]}
							]}
						]}
				]);
				
				
				
				for(var i = 0; i < this.candidates.length; i++) {
					var row = new aptElement([
								{ tag: 'tr', style: {cursor: 'pointer'}, 
									childs: [
									{tag: 'td',  innerHTML: this.findBackground(this.candidates[i].city,true)},
									{tag: 'td',  innerHTML: this.candidates[i].state}
									]}
					]);
					Event.observe(row.elements[0],'click',this.onClick.bind(this,i));
					Event.observe(row.elements[0],'mouseover',this.rollOver.bind(this,i));
					Event.observe(row.elements[0],'mouseout',this.rollOut.bind(this,i));
		 		 	table.elements[0].childNodes[0].appendChild(row.elements[0]);
		 		 }
				$(this.container).appendChild(table.elements[0]);
				$(this.container).show();
				this.open = true;
			}
		} else 
			if(typeof this.callBackNotFound != "undefined" && this.callBackNotFound != '')
			 	this.callBackNotFound();
	},
	selectCandidate: function(index){
		//seleciona um candidato no index das sgs
		switch(this.mode) {
			case  2:
				this.setValue(this.candidates[index]);
				//end da cidade, pois ela nao tem geocodificao
				if(typeof this.callBackEnd != "undefined" && this.callBackEnd != '')
					this.callBackEnd();
			break;
			default:
				this.setValue(this.candidates[index],false);

				if(typeof this.callBackSelected != "undefined" && this.callBackSelected != '')
					this.callBackSelected();

				if(this.autoGeocode)
					this.geocode();
	
				var address = this.result;
				if(this.autoSelection)
					this.setSelection(this.input,(address.street.length+2),(address.street.length+2+(address.num+"").length));			
			break;
		}

	},
	geocode: function()  {
		//executa geocode, for�ado ou nao
		if (this.verify) {
			if(typeof this.callBackEnd != "undefined" && this.callBackEnd != '')
				this.callBackEnd();
		} else {
			switch(this.mode) {
				case 2:
					//forca selecionar o 1 elemento (cidade)
					if (this.open && this.candidates.length > 0) {
			   			if (this.wishline != 0)
			   				var wishline = this.wishline-1; //diminui 1, devido ao cabecalho da table
			   			else
			   				var wishline = 0;
			   			this.selectCandidate(wishline);
			   		} else
			   			if(typeof this.callBackNotFound != "undefined" && this.callBackNotFound != '')
			   				 this.callBackNotFound();
				break;
		 	default:
 				try{
		 			if (typeof this.result.streetid != "undefined")
		 				var streetid = this.result.streetid;
		 			else
		 				var streetid = "";
		 		} catch(e) {
		 			var streetid = "";
		 		}
		 		try{
		 			if (typeof this.result.suburb != "undefined")
		 				var suburb = this.result.suburb;
		 			else
		 				var suburb = "";
		 		} catch(e) {
		 			var suburb = "";
		 		}
		 		this.reset();
		 		this.format();
				if (this.input.value.trim().toString().toUpperCase() == this.ignoreValue.trim().toString().toUpperCase() || this.input.value.trim().toString().toUpperCase() == "CENTRO DA CIDADE, 0") {
				 	this.formatedValue = "";
					this.formatedNumber = "";
				}
					
		 		//verifica cidade, caso merdeado, abortCity
		 		if(this.formatedCity == "" && this.formatedState == "") {
		 			if(typeof this.callBackCityAbort != "undefined" && this.callBackCityAbort != '')
		 			 	this.callBackCityAbort();
		 		} else {
		 			this.pars = {street: this.formatedValue, 
		 					num: this.formatedNumber, 
		 					city: this.formatedCity, 
		 					state: this.formatedState, 
		 					streetid: streetid,
		 					suburb: suburb
		 				};
		 			this.ajaxSGS(this.pars,this.urlGeocoding,this.geocodeEnd.bind(this));
		 		}
				break;
			}
		}

	},
	geocodeEnd: function(response) {
		//end do geocode
		if(response.responseText)
			var Holder = eval('(' + response.responseText + ')');
		else
			var Holder = response;


		//Transforma em boolean
		if (Holder.approx == "true")
			Holder.approx = true;
		else 
			Holder.approx = false;

		var error = false;
		if (this.pars.streetid == "") {
			//branco no nome da rua na resposta e branco no nome da rua entrada, centro
			//branco no nome da rua na resposta e escrito no nome da rua entrada, notfound
			//contrario, blz
			if (this.pars.street == "" && Holder.street == "") {
				Holder.street = "CENTRO DA CIDADE";
				Holder.num = 0;
				Holder.suburb = "";
			} else if (this.pars.street != "" && Holder.street == "")
				error = true;
		} else {
			Holder.street = this.pars.street;
			Holder.suburb = this.pars.suburb;
		}

		if(!error) {
			
			if(!this.autoReplaceNumber)
				Holder.num = this.pars.num;
			
			var result = new aptAddress(this.formatedCountry, this.formatedState, this.formatedCity, Holder.suburb, Holder.street, parseInt(Holder.num),"",parseFloat(Holder.y),parseFloat(Holder.x),Holder.streetid.substring(0,9),Holder.approx);
			/*compatibilidade com versoes anteriores*/
			result.latitude = parseFloat(Holder.y);
			result.longitude = parseFloat(Holder.x);
			result.lat = parseFloat(Holder.y);
			result.lon = parseFloat(Holder.x);
			
			this.setValue(result);
			if(typeof this.callBackEnd != "undefined" && this.callBackEnd != '')
				 this.callBackEnd();
		} else
			if(typeof this.callBackNotFound != "undefined" && this.callBackNotFound != '')
				 this.callBackNotFound();
		
	},
	//private
	findBackground: function(strCand, city){
		var inText = this.input.value.toUpperCase();
		inText = inText.replace(/-/g,'');
        strCand = strCand.toUpperCase().toString();
		var valueArray = inText.split(" ");
		var candArray = strCand.split(" ");
    	for(var i=0; i<candArray.length; i++){
    		for(var j=0;j<valueArray.length;j++){
				if (j == 0)
        	   		candArray[i] = candArray[i].replace(valueArray[j],"<span style='background-color: "+this.matchColor+"'>"+valueArray[j].toUpperCase()+"</span>");
    			else
    	   			candArray[i] = candArray[i].replace(valueArray[j],"<span style='background-color: "+this.matchColor+"'>"+valueArray[j]+"</span>");
			}
		}
		var candFinal;
		candFinal = candArray.join(" ");
		return candFinal;

	},
	//private
	onClick: function(index,e){
		this.selectCandidate(index);
	},
	//private
	rollOver: function(index) {
		// verifica se tem algum wishline selecionado
		if (this.wihcline >= 1)
			this.container.childNodes[0].childNodes[0].childNodes[this.wishline].style.background = "";
		this.wishline = index+1;
		//soma-se 1 devido ao cabecalho da table
		this.container.childNodes[0].childNodes[0].childNodes[index+1].style.background = this.trOverBackground;
	},
	//private
	rollOut: function(index) {
		//soma-se 1 devido ao cabecalho da table
		this.container.childNodes[0].childNodes[0].childNodes[index+1].style.background = "";
	},
	//private
	onKeyDown: function(e) {
		if(window.event)
			var keynum = e.keyCode;
		 else if(e.which) 
			var keynum = e.which;

		var oldKeyNum = this.keyNum;
		this.keyNum = keynum;
		//evitar, crt+tab, alt+tab,shift+tab
		if(keynum == 13 || (keynum == 9 && !(oldKeyNum == 16 || oldKeyNum == 17 || oldKeyNum == 18))) {
			//enter or tab (apenas)
			switch(this.mode) {
				case 2:
			   		if (this.open && this.candidates.length > 0) {
			   			if (this.wishline != 0)
			   				var wishline = this.wishline-1; //diminui 1, devido ao cabecalho da table
			   			else
			   				var wishline = 0;
			   			this.selectCandidate(wishline);
			   		} else if (this.verify) {
			   			if(typeof this.callBackEnd != "undefined" && this.callBackEnd != '')
			   					this.callBackEnd();
			   		} else
			   			if(typeof this.callBackNotFound != "undefined" && this.callBackNotFound != '')
			   				 this.callBackNotFound();
				break;
				default:
					this.format();
					if (this.open && this.candidates.length > 0 && this.formatedNumber == 0){
							if (this.wishline != 0)
								var wishline = this.wishline-1; //diminui 1, devido ao cabecalho da table
							else
								var wishline = 0;
							this.selectCandidate(wishline);
					} else if(this.verify) {
						if(typeof this.callBackEnd != "undefined" && this.callBackEnd != '')
							 this.callBackEnd();
					} else {
						this.geocode();
					}
				break;
			}

			return false;
		} else if(keynum == 40 && this.candidates.length > 0 && this.open) {
			//down
			if (this.wishline < (this.container.childNodes[0].childNodes[0].childNodes.length-1)) {
				// verifica se tem algum wishline selecionado
				if (this.wishline >= 1)
					this.container.childNodes[0].childNodes[0].childNodes[this.wishline].style.background = "";
				this.wishline += 1;
				this.container.childNodes[0].childNodes[0].childNodes[this.wishline].style.background = this.trOverBackground;
			}
			return false;
		} else if(keynum == 38 && this.candidates.length > 0 && this.open) {
			//up
			// verifica se tem algum wishline selecionado
			if (this.wishline > 1) {
				this.container.childNodes[0].childNodes[0].childNodes[this.wishline].style.background = "";
				this.wishline -= 1;
				this.container.childNodes[0].childNodes[0].childNodes[this.wishline].style.background = this.trOverBackground;
			}
		 	return false;
		}
		if(typeof this.callBackKeyDown != "undefined" && this.callBackKeyDown != '')
			this.callBackKeyDown(e,keynum);
	},
	registerListener: function(listener, typeOfListener) {
		switch(typeOfListener) {
				//incia uma sugestao
			case "start":
				this.callBackStart = listener;
			break;
				//executo uma sugestao
			case "changed":
				this.callBackChanged = listener;
			break;
				//seleciona um endereco
			case "selected":
				this.callBackSelected = listener;
			break;
				//sem cidade padrao, ou cidade padrao, nao selecionada
			case "abortCity":
				this.callBackCityAbort = listener;
			break;
				//nada encontrado
			case "notFound":
				this.callBackNotFound = listener;
			break;
				//termino a sugestao, cidade ou endereco
			case "end":
				this.callBackEnd = listener;
			break;
				//precionou alguma tecla
			case "keyDown":
				this.callBackKeyDown = listener;
			break;
				//limpou os estados
			case "reset":
				this.callBackReset = listener;
			break;
		}
	},
	//private
	setSelection: function(textBox, startIndex, endIndex) {
		if (textBox.setSelectionRange)
			textBox.setSelectionRange(startIndex, endIndex);
		else if (textBox.createTextRange) {
			var range = textBox.createTextRange();
			range.moveStart('character', startIndex);
			range.moveEnd('character', -textBox.value.length + endIndex);
			range.select();
		}
	}
});

