/**
 * @author Milovan Jovicic
 * 
 */
(function($) {



/**
 * Clones specified object. from http://javascript.geniusbug.com/index.php?action=show&name=clone
 * @param {Object} myObj
 */
$.clone = function (myObj){
	if(typeof(myObj) != 'object' || myObj == null) return myObj;
	var myNewObj = {};
	for(var i in myObj)	myNewObj[i] = $.clone(myObj[i]);
	return myNewObj;
}


/**
 * Check whether object is ancestor!
 * @param {Object} p
 * @param {Object} c
 */
$.isAncestor = function(p,c) {
	var p = p.get(0);
	var c = c.get(0);
	var parent = c.parentNode;
	while (parent) {
		if (parent == p) {
			return true;
		}
		else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
			return false;
		}
		parent = parent.parentNode;
	}
	return false;
}


/**
 * validateBox component::
 */
$.validateBox = function(options){
	this.init(options);
}

$.validateBox.prototype = {

	/**
	 * Validates addresses...
	 */
	doQuery:function(value) {
		/**
		 * Load results from remote server::
		 */
		this.cmbBox.loadIndicator(true);
		var $this = this;
		/*var urlComplete = 	  $this.cmbBox.storeUrlValidate
							+ '?'
							+ $this.source
							+ '='
							+ $this.el.val();*/
		
		var ajaxObj = {
			type	: "GET"
		  , url		: $this.cmbBox.storeUrlValidate
		  , dataType: "json"
		  , cache	: false
		  , success	: function(a) {
				$this.store = a;
				$this.onLoad();
			}
		  , error	: function() {
				$this.onLoad();
			}
		  , data : {} 
		}

		ajaxObj.data[$this.cmbBox.optsStore.urlValidate.queryText] = $this.cmbBox.getRawValue();
		this.cmbBox.ajaxValidationCall = $.ajax(ajaxObj);
		
	}
	
	/**
	 * triggers when component is loaded!
	 */
	,onLoad:function(){
		
		this.cmbBox.ajaxValidationCall = null;
		if(this.getCount()==1){
			
			var cmbBoxValue = this.cmbBox.getRawValue();
			
			/**
			 * SetValue here, if only one result found:
			 */
			this.cmbBox.setValue({
				  text	 : this.store.results[0].label
				, value	 : this.store.results[0].value
				, source : '0'
			});
			//this.cmbBox.largeWrapper.highlight();
			this.cmbBox.renderUndoLabel(cmbBoxValue);
			
			
		} else if(this.getCount() > 1){
			this.renderList();
			this.expand();
		}else{
			this.onEmptyResults();
		}
		
		this.cmbBox.loadIndicator(false);
		this.cmbBox.stillValidatingMsg.fadeOut();
	}
	
	/**
	 * triggers when there are no results...
	 */
	,onEmptyResults:function(){
		
		this.collapse();
		/**
		 * Mark Invalid...
		 */
		this.cmbBox.markInvalid();
	}
	
	
	/**
	 * return if addrBox is expanded::
	 */
	,isExpanded: function(){
		return (this.addrBox.css('display')!='none');
	}

	/**
	 * Expands addrBox!
	 */
	,expand:function(){
		if(this.isExpanded()){
			return;
		}
		this.cmbBox.collapse();
		
		this.addrBox.show();
		var $this = this;
		/*$(document).mousedown(function(e){
			$this.collapseIf(e,$this);
		});*/
	}

	/**
	 * Collapses list if somewhere outside clicked...
	 * @param {Object} e
	 * @param {Object} reference to THIS object...
	 */
	,collapseIf: function(e, $this) {
		if (!$.isAncestor($this.addrBox, $(e.target))) {
			//$this.collapse();
			$this.onEmptyResults();
		};
	}
	/**
	 * Collapse addrBox
	 */
	,collapse:function(){
		if(!this.isExpanded()){
			return;
		}
		this.addrBox.hide();
		var $this = this;
		$(document).unbind('mousedown');
	}
	/**
	 * get count!
	 */
	,getCount:function(){
		return this.store.length;
	}
	
	/**
	 * Render list!
	 */
	,renderList:function(){
		if(this.getCount()>0) {
			var s 		= this.store;
			var inputBox= this.el;
			var li		= '';
			for (var item in s) {
				if(item!='length') {
					$.each(s[item],function(i,j) {
						li+= "<li value='"+j.value+"'>"
							+	'<input type="radio" name="'+ inputBox.attr('id')+'Radiogroup" id="'+inputBox.attr('id')+'Radio-'+j.value+'"/>'
							+	'<label for="'+inputBox.attr('id')+'Radio-'+j.value+'">'
							+		j.label
							+	'</label>'
							+'</li>';
					})
				}
			}
			li+= 			 "<li none='true'>"
							+	'<input type="radio" name="'+ inputBox.attr('id')+'Radiogroup" id="'+inputBox.attr('id')+'Radio-NONE"/>'
							+	'<label for="'+inputBox.attr('id')+'Radio-NONE">'
							+		'None of above'
							+	'</label>'
							+'</li>';
			this.list.html(li);
			this.initListEvents();
		}
	}
	
	
	/**
	 * Add hover and click events!
	 */
	,initListEvents:function(){
		this.listItems = this.list.find("li");
		var $this=this;
		this.listItems
			.hover(function(){
				$(this).addClass('hover');
				$(this).find('label').addClass('hover');
			  }
			, function(){
				$(this).removeClass('hover');
				$(this).find('label').removeClass('hover');
			}
		)
		.click(function() {
			$this.onViewClick()
		});
	}
	
	/**
	 * set Value on component...
	 * @param {Object} value
	 */
	/*,setValue : function(params){

		this.el.val(params.text);
		this.hiddenField.attr('value',params.value);
		this.cmbBox.onValueSet();
	}*/
	
	/**
	 * Calculate quote::
	 */
	,doQuote : function() {
		
	}

	/**
	 * handles click event!
	 */
	,onViewClick:function(){
		var li = this.list.find("li.hover:first");

		var $this = this;
		
		/**
		 * If clicked on some text
		 */
		if($(li).text()) {
			/**
			 * If user has clicked on "None of above"...
			 */
			if ($(li).attr('none') == 'true') {
				
				//collapse, markInvalid::
				this.onEmptyResults();
				
				/**
				* Provide AJAX CALL also ::
				*/
				$.ajax ({
					type	: "GET"
				  , url		: $this.storeUrlSelect
				  , dataType: "text"
				  , cache	: false
				  , success	: function(){}
				  , error	: function(){} 
				  , data	: {
				  		id	: -1
				  }
				});
			}
			else {
				this.cmbBox.setValue({
					value: (typeof($(li).attr('value')) == 'undefined' ? '0' : $(li).attr('value')),
					text: $(li).text(),
					source: '0'
				});
			}
		} 
	}
	
	
	,init:function(opts){
		var $this = this;
		this.cmbBox 		= opts.cmbBox;
		this.addrBox 		= this.cmbBox.componentWrapper.find('div.cmbAddrBox:last');
		this.list			= this.addrBox.find('ul');
		/*this.closeAddrBox	= this.addrBox.find('.cmbCloseAddrBox');	*/	
		this.el				= this.cmbBox.el;
		this.hiddenField	= this.cmbBox.hiddenField;	
		this.store			= {};
		this.source			= this.cmbBox.source;
		/*this.el.keydown(function(e){
			if(e.keyCode==13) {
				$this.el.trigger('blur');
			}
		});*/
	}
} //validateBox



/**
 * Constructor of comboBox...
 */
$.cmbBox = function(options) { 

	/**
	 * Initialize component for passed elements::
	 */
	var options = options || {};
	var inputBox = $(options.el);
	
	/**
	 * Autocomplete off turn :)
	 */
	inputBox.attr("autocomplete", "off");
	
	
	/**
	 * Make necessary HTML elements, add ID to wrapper:: :->
	 */
	if(options.wrap==true) {
		inputBox
			.wrap(	  "<div class='cmbWrapper' id='"
					+ inputBox.attr('id')
					+ "cmbWrapper'><div class='cmbInputWrapper'></div></div>")				
			.after("<div 	class='cmbArrow' >&nbsp;</div>")
			.addClass('cmbInputBox')
			.parent()
			.after("<div class = 'cmbAddrBox'><div class = 'cmbAddrExplanation'>Select one from a list of found addresses:</div><ul class='cmbAddr'></ul><div class='cmbCloseAddrBox'>close <strong>X</strong>&nbsp;</div></div><div class='cmbSuggestionBox'><div class='cmbHistoryBaloon'>History<br>list</div><ul class='cmbSuggestions'></ul></div>");
	}
	
	
	var wrapper = (inputBox.parent());

	/**
	 * Call main init function:
	 */
	
	this.init({
		  wrapper		: wrapper
		, inputBox		: inputBox
		, historyData	: options.historyData
		, corners		: options.corners
		, store			: options.store /*Could be data object or object URL strings! */
		, emptyText		: options.emptyText || 'Enter address'
		, source		: options.source || null
		, airportBox	: options.airportBox || null
	})

}


/**
 * core cmbBox component code::
 */
$.cmbBox.prototype = {
	

	/**
	 * do validation of component. This is a main function!!
	 */
	validate : function() {
		this.validateBox.doQuery(this.getRawValue());
	}
	
	
	/**
	 * Return if component is Valid? 
	 */
	,isValid : function() {
		/**
		 * Do validation there!! or not?
		 */
	}	
	
	/**
	 * Clears invalid state of component 
	 */
	,clearInvalid : function() {
		this.el.removeClass('addrNotFound');
	}
	
	/**
	 * Marks invalid state of component
	 */
	,markInvalid : function() {
		this.el.addClass('addrNotFound');
	}

	/**
	 * Clear valid state of component
	 */
	,clearValid : function() {
		this.el.removeClass('addrFound');
	}
	
	/**
	 * Mark valid state of component
	 */
	,markValid : function() {
		this.el.addClass('addrFound');
	}




	/**
	 * Collapses list if somewhere outside clicked...
	 * @param {Object} e
	 * @param {Object} reference to THIS object...
	 */
	,collapseIf: function(e, $this) {
		if (!$.isAncestor($this.componentWrapper, $(e.target))) {
			$this.collapse();
		};
	}

	/**
	 * Returns element of component
	 */
	,getEl: function() {
		return this.el;
	}
	
	/**
	* Returns "Still validating message"
	**/
	,getStillValidatingMsg: function() {
		return this.stillValidatingMsg;
	}
	
	/**
	 * collapses the list::
	 */
	,collapse : function(){
		if(!this.isExpanded()){
			return;
		}
		this.wrapper.hide();
		this.list.find('li.hover').removeClass('hover');
		$(document).unbind('mousedown');
	}
	
	/**
	 * return if cmbBox is expanded::
	 */
	,isExpanded: function(){
		return (this.wrapper.css('display')!='none');
	}
	
	
	/**
	* returns empty text for control
	*/
	,getEmptyText: function() {
		return this.emptyText;
	}
	
	
	/**
	 * returns if location is airport or not
	 */
	,getIsAirport: function() {
		return this.isAirport;
	}
	
	/**
	* Toggle expand::
	*/ 
	,toggleExpand: function() {
		if(this.isExpanded()) {
			this.collapse();
		} else {
			this.expand();
		}
	}
	
	/**
	 * Expand 
	 */
	,expand : function(){
		
		if(this.isExpanded() || this.getCount()<1 || !this.hasFocus){
			return;
		}
		
		
		
		/**
		 * LATER UNCOMMENT THIS BELOW!!
		 */
		/*if(this.validateBox.isExpanded()) {
			this.validateBox.collapse();
		}*/

		this.wrapper.show();

		/**
		 * select first element in list::
		 */		
		this.select(++this.selectedIndex);
		
		
		var $this = this;
		$(document).mousedown(function(e){
			$this.collapseIf(e,$this);
			//return false;
		});
	}
	
	/**
	 * initialize component::
	 */
	,init : function(opts) {
		
		var $this = this;
		/**
		 * Init vars::
		 */
		this.componentWrapper	= opts.wrapper;
		this.largeWrapper		= opts.wrapper.parent();
		this.arrow				= opts.wrapper.find('.cmbArrow').eq(0);
		this.cmbInputWrapper	= opts.wrapper.find('.cmbInputWrapper');
		this.stillValidatingMsg = opts.wrapper.find('.cmbStillValidating');
		this.el					= opts.inputBox;
		this.list 				= opts.wrapper.find('ul.cmbSuggestions').eq(0);
		this.wrapper	 		= opts.wrapper.find('.cmbSuggestionBox').eq(0);
		this.emptyText			= opts.emptyText || "Enter text";
		this.hiddenField		= $("<input name='"+this.el.attr('name')+"Value' style='display:none' type='hidden'/>").insertAfter(this.el);
		this.selectedIndex		= -1;
		this.source				= opts.source || null;
		this.optsStore			= opts.store;
		this.helpLabel			= opts.wrapper.find('.helpLabel');
		this.helpLabelText		= this.helpLabel.text();
		this.isAirport			= false;

		/**
		 * Initialize AirportBox:
		 */
		this.airportBox 		= opts.airportBox || null ; 

		
		/**
		 * TimeOut for suggestion (in ms)::
		 */
		this.timeOut			= 100;
		
		
		
		/**
		 * Initialize validateBox
		 */
		this.validateBox = new $.validateBox({
			cmbBox : this
		});





		/**
		 * init store::
		 */
		if(this.optsStore.mode=='remote')
		
		{
			/**
			 * Remote mode::
			 */
			this.mode='remote';
			this.store = {};
			this.storeUrlValidate 	= this.optsStore.urlValidate.url;
			this.storeUrlAddresses	= this.optsStore.urlAddresses.url;
			this.storeUrlSelect		= this.optsStore.urlSelect.url;
		} else if (this.optsStore.mode=='local') {
			/**
			 * Local Mode::
			 */
			this.mode='local';
			this.store	= opts.store.data;
		} else {
			throw('Fatal error initializing store!!!');
		}

		// if cmbBox value iz not set, apply empty text!!
		if(!this.el.val().length || this.el.val()==this.emptyText) {
			this.applyEmptyText();		
		}
		this.initEvents();
		//this.renderList();
		
	}
	
	
	/**
	 * Apply Default value!
	 */		
	,applyEmptyText:function(){
		this.el	.val(this.emptyText)
				.addClass('defaultText');
		this.clearInvalid();
		this.clearValid();
		this.hiddenField.attr('value','');
	}

	
	/**
	 * Initialize keyEvents for txtBox::
	 */
	,initEvents:function(){
		
		var $this = this;
		
		this.el
			.focus(function(){
				if ($this.getRawValue() == '') {
					$this.setValue({
						text: '',
						value: '',
						source: ''
					});
				}
				if($this.ajaxSuggestCall) {
					$this.ajaxSuggestCall.abort();
				}				
				$this.hasFocus = true;
				$this.loadIndicator(false);
				$this.validateBox.collapse();
				$(this).removeClass('defaultText')
				
			})
			.blur(function(e){
				$this.onBlur();
			})
			.keydown(function(e){
				switch (e.keyCode) {
					case 9: //tab
							//$this.onViewClick();
					  break;
					case 27: //ESC
						$this.collapse();
					  break;
					case 38: //keyUP
						$this.selectPrev();
					  break;
					case 40: //keyDown
						if(!$this.isExpanded()){
							$this.onTriggerClick();
						}else{
							$this.selectNext();
						}
					  break;
					case 13: //Enter
						$this.onViewClick();
						e.preventDefault();
					  break;
				}
			})
			.keyup(function(e){
				switch (e.keyCode) {
					case 9:		//tab
					case 16:	//shift
					case 27:	//ESC
					case 38:	//keyUp
					case 39:	//key
					case 37:	//key
					case 40:	//keyDown
					case 13:	//Enter
					  break;
					default:
						if($this.getRawValue()!='') {
							/**
							 * this occurs when user start to change value in cmbBox:
							 */
							if ($this.airportBox) {
								$this.airportBox.collapse();
								
								//provide:: .is(":visible") here instead of css.(...) ::
							 	if ($this.airportBox.infoLabel.css('display') != 'none') {
									$this.airportBox.clearInfoLabel();
								}
							}
							
							$this.isAirport = false;
							
							
							//clear undo label below input field::
							$this.clearUndoLabel();
							$this.clearValue();
							
							if($this.ajaxSuggestCall) {
								$this.ajaxSuggestCall.abort();
							}
							setTimeout(function(){
								$this.doQuery($this.getRawValue());
							},$this.timeOut);
						} else {
							$this.collapse();
						}
					  break;
				}
			})
		this.arrow
			.click( 
				  function(e){
				  	e.preventDefault();
					$this.el.focus();
					$this.onTriggerClick();
					return false;
				  }
			)
			
		/**
		 * fix for IE6 :hover bug::
		 */
		/*if($.browser.msie && $.browser.version < 7) {
			alert('aaa');
			this.arrow	
			.hover( 
				  function(){
					$(this).addClass('over');
				  }
				, function(){
					$(this).removeClass('over');
				  }
			)
		}*/
		
		
		
		
			/*.mousedown(function(){$(this).addClass('click')})
			.mouseup(function(){$(this).removeClass('click')})
			.hover( 
				  function(){
					$(this).addClass('over');
				  }
				, function(){
					$(this).removeClass('over');
				  }
			)*/
	}

	/**
	 * Initializes a list with events...
	 */
	,initListEvents : function() {
		this.listItems = this.list.find("li:not('.category')");
		var $this=this;
		this.listItems
			.hover(
				function() {
					$this.listItems.filter('.hover').removeClass('hover');
					$(this).addClass('hover');
				}
				,function(){
				}
			)
			.mousedown(function(e){
				//e.stopPropagation();
				//e.preventDefault();
				//return false;
				$this.mouseDown=true;
			})
			.click(function() {
				//Do not populate field when clicked on "edit history"::
				if(!$(this).hasClass('editHistory')) {
					$this.onViewClick();
				}
			});
	}
	
	
	/**
	 * Renders LI elements according to this.store...
	 */
	, renderList: function(params){
		if(this.getCount()>0) {
			var store = this.store;
			var li='';
			for (var key in store) {
				/**
				 * check whether is store in remote mode, if yes then check store length
				 */
				if(key!='length' && (this.mode=='remote'?store[key].length>0:true)) {
					li+="<LI class='category'>"+key+"</LI>";
					$.each(store[key], function(i,j){
						li += '<LI value='+j.value+'>'+j.label+'</LI>';
					})
				}
			}
			
			if(typeof params == 'object' && params.historyAddresses == true ) {
				/**
				 * render 'Edit history label'...
				 */
				li += "<LI class='editHistory'><a href = 'userAddress.do'>Edit history addresses...</a></LI>";
			}
			this.list.html(li);
			this.selectedIndex=-1;
			this.initListEvents();
		}
	}
	
	
	
	/**
	 * Render label for undoing validation::
	 * @param cmbBoxValue
	 */
	,renderUndoLabel : function(cmbBoxValue) {

		if(typeof cmbBoxValue == 'undefined') {
			throw "fatal error rendering undo Label."
			return;
		}
		
		var $this = this;

		this.undoHandlerSelector = this.el.attr('id')+"UndoHandler";
		var html = "<span style='color:#55bb55'>Address validated.</span>If address is not correct,<a href='#' id='"+this.undoHandlerSelector+"'>click here.</a>";
		
		this.helpLabel.html(html);
		

		//assign event handler::
		$('#'+this.undoHandlerSelector).click(function(){
			$this.el.val(cmbBoxValue);
			$this.clearUndoLabel();	
			$this.validateBox.onEmptyResults();
			if($this.airportBox) {
				$this.airportBox.clearInfoLabel();
			}
			
			$this.isAirport = false;
			
			/**
			* Provide AJAX CALL also ::
			*/
			$.ajax ({
				type	: "GET"
			  , url		: $this.storeUrlSelect
			  , dataType: "text"
			  , cache	: false
			  , success	: function(){}
			  , error	: function(){} 
			  , data	: {
			  		id	: -1
			  }
			});
		})
	}
	
	
	/**
	 * Clears label for undiong validation::
	 */
	,clearUndoLabel : function() {
		if (this.undoHandlerSelector) {
			$('#' + this.undoHandlerSelector).unbind()
			this.undoHandlerSelector = false;
			this.helpLabel.html(this.helpLabelText);
		}
	}
	
	/**
	 * gets total returned elements ...
	 */
	,getCount:function(){
		return this.store.length;
	}


	/**
	 * set Value of component 
	* @param {Object} params to set
	 * e.g.: params :{value:'4', text:'145 ave', source:'0'} 
	 */
	,setValue:function(params) {

		this.el
			.removeClass('defaultText')
			.val(params.text);
		
		if (params.text!='' && !isNaN(parseInt(params.value))){
			this.markValid();
			this.hiddenField.attr('value', params.value);
			this.onValueSet(params.source);
		}
		
	}
	
	,clearValue:function(){
		this.hiddenField.attr('value', '');
		this.clearInvalid();
		this.clearValid();
	}

	
	/**
	 * get ID from cmbBox element!
	 */
	,getValue:function() {
		var value = this.hiddenField.attr('value');
		return ((isNaN(parseInt(value))||typeof value== 'undefined' || value === null)?'':value);
	}
	
	/**
	 * get raw value from inputBox!
	 * @param {Object} value
	 */
	,getRawValue:function(){
		var v = this.el.val();
		if(v === this.emptyText){
			v = '';
		}
		return v;
	}
	
	/**
	 * Does querying dataset for value entered!
	 * filtering dataset and return filtered dataset!
	 */
	,doQuery : function(value){
		
		var filteredRows = 0;

		if(this.mode=='local'){

			/**
			 * clone the store object into snapshot object,
			 * THIS IS DONE ONLY FOR THE FIRST TIME!!!
			 */

			 if(typeof this.snapshot!='object') {
				this.snapshot =  $.clone(this.store);
			}
			
			
			this.store = $.clone(this.snapshot);
			var store = this.store;
			
			for (var key in store) {
				var found=false;
				if(key!='length') {
					$.each(store[key], function(i,j){
						var position = j.label.toLowerCase().indexOf(value.toLowerCase(), 0); 

						if (position > -1) {
							/**
							 * Found!
							 */
							filteredRows++;
							found=true;
						} else {
							delete store[key][i];
						}
						
					});
					if(!found) {
						delete store[key];
					}

				}
			}
			
			this.store.length = filteredRows;
			this.onLoad();
			
		} else if (this.mode=='remote') {
			/**
			 * Load results from remote server::
			 */
			this.storeLoad({value:value, loadIndicator:true});
		}
	}
	
	
	/**
	 * load store - remote mode only!
	 */
	,storeLoad : function(options) {
		if (typeof options.loadIndicator == "undefined") {
			options.loadIndicator = true;
		}
		if(options.loadIndicator) {
			this.loadIndicator(true);
		}
		var $this = this;
		
		var ajaxObj = {
			type	: "GET"
		  , url		: $this.storeUrlAddresses
		  , dataType: "json"
		  , cache	: false
		  , success	: function(a) {
				$this.store = a;
				/**
				 * CLONE STORE, but ONLY ONCE!! 
				 */
				/*if(typeof $this.snapshot!='object') {
					$this.snapshot =  clone($this.store);
				}		*/			
				$this.onLoad();
			}
		  , error	: function() {
				$this.onLoadError();
			} 

		  , data	: {}
		} 			
		
		ajaxObj.data[$this.optsStore.urlAddresses.queryText] = options.value;
		this.ajaxSuggestCall=$.ajax(ajaxObj);
	}
	
	
	
	/**
	 * shows or hides loading indicator according to flag...
	 * @param {Object} flag
	 */
	,loadIndicator:function(flag){
		if(flag) {
			this.el.addClass('loading');
		} else {
			this.el.removeClass('loading');
		}
	}
	
	/**
	 * Choose value on click...
	 * @param {Object} doFocus
	 */
	,onViewClick : function(){
		var li = this.list.find("li.hover:first");
		if($(li).text()) {
			this.setValue({
				  text 	: $(li).text()
				, value	: (typeof($(li).attr('value'))=='undefined'?'0':$(li).attr('value'))
				, source: '1'			
			})
			this.el.focus();
		} 
		
	}		
	
	/**
	 * Fires when user go out from input box
	 */
	,onBlur : function() {

		/**
		* fix for IE ordering of events:: first mouseDown, then blur 
		*/
		if(this.mouseDown) {
			this.mouseDown=false;
			return;
		}

		this.mouseDown=false;
		
		this.hasFocus = false;
		this.collapse();
		
		//console.log(this.mouseDown);
		this.loadIndicator(false);
		if(this.ajaxSuggestCall) {
			this.ajaxSuggestCall.abort();
		}
		if(isNaN(parseInt(this.getValue())) && this.getRawValue()!='') {
			/**
			 * if value is not set, validate address:
			 */
			this.validate();
		} else if (this.getRawValue() == '') {
			this.applyEmptyText();
		}
	
	}
	
	/**
	 * fires when triggers click :))
	 */
	, onTriggerClick : function() {

		/**
		 * if box is not expanded, load history data and expand it...
		 */
		if (!this.isExpanded()) {

			this.loadIndicator(true);
			var $this = this;
			var ajaxObj = {
				type: "GET",
				url: $this.storeUrlAddresses,
				dataType: "json",
				cache: false,
				success: function(a){
					$this.store = a;
					/**
					 * params:
					 * historyAddresses:true
					 * whether to render 'edit history addresses on the end of the list!!
					 */
					$this.onLoad({
						historyAddresses: true
					});
				},
				error: function(){
					$this.onLoadError();
				},
				data: {
					query: ''
				}
			}
			$.ajax(ajaxObj);
		} else {
			this.collapse();
		}
		
		
		/*
		if(this.getRawValue()=='') {
			/**
			 * if empty value, then reset store::
			 *
			if(typeof this.snapshot=='object') {
				**
				 * reset store::
				 *
				this.store = $.clone(this.snapshot);
			}
			this.onLoad();
		} else {
			this.toggleExpand();
		}*/
	}
	
	/**
	 * triggers on load event!
	 * params: 
	 * historyAddresses:true
	 * whether to render 'edit history addresses on the end of the list!!
	 */
	,onLoad : function(params){
		this.selectedIndex = -1;
		this.loadIndicator(false);
		this.ajaxSuggestCall = null;
		this.collapse();
		if(this.getCount() > 0){
			this.renderList(params);
			this.expand();
			/*if(!this.selectByValue(this.value, true)){
				this.select(0, true);
			}*/
		}else{
			this.onEmptyResults();
		}
	}
	
	/**
	 * triggers when error loading...
	 */
	,onLoadError : function() {
		this.loadIndicator(false);
		this.markInvalid();
	}
	
	
	/**
	 * fires when there are no results!
	 */		
	,onEmptyResults:function(){
		this.collapse();
	}
	
	
	/**
	 * triggers when value of inputbox is set
	 */
	,onValueSet:function(source){

		var $this = this;
		
		var ajaxObj = {
			type	: "GET"
		  , url		: $this.storeUrlSelect+'?source='+source
		  , dataType: "text"
		  , cache	: false
		  , success	: function(s) {
				$this.collapse();
				$this.validateBox.collapse();
				var results = eval('(' + s + ')');
				
				/**
				 * update flag if is airport:
				 */				
				if(results.category=="AIRPORT") {
					$this.isAirport = true;
				} else {
					$this.isAirport = false;
				}

		  		if($this.airportBox && results.category=="AIRPORT" && $.cmbBox.prototype.displayFlightDetails) {
					//clear previous field values in airportbox and displays airport box::
					$this.airportBox.clearFields();
					$this.airportBox.render();
				} 
			}
		  , error	: function() {
				//throw error.
		  } 
		  , data	: { }
		} 
		ajaxObj.data[$this.optsStore.urlSelect.queryText] = this.getValue();
		$.ajax(ajaxObj);

		this.clearInvalid();
		this.markValid();
		this.collapse();
		this.validateBox.collapse();
		
	}
	
	
	/**
	 * Select an item in the dropdown list by its numeric index in the list.
	 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
	 * @param {Number} index The zero-based index of the list item to select
	 */
   , select : function(index){
		this.selectedIndex = index;
		
		this.listItems
			.removeClass('hover')
			.eq(index).addClass('hover');
	 }

	// private
	,selectNext : function(){
		var ct = this.getCount();
		if(ct > 0){
			if(this.selectedIndex == -1){
				this.select(0);
			}else if(this.selectedIndex < ct-1){

				//this.selectedIndex = this.listItems.index($('.hover')[0]);
				/*this.selectedIndex = this.listItems.index(this.listItems.filter('.hover'));*/

				this.select(++this.selectedIndex);
			}
		}
	}

	// private
	,selectPrev : function(){
		var ct = this.getCount();
		if(ct > 0){
			if(this.selectedIndex == -1){
				this.select(0);
			}else if(this.selectedIndex != 0){
				//this.selectedIndex = this.listItems.index($('.hover')[0]);
				/*this.selectedIndex = this.listItems.index(this.listItems.filter('.hover'));*/
				this.select(--this.selectedIndex);
			}
		}
	}
	

}; //cmbBox();


})(jQuery);
