/**
 * Auto Completion Class
 * @author 58062 Florian Collot
 * @copyright starlimos.fr
 * var autoCompletion = new AcSLS(inputElement, urlToRequest, target, {
 * 		'delay': 200, (in millisecond),
 * 		'defaultValue' : '-1', (send if the input value is empty)
 * 		'result'	:	10, (nb result queried)
 * 		'method'	:	'post', (HTTP method used),
 * 		'caseSensitive'	: false,
 * 		'catchResult' 	: false,
 * 		'catchSelect	: false,
 * 		'classes'	:	{
 * 						'generic' : 'ac',
 * 						'normal'  : 'option',
 * 						'hover'	  : 'hover'
 * 							}
 * 		'fks'		: [{
 * 						'target' : 'tableName',
 * 						'value'	 : 'string' or element,
 * 						'column' : 'string'
 * 						}],
 * 		'gap'		: {
 * 						'top' 	: 0,
 * 						'left'	: 0,
 * 						'width'	: 0
 * 					},
 * 
 * 		onResult : function(xhr){} // Only available if catchResult = true
 * 		onSelect : function(element){} // Only available if catchSelect = true
 * 
 * 	});
 */

var AcSLS = new Class ({
	Implements: [Events, Options],
	options : {
		'delay' : 200,
		'defaultValue' : '-1',
		'results' : 10,
		'method' : 'post',
		'caseSensitive' : false,
		'catchResult' : false,
		'catchSelect' : false,
		'classes' : {
			'generic' : 'ac',
			'normal'  : 'option',
			'hover'	  : 'hover'
				},
		'fks' : [],
		'gap' : {
			'top' 	: 0,
			'left'	: 0,
			'width'	: 0
			},
		'loader' : {
			'element' : null,
			'styles' : {
				'on' : {},
				'off': {}
			}
		}
	},
	
	initialize:function(element, url, target, options){
		this.setOptions();
		this.genericConstruct(element, url, target);
	},
	
	genericConstruct : function(element, url, target) {
		// Check Element Existing
		if (typeof(element) == 'string'){
			if ($chk($(element)))
				element = $(element);
		}		
		if (!$chk(element))
			return false;
		
		this.infos = {'id' : element.get('id'), 'name' : element.get('name')};
		
		if (AcSLS.elements[this.infos.id] != null)
			return false;
		
		if (this.options.method.toLowerCase() != 'post' && this.options.method.toLowerCase() != 'get')
			this.options.method = 'get';
		
		this.fired = null;
		this.hidden = null;
		this.element = element;
		this.overflow = null;
		this.crrentLabel = null;
		this.currentValue = {'user' : '', 'know': ''};
		this.currentHover = null;
		this.total = null;
		
		if (!$chk($(this.infos.id+"_hide_value"))){
			var hidden = new Element('input', {
				'type' : 'hidden',
				'name' : this.infos.name+"_hide_value",
				'id' : this.infos.id+"_hide_value",
				'styles' : {
					'display' : 'none'
				},
				'value' : this.options.defaultValue
			}).inject(element, 'after');
		}
		this.hidden = $(this.infos.id+"_hide_value");
		
		// Create AutoCompletion Block
		var div = new Element('div', {
			'class' : this.options.classes.generic+'_container',
			'id'	: this.options.classes.generic+'_container_'+this.infos.id
		});
		
		$$('body')[0].grab(div);
		
		this.overflow = $(this.options.classes.generic+'_container_'+this.infos.id);
		this.element.addEvent('keyup', function(){
			if (this.fired != null){
				$clear(this.fired);
			}
			this.fired = this.fireKeyUp.delay(this.options.delay, this);
		}.bind(this));
		
		this.element.set('autocomplete', 'off');
		
		if (url == null || url == '' || target == null || target =='')
			return false;
		
		this.url = url;
		this.target = target;
		
		if (this.options.method == 'get')
			this.url = this.url.substr(0, this.url.lastIndexOf('.'));
		
	},
	
	childKeyUp : function(keywords){
		// Get FKS values
		var fkString = {'url' : '', 'param' : ''};
		if (this.options.fks.length > 0){
			var fks = {'columns':'','values':'','target':''};			
			for (var i=0;i<this.options.fks.length;i++){
				if (typeof(this.options.fks[i].value) == 'string')
					fks.values += (fks.values == '') ? this.options.fks[i].value : '||'+this.options.fks[i].value; 
				else
					fks.values += (fks.values == '') ? this.options.fks[i].value.get('value') : '||'+this.options.fks[i].value.get('value');

				fks.columns += (fks.columns == '') ? this.options.fks[i].column : '||'+this.options.fks[i].column;
				fks.target += (fks.target == '') ? this.options.fks[i].target : '||'+this.options.fks[i].target;
			}
			fkString.url = '/fk_targets/'+fks.target+'/fk_columns/'+fks.columns+'/fk_values/'+fks.values;
			fkString.param = '&fk_targets='+fks.target+'&fk_columns='+fks.columns+'&fk_values='+fks.values;
		}		
		var url = (this.options.method == 'get') ? this.url+'/keyword/'+keywords.main+'/target/'+this.target+'/nb/'+this.options.results+fkString.url+'.'+slsBuild.site.defaultExtension : this.url;
		var param = (this.options.method == 'get') ? null : 'keyword='+keywords.main+'&target='+this.target+'&nb='+this.options.results+fkString.param;
		
		if (this.currentRequest != null)
			this.currentRequest.cancel();
		
		this.currentRequest = new Request.JSON({
			'url' : (this.options.method == 'get') ? url : this.url,
			'method' : this.options.method,
			onStart: function(){
				// Loader
				if ($chk(this.options.loader.element)) {
					this.options.loader.element.setStyles(this.options.loader.styles.on);
				}
			}.bind(this),
			onComplete:function(xhr){
				this.processResults(xhr, keywords);
			}.bind(this)
		}).send(param);
	},
	
	fireKeyUp : function(){
		var keywords = this.getKeywords();
		if (this.currentValue.user != null && keywords.main.trim() == this.currentValue.user.trim())
			return;
		if (keywords.main.trim() == ''){
			if (this.overflow.getStyle('display') == 'block')
				this.hideOverflow();
			this.currentValue.user = null;
			this.hidden.set('value', this.options.defaultValue);
			return;
		}
		
		if (this.currentValue.know.trim() != ''){
			if (keywords.main.trim() != this.currentValue.know.trim()){
				this.hidden.set('value', this.options.defaultValue);
				this.currentValue.know = '';
			}
		}
		
		this.currentValue.user = keywords.main;
		this.childKeyUp(keywords);
	},
	
	processResults : function(xhr, keywords) {
		this.currentRequest = null;
		this.overflow.empty();
		if (this.options.catchResult){
			this.fireEvent('result', [xhr]);
			return;
		}	
		if (typeof(xhr) == 'object' && xhr.length != 0){					
			var ul = new Element('ul', {
				'class' : this.options.classes.generic+'_ul'
			});
			
			ul.empty();
			var obj = this;
			ul = this.childProcessResult(ul, xhr, keywords);
			
			if (ul.getFirst('li') != null){
				// Loader
				if ($chk(this.options.loader.element)) {
					this.options.loader.element.setStyles(this.options.loader.styles.off);
				}
				this.insertOptions(ul, 'li span a', xhr.length);
			}
		}
		else{
			if (this.overflow.getStyle('display') == 'block')
				this.hideOverflow();
		}
	},
	
	childProcessResult : function(ul, xhr, keywords) {
		for (var i=0;i<xhr.length;i++){
			if (xhr[i].value != '' && xhr[i].key != ''){
				var li = new Element('li').inject(ul);
				var span = new Element('span').inject(li);
				var a = new Element('a', {
					'title' : xhr[i].key,
					'href' : xhr[i].value,
					'html' : xhr[i].key
				}).inject(span);
				if (this.options.caseSensitive){
					if (xhr[i].key.trim() == keywords.main.trim()){
						this.hidden.set('value', xhr[i].value);
						this.currentValue.know = xhr[i].key;
					}
				}
				else {
					if (xhr[i].key.trim().toLowerCase() == keywords.main.trim().toLowerCase()){
						this.hidden.set('value', xhr[i].value);
						this.currentValue.know = xhr[i].key;
					}
				}
			}
		}
		return ul;
	},
	
	insertOptions : function(element, clicks, total) {
		this.elementParent = element;
		this.itemSelector  = clicks;
		element.inject(this.overflow);
		var elClick = element.getElements(clicks);
		for (var i=0;i<elClick.length;i++){
			elClick[i].addEvent('mouseover', function(i){
				this.setCurrentHover(i);
			}.bind(this,[i]));
			elClick[i].addEvent('click', function(e){
				this.selectItem();
				e.stop();
			}.bind(this));
		}
		this.adjustOverflow();
		this.total = total;
		this.setCurrentHover(null);
		// Configure key Event
		if (this.overflow.getStyle('display') == 'none') {
			if (Browser.Engine.trident){
				$$('body')[0].addEvent('keydown', function(e){
					this.handleKey(e);
				}.bind(this));
				$$('body')[0].addEvent('click', function(e){
					this.handleClick(e);
				}.bind(this));
			}
			else{
				window.addEvent('keydown', function(e){
					this.handleKey(e);
				}.bind(this));
				window.addEvent('click', function(e){
					this.handleClick(e);
				}.bind(this));
			}
		}
		this.overflow.setStyle('display', 'block');
	},
	
	getKeywords : function(){
		var keywords = {
				'main' : this.element.get('value')
		};
		return keywords;
	},
	
	adjustOverflow : function(){
		var top = Display.getY(this.element)+parseInt(this.options.gap.top)+parseInt(this.element.getStyle('height').split("px")[0]);
		var left = Display.getX(this.element)+parseInt(this.options.gap.left);
		var width = parseInt(this.element.getStyle('width').split('px')[0])+parseInt(this.options.gap.width);
		this.overflow.setStyles({
			'top' : top.toString()+"px",
			'left': left.toString()+"px",
			'width' : width.toString()+"px"
		});
	},
	setCurrentHover : function(index){
		if (index == null)
			index = -1;
		var normal = this.options.classes.normal;
		var hover  = this.options.classes.hover;
		$$('#'+this.options.classes.generic+'_container_'+this.infos.id+' '+this.itemSelector).each(function(element, i){
			if (index == i){
				element.set('class', hover);
			}
			else
				element.set('class', normal);
			
		});
		this.currentHover = (index == -1) ? null : index;
	},
	selectItem : function() {
		if ($chk($$('#'+this.options.classes.generic+'_container_'+this.infos.id+' '+this.itemSelector)[this.currentHover])){
			if (this.options.catchSelect){
				this.fireEvent('select', [$$('#'+this.options.classes.generic+'_container_'+this.infos.id+' '+this.itemSelector)[this.currentHover]]);
				return;
			}
			var itemToSelect  = $$('#'+this.options.classes.generic+'_container_'+this.infos.id+' '+this.itemSelector)[this.currentHover];
			this.element.set('value', itemToSelect.get('text'));
			this.setHidden(itemToSelect.get('href'));
			this.currentValue.user = itemToSelect.get('text');
			this.currentValue.know = itemToSelect.get('text');
			this.hideOverflow();
		}
	},
	
	setHidden : function(value){
		this.hidden.set('value', value);
	},
	
	getHidden : function(){
		return this.hidden.get('value');
	},
	
	hideOverflow : function(){
		this.currentHover = null;
		if (Browser.Engine.trident){
			$$('body')[0].removeEvents('keydown');
			$$('body')[0].removeEvents('click');
		}
		else{
			window.removeEvents('keydown');
			window.removeEvents('click');
		}

		this.overflow.setStyle('display', 'none');
	},
	handleKey : function(e){
		/* Down = 40
		 * Up = 38
		 * Right = 39
		 * Left = 37
		 * Enter = 13
		 * Esc = 27 	
		 * Tab = 9
		 * Shift = 16
		 * Space = 32 
		 */
		if (e.code == 27 || e.code == 9)
			this.hideOverflow();
		if (e.code == 40){
			this.setNextHover();
			e.stop();
		}
		if (e.code == 38){
			this.setPreviousSelectHover();
			e.stop();
		}
		if (e.code == 13 || e.code == 39) {
			if (this.currentHover != null)
				this.selectItem();
			e.stop();
		}

	},
	handleClick : function(e) {
		if (navigator.appName == "Netscape")
		{document.captureEvents(Event.CLICK);}
		if (navigator.appName == "Microsoft Internet Explorer")
		{sX = event.clientX; sY = event.clientY;}
		else {sX = e.pageX;sY = e.pageY;}
		if (this.overflow.getStyle('display') == 'block')
		{
			var xMinOverflow = Display.getX(this.overflow);
			var yMinOverflow = Display.getY(this.overflow);
			var xMaxOverflow = xMinOverflow+parseInt(this.overflow.getStyle('width').split('px')[0]);
			var yMaxOverflow = yMinOverflow+parseInt(this.overflow.getStyle('height').split('px')[0]);
			if (sX > xMinOverflow && sX < xMaxOverflow && sY > yMinOverflow && sY < yMaxOverflow)
				return;
			else
				this.hideOverflow();
		}
		
	},
	setNextHover : function(){
		if (this.currentHover == null){
			var next = 0;
		}
		else{
			if ((parseInt(this.currentHover+1)) != parseInt(this.total)){
				var next = parseInt(this.currentHover)+1;
			}
			else
				var next = 0;
		}
		this.setCurrentHover(next);
	},
	setPreviousSelectHover : function (){
		if (this.currentHover == null){
			var prev = parseInt(this.total)-1;
		}
		else{
			if (parseInt(this.currentHover) != 0){
				var prev = parseInt(this.currentHover)-1;
			}
			else
				var prev = parseInt(this.total)-1;
		}
		this.setCurrentHover(prev);
	}
});
AcSLS.elements = {};

var GoogleAcSLS = new Class({
	Implements: [AcSLS],
	options : {
		'google_map' : {
			'url' : 'http://maps.google.com/maps/api/js?sensor=true'
		},
		'limitations' : {
			'country' : null,
			'city': null
		}
	},
	
	initialize : function(element, options) {
		this.setOptions(options);
		GoogleAcSLS.elements[element.get('id')] = this;
		GoogleAcSLS.nbElements++;
		this.element = element;
		this.initGoogleAc();
		
	},
	
	initGoogleAc : function() {
		// Google Maps
		var scriptExist = false;
		if (GoogleAcSLS.nbElements > 1)
			scriptExist = true;
		else {
			$$('script').each(function(element, index){
				if (element.get('src') == this.options.google_map.url)
					scriptExist = true;
			}.bind(this)); 
		}
		if (scriptExist == false) {
			this.google_script = new Element('script', {
				'type' : 'text/javascript',
				'src' : this.options.google_map.url+'&callback=GoogleAcSLS.elements.'+this.element.get('id')+'.googleScriptLoaded'
			}).inject($$('body')[0], 'bottom');
		}
		else
			this.googleScriptLoaded();
	},
	
	googleScriptLoaded : function(){
		this.genericConstruct(this.element);
	},
	
	childKeyUp : function(keywords) {
		// Google Maps
		
		if (!$chk(this.geocoder))
			this.geocoder = new google.maps.Geocoder();
		
		// Loader
		if ($chk(this.options.loader.element)) {
			this.options.loader.element.setStyles(this.options.loader.styles.on);
		}
		
		var ref = this;
		
		this.geocoder.geocode(
			{ 'address' : keywords.main },
			function(results, status) {
				if (status == google.maps.GeocoderStatus.OK) {
					ref.processResults(results, keywords);
				}
			}
		);
		
		return;
		
	},
	
	childProcessResult : function(ul, xhr, keywords) {
		var print = 0; 	
		
		for (var i=0;i<xhr.length;i++){
			
			var limitations = {'country' : null,'city':null};
			var li = new Element('li');
			var span = new Element('span').inject(li);
			var str = '';
			for (var j=0;j<xhr[i].address_components.length;j++) {
				str += (j == 0) ? 
						xhr[i].address_components[j].types[0]+'='+xhr[i].address_components[j].long_name+'='+xhr[i].address_components[j].short_name : 
						'|||'+xhr[i].address_components[j].types[0]+'='+xhr[i].address_components[j].long_name+'='+xhr[i].address_components[j].short_name;
						
				if (xhr[i].address_components[j].types[0] == 'locality')
					limitations.city = xhr[i].address_components[j].long_name;
				if (xhr[i].address_components[j].types[0] == 'country')
					limitations.country = xhr[i].address_components[j].long_name;
			}
			str += '|||lng='+xhr[i].geometry.location.lng()+'|||lat='+xhr[i].geometry.location.lat()+'|||full_address='+xhr[i].formatted_address;
			
			var a = new Element('a', {
				'title' : xhr[i].formatted_address,
				'href' : str,
				'html' : xhr[i].formatted_address
			}).inject(span);
			if (this.options.caseSensitive){
				if (xhr[i].formatted_address.trim() == keywords.main.trim()){
					this.hidden.set('value', str);
					this.currentValue.know = xhr[i].formatted_address;
				}
			}
			else {
				if (xhr[i].formatted_address.trim().toLowerCase() == keywords.main.trim().toLowerCase()){
					this.hidden.set('value', str);
					this.currentValue.know = xhr[i].formatted_address;
				}
			}
			
			if (this.options.results > print) {
				
				// Limitations
				var insert = true;
				if (this.options.limitations.country != null || this.options.limitations.city !=  null) {
					if (limitations.country == null && 
						this.options.limitations.country != null)
						insert = false;
					if (insert == true && 
						limitations.city == null && 
						this.options.limitations.city != null)
						insert = false;
					if (insert == true && 
						this.options.limitations.country != null && 
						this.options.limitations.country.toLowerCase() != limitations.country.toLowerCase())
						insert = false;
					if (insert == true && 
						this.options.limitations.city != null && 
						this.options.limitations.city.toLowerCase() != limitations.city.toLowerCase())
						insert = false;
				}
				
				if (insert == true) {
					li.inject(ul);
					print++;
				}
			}
			else
				break;
		}
		return ul;
	}
	
});
GoogleAcSLS.elements = {};
GoogleAcSLS.nbElements = 0;



