
// Wm Select
{
	let $ = jQuery; 
	WmSelect = function($select){
		let self = this;
		this.$mainDiv = undefined;
		this.$selectDiv = $('<div class="wmSelectDisplay"><span class="wmsText">Select</span><div class="wmSelectBody"><input type="text" tabindex="-1" /><div class="wmSelectList"></div></div></div>');
		if($select.is('.wmSelectShowValue'))
			this.$selectDiv.addClass('showValue');
		
		this.$selectBody = this.$selectDiv.find('.wmSelectBody');
		this.$selectList = this.$selectDiv.find('.wmSelectList');
		this.$select = $select;
		this.$select.change(() => {
			this.currentSelectedKey = this.getOptionSelected().key
		});
		this.$select.focus(() => {
			this.open();
		});
		
		this.selectionOffset = 0;
		
		this.execSearch = function(val){
			val = val || this.$selectBody.find('input[type=text]').val();
			val = ''+$.trim(val); // Just in case
			val = val.toLowerCase();
			
			let searchTerms = val.split(' ');
			
			
			this.options.forEach( (option, key) => {  
				if($(option.dom).is('[disabled="disabled"]'))
					$(option.wmDom).addClass('disabled');
				else
					$(option.wmDom).removeClass('disabled');
			});  
			
			let eq = 0;
			this.visibleOptionsKeys = [];
			if(val == '')
			{ 
				this.selectionOffset = this.getOptionSelected().key;
			
				this.options.forEach( (option, key) => { 
					this.visibleOptionsKeys.push(key);
					$(option.wmDom).removeClass('hidden');
					$(option.wmDom).attr('even', (eq % 2 == 0) ? 1 : 0);
					eq++;
					
				});
			}
			else
			{  
				this.selectionOffset = 0; // Reset
				this.visibleOptionsKeys = [];
				this.options.forEach( (option, key) => { 
					if(val.indexOf(' ')>=0)
					{
						// Multi words 
						var allOk = true;
						searchTerms.forEach( word => {
							if(!(option.htmlLower.indexOf(word) >= 0))
								allOk = false;
						});
						if(allOk)
						{
							this.visibleOptionsKeys.push(key);
							$(option.wmDom).removeClass('hidden');
							$(option.wmDom).attr('even', (eq % 2 == 0) ? 1 : 0);
							eq++;
						}
						else 
							$(option.wmDom).addClass('hidden');
					}
					else
					{
						if(!(option.htmlLower.indexOf(val) >= 0))
							$(option.wmDom).addClass('hidden');
						else
						{ 
							this.visibleOptionsKeys.push(key);
							$(option.wmDom).removeClass('hidden');
							$(option.wmDom).attr('even', (eq % 2 == 0) ? 1 : 0);
							eq++;
						} 
					}
				});
			}
			this.repositionBody(); 
			this.preselectOption();
		}
		
		this.$selectBody.find('input[type=text]').each(function(e){
			
		
			let val = $(this).val();
			let timeout = false;
			$(this).keydown( e => { 
				if(e.key == 'ArrowDown')
					self.selectionOffset++;
				else if (e.key == 'ArrowUp')
					self.selectionOffset--;
					
				if(self.selectionOffset < 0)
					self.selectionOffset = 0;
				else if(self.selectionOffset >= self.visibleOptionsKeys.length)
					self.selectionOffset = self.visibleOptionsKeys.length - 1;
				
				self.preselectOption(); 
				
				if(e.key == 'ArrowDown' || e.key == 'ArrowUp')
				{
					e.preventDefault();
					return false;
				}
				val = $(this).val();
			});
			
			$(this).keyup( e => {
				
				if(e.key == 'ArrowDown' || e.key == 'ArrowUp')
				{
					e.preventDefault();
					return false;
				}
			
				if(timeout)
					clearTimeout();
					
				timeout = setTimeout( () => {
					timeout = false;
					let newVal = $(this).val(); 
					if(newVal != val)
					{
						self.execSearch(newVal);
					}
				}, 100);
			});
		});
		
		this.$selectBody.find('input[type=text]').blur(() => { 
			this.close();
		});
		
		this.open = () => { 
			this.show();
			this.$selectDiv.addClass('loading');
			this.$select.hide();
			this.$selectBody.css({ opacity : 0, pointerEvents : 'none' });
			this.$selectDiv.addClass('open');
			setTimeout( e => { 
				this.execSearch('');
				this.repositionBody(); 
				this.$selectBody.css({ opacity : 1, pointerEvents : 'all' });
				this.$selectBody.find('input[type=text]').focus();
				this.$selectDiv.removeClass('loading');
				this.preselectOption(); 
				
			}, 10);
		};
		this.repositionBody = () => {
			this.$selectBody.css('--height', (this.$selectBody.outerHeight())+'px');
		}
		
		this.select = () => {
			if(this.visibleOptionsKeys.length > 0)
			{
				let option = this.options[this.visibleOptionsKeys[this.selectionOffset]]; 
				this.$select.val(option.value); 
				this.$select.triggerHandler('change');
				this.updateWmsValue();
				
				
				this.currentSelectedKey = option.key; 
			}
		};
		
		this.close = () => {
			this.select();
		 
			this.hide(); 
			this.$selectDiv.removeClass('open');
			setTimeout( e => this.$select.show() , 2);
			setTimeout( e => {
				this.$selectDiv.find('input[type=text]').val('');
				this.selectionOffset = this.getOptionSelected().key;
				this.visibleOptionsKeys = [];
				this.options.forEach( (option, key) => { 
					this.visibleOptionsKeys.push(key);
					$(option.wmDom).removeClass('hidden');
				});
				
			}, 4)
		}
		
		this.$selectList.mousedown( e => e.preventDefault());
		this.$selectList.click( e => e.preventDefault());
		
		this.$selectDiv.click( () => {
			if(!this.$selectDiv.is('.open'))
			{ 
				this.$select.focus(); 
			}
		});		
		this.currentSelectedKey = 0;
		this.options = [];
		this.indexValueToKey = {};
		this.indexDomToKey = {};

		this.visibleOptionsKeys = [];
		
		this.preselectOption = () => {  
			this.$selectList.find('.preselect').removeClass('preselect');
			if(this.visibleOptionsKeys.length > 0)
			{
			
 				let keySelection = this.visibleOptionsKeys[this.selectionOffset ];
				$(this.options[keySelection].wmDom).addClass('preselect');
			}
			
			if(this.$selectList.find('.preselect').length > 0)
			{  
				this.$selectList[0].scrollTop = (this.$selectList.find('.preselect')[0].getBoundingClientRect().height+2) * (this.selectionOffset - 3);
			}
		};
		this.hide = () => { 
			this.$mainDiv.css({
				display : 'none'
			})
		}
		this.show = () => { 
			this.$mainDiv.css({
				display : 'block'
			});
			setTimeout( e => this.updateListOverflow() , 1);
		};
		this.updateListOverflow = () => {
			this.$selectList[0].scrollTop = 0;
			// let bottomList = this.$selectList[0].getBoundingClientRect().bottom; 
			// let bottomLast = this.$selectList.find('.wmSelectItem:last')[0].getBoundingClientRect().bottom;
			// if(bottomLast > bottomList)
			// {
				// this.$selectList.css('overflow-y','scroll');
				// this.$selectBody.find('input[type=text]').css('width','calc(100% - 8px)');
			// }
			// else
			// {	
				// this.$selectList.css('overflow-y','hidden');
				// this.$selectBody.find('input[type=text]').css('width','calc(100% - 2px)');
			// }
		}
		
		this.updateContent = () => {
			this.options.forEach( (option, key) => {
				let wmsItemText = '<div class="wmsItemText">'+option.html+' </div>';
				let $item = $('<div class="wmSelectItem">'+wmsItemText+'<div class="wmSelectValue">'+option.value+'</div></div>'); 
				$item.click( e => {
					e.stopPropagation();
					e.preventDefault();
					 
					self.visibleOptionsKeys.forEach( (keyTarget, offset) => { 
						if( key == keyTarget )
						{
							self.selectionOffset = offset;
							self.preselectOption();
						}
					});
					setTimeout( () => { 
						self.close();
					}, 1)
				});
				if(option.iconUrl)
				{
					$item.addClass('hasIcon'); 
					$item.css('--iconUrl', 'url("'+option.iconUrl+'")');  
				} 
				this.$selectList.append($item); 
				option.wmDom = $item[0];
				
			})
		};
		
		this.updateWmsValue = () => {
			this.$selectDiv.find('.wmsText').eq(0).html(this.getOptionSelected().html);  
			if(this.getOptionSelected().iconUrl)
			{
				this.$selectDiv.addClass('hasIcon');
				this.$selectDiv.css('--iconUrl','url('+this.getOptionSelected().iconUrl+')');
			}
			else
			{
			
				this.$selectDiv.removeClass('hasIcon');
				this.$selectDiv.css('--iconUrl','none');
			}
		} 
		this.init = () => {   
			this.$mainDiv = $('<div class="wmSelectController"></div>');
			this.hide(); 
			let defaultText = this.$select.attr('wmSelectPlaceholder') || "Select from the list :"; 
			if(!$select.is('.noNullValue'))
				if(this.$select.find('option[value="__noSelection__"]').length == 0)
					this.$select.prepend('<option value="__noSelection__">'+defaultText+'</option>'); 
			
			if(this.$select.find('option[selected]').length == 0)
				this.$select.find('option[value="__noSelection__"]')[0].selected = true;
			
			this.$select.find('option').each(function(){
				
				let html = this.innerHTML
				let value = this.value;
				var nextKey = self.options.length;
				let option = {
					key : nextKey,
					value : value, 
					html : html,
					htmlLower : html.toLowerCase(),
					iconUrl : $(this).attr('iconUrl') || false,
					dom : this,
					wmDom : false
				} 
				Object.defineProperty(option, "isSelected", { value : function(){
					return this.key == self.currentSelectedKey;
				}});
				
				if($(this)[0].selected) 
					self.selectionOffset = nextKey;
				
				
				self.options.push(option);
				self.indexValueToKey[value] = nextKey;
				self.visibleOptionsKeys.push(nextKey);
			});
			this.$select.data('WmSelect', this); 
			
			this.$mainDiv.appendTo($('body'));
			this.$select.after(this.$selectDiv);
			this.$select.addClass('hidden');
			this.updateSelectDivText();
			this.updateContent(); 
			this.updateWmsValue();
			setTimeout( () => {
				this.execSearch('');
			}, 10);
		}
		
		this.updateSelectDivText = () => {
			this.$mainDiv.appendTo($('body'));
			this.$selectDiv.find('.wmsText').html(this.getOptionSelected().html);

			
			if(this.getOptionSelected().iconUrl)
			{
				this.$selectDiv.addClass('hasIcon');
				this.$selectDiv.css('--iconUrl','url("'+this.getOptionSelected().iconUrl+'")');
			}
			else
			{
			
				this.$selectDiv.removeClass('hasIcon');
				this.$selectDiv.css('--iconUrl','none');
			}
		}
		this.getOptionByValue = (value) => {
			return this.options[this.indexValueToKey[value]];			
		}
		this.getDomValue = (value) => {
			return this.getOptionByValue(value).dom;
		}
		this.getOptionSelected = () => {
			if(this.$select.find('option:selected').length)
			{
		
		  		let optionSelected = this.$select.find('option:selected')[0];
				return this.getOptionByValue(optionSelected.value); 
			}
			return false;
		}
		this.init(); // Right Away 
	}

	WmSelectController = new (function(){
		let self = this; 
		this.list = []; 
		
		
		this.onLoad = () => { 
			$('.wmSelect').each(function(){
				self.init($(this));
			});	 
		}
		 
		this.initWithJson = ($select, jsonArray) => {
			// Json must be in format , [{ html : ..., value : ..., ?icon : ... })
			$select.find('option').remove();
			if(!$select.is('.wmSelect'))
				$select.addClass('wmSelect');
				
				
			let defaultText = $select.attr('wmSelectPlaceholder') || "Select from the list :"; 
			
			if(!$select.is('.noNullValue'))
				$select.prepend('<option value="__noSelection__">'+defaultText+'</option>');
			
			jsonArray.forEach( json => {
				let $option = $('<option></option>');
				$option.html(json.html);
				$option.attr('value', json.value);
				if(json.value+'' == $select.attr('value'))
					$option.attr('selected', 1);
				if(json.icon)
					$option.attr('iconUrl', json.icon);
				$select.append($option);
			});
			
			this.init($select);
			
		}
		this.init = $select => { 
			let _wmSelect = new WmSelect($select);
			this.list.push(_wmSelect);
			return _wmSelect;
		}
		
	});
 
}