/**
 * @author Shin
 * new auto_geocode.js from D2
 */

////// Objetos auxiliares modificados da prototype.js 
Abstract.TimedObserver2 = function() {}
Abstract.TimedObserver2.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;
    
    this.lastValue = this.getValue();
    this.start();
  },

  start: function() {
  	
  	this.lastValue = this.getValue();
    this.interval = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },
  
  stop: function() {
    clearInterval(this.interval);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
      ? this.lastValue != value : String(this.lastValue) != String(value));
    if (changed) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer2 = Class.create();
Form.Element.Observer2.prototype = Object.extend(new Abstract.TimedObserver2(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

//////
  
/*Api Geocode, passar campo input, campo input city, instancia um objeto que vai receber: candidatos com streetid, nome, bairro, numero, funcao onclick*/

autoGeocode = function(varName,input,input_city,candidatesDiv,candidatesBoxDiv,callBackStart,returnCallBack,returnOverCallBack,returnStreetIdCallBack){
	this.varName = varName;
	this.geocodeHolder = []; //armazena os candidatos
	this.input = input;
	this.input_city = input_city;
	this.callBackStart = callBackStart;
	this.returnCallBack = returnCallBack;
	this.returnOverCallBack = returnOverCallBack;
	this.returnStreetIdCallBack = returnStreetIdCallBack;
	this.urlGeocode = '/memorygeocode/addresssuggestion';
	this.urlStreetId = '/memorygeocode/geocoding';
	this.geocodeObj;
	this.candidatesBoxDiv = candidatesBoxDiv;
	this.candidatesDiv = candidatesDiv;
	this.observer = null;
	this.observer2 = null;
	this.address = new Object();
	this.address.streetid   = "";
	this.address.street     = "";
	this.address.street_esc = "";
	this.address.number     = "";
	this.address.district   = "";
	this.address.city       = "";
	this.address.city_esc   = "";
	this.address.state_esc  = "";
	this.address.country    = "";
	//this.input.autoGeocodeObj = this;
}

autoGeocode.prototype.start = function(){
	this.observer = new Form.Element.Observer2(
	 this.input,
	  0.5,
	   this.auto_geocode.bind(this)
	)
	this.observer2 = new Form.Element.Observer2(
	 this.input_city,
	  0.5,
	   this.auto_geocode_city.bind(this)
	)
	
	this.input.onchange = this.streetonchange.bind(this);
	this.input_city.onchange = this.cityonchange.bind(this);
	
	this.addListenerKeyDown(this.input, this.responseKeyCodeEnderecos.bind(this));
	this.addListenerKeyDown(this.input_city, this.responseKeyCodeEnderecos.bind(this));
	
}

autoGeocode.prototype.startObserver = function(){
	if(this.observer!=null)
		this.observer.start();
	if(this.observer2!=null)
		this.observer2.start();
}

autoGeocode.prototype.stopObserver = function(){
	if(this.observer!=null)
		this.observer.stop();
	if(this.observer2!=null)
		this.observer2.stop();
}

autoGeocode.prototype.cityonchange = function() {
	var temp = this.input_city.value.split(",");
	var city = temp[0];
	var state = temp[1];
	//alert("streetonchange\naddress.street:" + this.address.street + " name:"+ name);	
	if (this.address.streetid != "" && (this.address.city.toLowerCase() != city.toLowerCase() || this.address.state_esc.toLowerCase()!=state.toLowerCase())){
		this.address.streetid = "";
	}
	if(typeof this.input.onChangeCallback != "undefined" && this.input.onChangeCallback != "") {
		if(typeof this.input.onChangeCallback == "String")
			eval('(' + this.input.onChangeCallback + ')');
		else
			eval('(' + this.input.onChangeCallback + '())');
	}
}

autoGeocode.prototype.streetonchange = function() {
	//alert('this.address.street ' + this.address.street);
	var placeHolder = this.input.value.split(",");
	var name = placeHolder[0];
	//alert("streetonchange\naddress.street:" + this.address.street + " name:"+ name);	
	if (this.address.streetid != "" && this.address.street.toLowerCase() != name.toLowerCase()){
		this.address.streetid = "";
	}
	if(typeof this.input.onChangeCallback != "undefined" && this.input.onChangeCallback != "") {
		if(typeof this.input.onChangeCallback == "String")
			eval('(' + this.input.onChangeCallback + ')');
		else
			eval('(' + this.input.onChangeCallback + '())');
	}
}

autoGeocode.prototype.cityonblur = function() {
	//this.auto_geocode(this.input,this.input.value);
}

autoGeocode.prototype.cityonchange = function() {
	this.address.streetid = "";
	
	if(typeof this.input_city.onChangeCallback != "undefined" && this.input_city.onChangeCallback != "") {
		if(typeof this.input_city.onChangeCallback == "String")
			eval('(' + this.input_city.onChangeCallback + ')');
		else
			eval('(' + this.input_city.onChangeCallback + '())');
	}
}

autoGeocode.prototype.auto_geocode = function(el,value) {
	if (value.length > 2) {
		this.ajax_start(value,this.ajax_response.bind(this));
	} else {
		this.open = false;
		this.candidatesBoxDiv.hide();
		this.returnOverCallBack();
	}
		
}
autoGeocode.prototype.auto_geocode_city = function(el,value) {
	var temp = value.split(",");
	var state = temp[1];
		
	if (typeof state == "string") 
		state = state.trim();
		
	if (temp.length == 2 && state.length == 2) {
		this.ajax_start(value, this.ajax_response.bind(this));
	}
	else {
		this.open = false;
		this.candidatesBoxDiv.hide();
		this.returnOverCallBack();
	}	
}


autoGeocode.prototype.format_value = function() {
	var city;
	var state;
	var num;
	var placeHolder;
	var citystate = this.input_city.value.split(",");
	
	if(citystate.length == 2) {
		city = citystate[0].removeAccents().trim();
		state = citystate[1].removeAccents().trim();
	} else {
		city =  "SAO PAULO";
		state = "SP";
	}
	
	this.address.city_esc = city;
	this.address.state_esc = state;
		
	placeHolder = this.input.value.split(",");
	this.address.street_esc = placeHolder[0].removeAccents().trim();
	
	if (placeHolder.length == 4)  {
		this.address.city_esc = placeHolder[2].removeAccents().trim();
		this.address.state_esc = placeHolder[3].removeAccents().trim();
	}
	
	this.address.number = 0;
	num = placeHolder[1];
	if (typeof num != "undefined" && num != "undefined" && num.trim() != "")
		this.address.number = num.trim();
	
}

autoGeocode.prototype.ajax_start = function(value,ajax_response) {
	if(typeof this.callBackStart != "undefined" && this.callBackStart != '')
		eval('(' + this.callBackStart + '())');

	this.format_value();
		
	//verifica se náo é o mesmo cara
	//alert("street " + this.address.street + "\nstreet_esc "+ this.address.street_esc+ "\ncity" + this.address.city+"\ncity_esc "+ this.address.city_esc);
	if(this.address.street.toString() == this.address.street_esc.toString()
		//&& this.address.city.toString().toLowerCase() == this.address.city_esc.toString().toLowerCase()
		){
		//alert("igual");
		delete(this.geocodeObj);
	}
	else{
		//alert("diferente");
		this.geocodeObj = new Ajax.Request(this.urlGeocode,
			{
			method:'get',
			parameters: {street: this.address.street_esc, city: this.address.city_esc, state: this.address.state_esc},
			onSuccess: ajax_response
			}
		);
	}	
}

autoGeocode.prototype.ajax_response = function(response){
	this.open = true;
		
	var Holder = eval('(' + response.responseText + ')');
	this.geocodeHolder = [];
	
	if(Holder.length > 0) {
		for(var i = 0; i < Holder.length; i++) {
			this.geocodeHolder[i]= {
				city: this.address.city_esc.trim(),
				state: this.address.state_esc.trim(),
				streetid: Holder[i].streetid.trim(),
				street: Holder[i].name.trim(),
				district: Holder[i].district.trim(),
				number: (this.address.number+"").trim()};
		}
	}
	
	this.returnCallBack();
}


autoGeocode.prototype.selectCandidate = function(id){ 
	//alert("selectCandidate");
	this.HolderGeoCode = null;
	
	if (id == -1)
		id = 0;

	this.open = false;
	this.address.streetid = this.geocodeHolder[id].streetid;
	this.address.city = this.geocodeHolder[id].city;
	this.address.district = this.geocodeHolder[id].district;
	this.address.street = this.geocodeHolder[id].street;
	this.address.number = this.geocodeHolder[id].number;
	//alert("selectCandidate\n"+ this.geocodeHolder[id].street + ", " + this.geocodeHolder[id].number);
	
	this.observer.stop();
	this.input.value = this.geocodeHolder[id].street + ", " + this.geocodeHolder[id].number;
	this.observer.start();
	
	this.observer2.stop();
	this.input_city.value = this.address.city_esc + ", " + this.address.state_esc.trim();
	this.observer2.start();
	
	/*
	this.input.geocode_streetid = this.geocodeHolder[id].streetid;
	this.input.geocode_district = this.geocodeHolder[id].district;
	this.input.geocode_name = this.geocodeHolder[id].name;
	this.input.geocode_number = this.geocodeHolder[id].number;
	this.input.value = this.geocodeHolder[id].name + ", " + this.geocodeHolder[id].number;
	this.input_city.value = this.escape_value_city + ", " + this.escape_value_state.trim();
	*/
	//shin <<<
	//alert("selectCandidate\nthis.address.number " + this.address.number);
	if(this.address.number > 0){
		this.doStreetID();
	}
	else{
		this.setSelection(this.input,(this.geocodeHolder[id].street.length+2),(this.geocodeHolder[id].street.length+2+this.geocodeHolder[id].number.length));
		this.input.focus();
	}
	
	//shin >>>
	
}

autoGeocode.prototype.doStreetID = function(){ 
	//alert("doStreetID");
	//var streetid = (this.input.geocode_approx=="false") ? (this.input.geocode_streetid):("");
	
	var streetid = this.address.streetid;
	var placeHolder = this.input.value.split(",");
	var number = placeHolder[1];
	
	if (!this.open 
		&& typeof number != "undefined" && number != "undefined" && number.trim() != "" 
		&& typeof streetid != "undefined" && streetid != "undefined" && streetid.trim() != ""){
		
		//alert("doStreetID geocoding " + number);
		var autogeo = new Ajax.Request(this.urlStreetId,
		  {
		    method:'get',
		    parameters: {streetid: streetid.trim(), num: number.trim()},
		    onSuccess: this.ajax_streetid.bind(this)
		  });
	
	
	} else {
		this.format_value();
		
		//alert("doStreetID validate");
		delete(this.geocodeObj);
		this.geocodeObj = new Ajax.Request(this.urlStreetId,
			{
				method:'get',
				parameters:
					{street: this.address.street_esc,
					city: this.address.city_esc,
					state: this.address.state_esc,
					num: this.address.number},
				onSuccess: this.ajax_streetid.bind(this)
			}
		);			
	}
	return false;
}



autoGeocode.prototype.ajax_streetid = function(response){
	var Holder = eval('(' + response.responseText + ')');

	//Caso o name venha do geocode
	if (typeof Holder.street != "undefined" && Holder.street != "undefined" && Holder.street.trim() != "")
		this.address.street = Holder.street;

	//Zera para caso que venha sem streetid e name e bairro
	if (typeof this.address.streetid == "undefined")
		this.address.streetid = "";

	if (typeof this.address.district == "undefined")
		this.address.district = "";

	//Caso esteja em branco, era centro
	if (typeof this.address.street == "undefined")
		this.address.street = "CENTRO DA CIDADE";

	if(Holder.x!=undefined && Holder.y!=undefined)
	
	this.input_city.value = this.address.city_esc + ", " + this.address.state_esc;
	
	this.HolderGeoCode= {
		streetid: this.address.streetid,
		street: this.address.street,
		district: this.address.district,
		number: Holder.num,
		approx: Holder.approx,
		x: parseFloat(Holder.x),
		y: parseFloat(Holder.y),
		city: this.address.city_esc,
		state: this.address.state_esc
	}
		
		
	this.returnStreetIdCallBack();
}

 
autoGeocode.prototype.setSelection = function(textBox, startIndex, endIndex) {
	//alert("setSelection");
	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();
    }
}

/**
 * default geocode result check
 * true if 
 * 1)street exact match
 * or 2)only city and valid lat|lon
 * or 3)street chosen from candidates
 */
autoGeocode.prototype.isOk = function() {
	if(this.HolderGeoCode == null || this.HolderGeoCode==undefined){
		return false;
	}
	if (this.HolderGeoCode.approx == "false" /*exact match or chosen from candidates and valid number*/ ||
	(this.HolderGeoCode.approx == "true" && (this.HolderGeoCode.x != 0.0 || this.HolderGeoCode.x != 0.0) && this.input.value == "") /*city center*/ ||
	(this.HolderGeoCode.approx == "true" && (this.HolderGeoCode.x != 0.0 || this.HolderGeoCode.x != 0.0) && this.HolderGeoCode.streetid != "") /*street from candidates but invalid number*/) {
		if (this.input.value != ""){
			//alert("isOk\n" + this.HolderGeoCode.street + ", " + this.HolderGeoCode.number); 
			this.observer.stop();
			this.input.value = this.HolderGeoCode.street + ", " + this.HolderGeoCode.number;
			this.observer.start();
		}
		//alert("isOk() true");
		return true;
	}
	else {
		if(this.HolderGeoCode.approx == "true" && (this.HolderGeoCode.x == 0.0 && this.HolderGeoCode.x == 0.0))
			this.geocodeHolder = [];
			
		this.HolderGeoCode = [];
		this.returnCallBack();
		//alert("isOk() false");
		return false;
	}
}

/*
autoGeocode.prototype.limpaEnderecos = function(){
	this.candidatesBoxDiv.hide();
	//aptCont.geocode.streetOpen = false;
	//$(aptCont.geocode.boxStreet).style.display='none';
}
*/

autoGeocode.prototype.selecionaEnderecos = function(id) {
	//alert("selecionaEnderecos");
	this.candidatesDiv.innerHTML = "";
	this.candidatesBoxDiv.hide();
	this.selectCandidate(id);
	//geocoded = true;
	//if(typeof enderecos.input.streetid != "undefined" && enderecos.input.streetid != "") {
		//enderecos.doStreetID();
	//}
}


autoGeocode.prototype.addListenerKeyDown = function(elm, dispatch) {
	if (elm.attachEvent) {
   		elm.attachEvent("onkeydown", dispatch);
 	} else {
		elm.onkeydown = dispatch;
	}
}

autoGeocode.prototype.responseKeyCodeDown = function(candidates, input) {
	if(typeof input.whichline == "undefined") //pula o primeiro
		input.whichline = 0;

	//verifica limite
	if(candidates.childNodes[0].childNodes[0]!=undefined){
		if (input.whichline < (candidates.childNodes[0].childNodes[0].childNodes.length-1)) {
			input.whichline += 1;
			
			for (i = 0; i < candidates.childNodes[0].childNodes[0].childNodes.length; i++) {
				if (input.whichline != i) {		
					lastelement = candidates.childNodes[0].childNodes[0].childNodes[i];
					lastelement.className = 'zebraOut';
				}
			}
			
	
			element = candidates.childNodes[0].childNodes[0].childNodes[input.whichline];
			element.className = 'zebraIn';
		}
	}
}

autoGeocode.prototype.responseKeyCodeUp = function(candidates,input){
	if(typeof input.whichline == "undefined") //pula o primeiro
		input.whichline = 0;
			
	if(candidates.childNodes[0].childNodes[0]!=undefined){
		//tem de ser maior que 1 senão bugged
		if (input.whichline > 1) {
			input.whichline -= 1;

			for (i = 0; i < candidates.childNodes[0].childNodes[0].childNodes.length; i++) {
				if (input.whichline != i) {		
					lastelement = candidates.childNodes[0].childNodes[0].childNodes[i];
					lastelement.className = 'zebraOut';
				}
			}
	
			element = candidates.childNodes[0].childNodes[0].childNodes[input.whichline];
			element.className = 'zebraIn';
		}
	}
}


autoGeocode.prototype.responseKeyCodeEnderecos = function(e) {
	//alert("responseKeyCodeEnderecos");
	//geocoded = false;
	
	if(window.event) {
		keynum = e.keyCode;
	} else if(e.which) {
		keynum = e.which;
	}
	
	if(keynum == 40/*DOWN*/) {
		this.responseKeyCodeDown(this.candidatesDiv, this.input);
		//*return false;
	} else if(keynum == 38/*UP*/) {
		this.responseKeyCodeUp(this.candidatesDiv, this.input);
		//*return false;
	} else if(keynum == 13/*ENTER*/) {
		//alert("key down ENTER");
		//alert("input.whichline " + this.input.whichline + " open " + this.open);
		if(this.input.whichline > 0 && this.open) {
			this.selecionaEnderecos(this.input.whichline - 1);
			return false;
		}
		placeHolder = this.input.value.split(",");
		if (this.address.street != placeHolder[0])
			this.address.streetid = "";
		//alert("key down doStreetID");
		this.doStreetID();
		return false;

	}
	else{
		this.streetonchange();
	}

}

autoGeocode.prototype.rolloverEnderecos = function(id) {
	this.input.whichline = id+1;
	
	for (i = 0; i < this.candidatesDiv.childNodes[0].childNodes[0].childNodes.length; i++) {
		if (id != i) {
			lastelement = this.candidatesDiv.childNodes[0].childNodes[0].childNodes[i];
			lastelement.className = 'zebraOut';
		}
	}

	element = this.candidatesDiv.childNodes[0].childNodes[0].childNodes[id+1];
	element.className = 'zebraIn';
	element.style.cursor = 'pointer';
	
}

autoGeocode.prototype.rolloutEnderecos = function(id) {
	this.input.whichline = id+1;
	
	for (i = 0; i < this.candidatesDiv.childNodes[0].childNodes[0].childNodes.length; i++) {
		lastelement = this.candidatesDiv.childNodes[0].childNodes[0].childNodes[i];
		lastelement.className = 'zebraOut';
	}

	element = this.candidatesDiv.childNodes[0].childNodes[0].childNodes[id+1];
	element.style.cursor = 'auto';

}

autoGeocode.prototype.setStreetNumOnChangeCallback = function(func) {
	this.input.onChangeCallback = func;
}
autoGeocode.prototype.setCityStateOnChangeCallback = function(func) {
	this.input_city.onChangeCallback = func;
}



/*Fim Api Geocode*/
