//require $.DropShadow class
(function($){
    $.CustomSelects = [];

	$.CustomSelect = function(sb,options){
		if (!sb || !sb.get(0)) throw new Error("$.CustomSelect: Selectbox is not defined or not jQ extended");
		
	/*****Initialize*******/	
		sb.wrap('<div class="select_parent"></div>');
		this.container = sb.parent();
		
		this.select = sb;
		this.index = $.CustomSelects.length;
		$.CustomSelects.push(this);
		
		var self = this;
		this.isOpen = this.isFocused = 0;
		
		this.settings = $.extend({
			maxHeight: 400,
			zIndex: 1,
			openZIndex: 50000,
			ignoredValue:false, //Options with ignored value will only be processed by javascript
			functions:'',
			submitFunction: false, //Click or enter on an option will submit the form, which calls the submitFunction if it is defined, opts with ignoredValue will not trigger submit
			openCallback : false,
			closeCallback : false,
			truncateDisplay:16,
			openAtTop : false,
			dropShadow : false,
			scrollPaneOpts : {}
		},options);
		
		this.locked = false;
		this.parentForm = this.select.parent('form');
		
	/******Create DropDown*******/
		
		this.wrapper = $('<div id="customSelect_'+this.index+'" class="select_wrapper"></div>');
		this.dropDown = $('<div class="select_dropdown"></div>');
		this.listContainer = $('<div class="select_scroller"></div>');
		this.list = $('<ul class="select_list"></ul>');
		this.currentIndex = 0;
		this.opts = this.select.find('option');
		
		this.createList();
		
		var currentItem = this.opts[this.currentIndex].innerHTML;
		var wasTruncated = false;
		
		if (this.settings.truncateDisplay && currentItem.length > this.settings.truncateDisplay){
			currentItem = currentItem.substr(0,this.settings.truncateDisplay) + "...";		
			wasTruncated = "true";		
		}
		
		this.display = $('<div class="select_display"><span>'+currentItem+'</span></div>');
		this.displaySpan = this.display.find('span');
		
		if(wasTruncated) {
			this.displaySpan.addClass("truncated");	
		}
		
		this.listContainer.append(this.list);
		this.dropDown.append(this.listContainer);
		this.wrapper.append(this.display);
		this.wrapper.append(this.dropDown);
		this.container.append(this.wrapper);
		this.listContainer.wrap('<div class="select_dropdown_wrapper"></div>');
		
		this.setScrollPane();
		this.adjustWidth();
	/******Bind Events ******/
		
		$(document).click(function(e){
			if (self.isOpen){
				var parent = '#customSelect_'+self.index;
				if (!$(e.target).parents(parent).get(0)){
					self.close();
				}
			}
		}).keyup(function(e){
			if (self.isFocused||self.isOpen){
				self.changeValue();
				if (e.keyCode==9 || e.keyCode==13 || e.keyCode == 27){
					if (e.keyCode == 13){
						self.clickOption();
					}
					self.close();
				}
			}
		});
		
		this.display.click(function(){
			self.select.focus();
			self.isOpen ? self.close() : self.open();
		}).hover(function(){
			$(this).addClass('hovered');
		},function(){
			$(this).removeClass('hovered');
		});
		
		$("#" + this.wrapper.attr("id") + " li").live('click',function(e){
			e.preventDefault();
			self.clickOption(e.target);
			self.select.focus();
		}).live('mouseover',function(e){
			$(e.target).addClass("hovered");
		}).live('mouseout',function(e){
			$(e.target).removeClass("hovered");
		});
		
		this.select.focus(function(e){
			self.isFocused = true;
		}).blur(function(e){
			self.isFocused = false;
		});
	}

	/*******CustomSelect methods ******/
	$.CustomSelect.prototype = {
	
		createList : function(){
			var self = this,
				liString = '';
			
			this.opts.each(function(i){
				var $this = $(this);
				if (this.selected) { self.currentIndex = i; }
				
				var optgroup = $this.parents('optgroup');
				
				if (optgroup.length > 0 && $this.prev().length == 0){
					liString += '<li class="opt_group">'+optgroup.attr('label')+'</li>';				
				}
				
				liString += '<li class="select_opt--' + i +'">'+this.innerHTML+'</li>';			
			});
			
			this.list.html(liString);
			
			this.listItems = this.list.find('li');
			
			this.listItems.eq(0).addClass('first');
			this.listItems.eq(this.listItems.length - 1).addClass('last');
			
			this.selectables = [];
			
			this.listItems.each(function(){
				if (this.className.indexOf('opt_group') == -1){
					self.selectables.push($(this));
				}
			});
			
			this.selectables[this.currentIndex].addClass('selected');
			
			
		},
		
		setScrollPane : function(){
		    
			if (this.listContainer.outerHeight()>=this.settings.maxHeight){
				this.listContainer.css({height:this.settings.maxHeight - 14});
				this.scrollPane = this.listContainer.jScrollPane(this.settings.scrollPaneOpts);
			} else if (this.scrollPane){
				this.listContainer.css({height:'auto'}).jScrollPane(this.settings.scrollPaneOpts);
			}
		},
		
		resetScrollPane : function(){
			if (this.scrollPane){
				this.listContainer.jScrollPaneRemove();
			}
			this.setScrollPane();
		},
		
		matchToDisplay : function(){
			var self = this;
			if (this.opts.eq((this.select.get(0).selectedIndex)).html() != this.displaySpan.html()){
				this.opts.each(function(index){
					if (this.innerHTML == self.displaySpan.html()){
						self.select.get(0).selectedIndex = index;
						self.changeValue();
						return false;
					}
				});
			}
		},
		
		matchToValue : function(val){
			var self = this;
			this.opts.each(function(i){
				if (this.value == val){
					self.select.get(0).selectedIndex = i;
					self.changeValue();
					return false;
				}
			});
		},
		
		matchToIndex : function(){
			this.displaySpan.html(this.opts.eq((this.select.get(0).selectedIndex)).html());
		},
		
		updateList : function(){
			this.locked = true;
			this.opts = this.select.find('option');
			this.createList();
			this.setScrollPane();

			this.list.find('li').hover(function(e){
				$(this).addClass('hovered');
			},function(e){
				$(this).removeClass('hovered');
			});
				
			this.locked = false;
		},
		
		open : function(){
			if (this.isOpen || this.locked) return;
			this.wrapper.addClass('select_open');
			this.container.css({zIndex:this.settings.openZIndex});
						
			if (this.scrollPane && typeof this.scrollPane[0].scrollTo == "function") {
				
				this.scrollPane = this.listContainer.jScrollPane(this.settings.scrollPaneOpts);
				if (!this.settings.openAtTop){
					this.scrollPane[0].scrollTo('li.selected');
				}
				else {
					this.scrollPane[0].scrollTo('li:first');
				}
			}
			
			this.isOpen = true;
			
			if (typeof this.settings.openCallback == 'function'){
				this.settings.openCallback();
			}
		},
		
		close : function(){
			if (!this.isOpen) {
				this.locked = false;
				return;
			}
			this.container.css({zIndex:this.settings.zIndex});
			this.wrapper.removeClass('select_open');
			this.isOpen = this.locked = false;

			if (typeof this.settings.closeCallback == 'function'){
				this.settings.closeCallback();
			}
		},
		
		clickOption : function(tar){
			this.locked = true;
			
			if (tar && tar.className.indexOf('opt_group') != -1) return; //Always ignore optgroup clicks
			
			var select = this.select.get(0);
			var index;
			
			if (tar){
				index = parseInt(tar.className.split('--')[1]);
			} else {
				index = select.selectedIndex;
			}
			
			var value = select[index].value;
			
			if (this.settings.ignoredValue&&value.search(this.settings.ignoredValue) != -1){	
				
				if (typeof(this.settings.functions[value.replace(this.settings.ignoredValue + " ", "")])=='function'){
					
					this.settings.functions[value.replace(this.settings.ignoredValue + " ", "")]();
				
				}
				
			} else {
				select.selectedIndex = index;
				
				if (typeof(this.settings.submitFunction)=='function'){
					this.settings.submitFunction();
				}
				
				this.changeValue();
			}
			
			$(this.select).trigger("change");
			
			this.close();
			
		},
		
		changeValue : function(){
			var index = this.select.get(0).selectedIndex;
			if (index==this.currentIndex) return;
			
			$(this.selectables[this.currentIndex]).removeClass('selected'); //remove selected class from old item
			
			var newItem = $(this.selectables[index]);
			setTimeout(function() {newItem.addClass('selected');}, 50);
			
			if (this.itemVisible(newItem)==false&&this.scrollPane){
				this.scrollPane[0].scrollTo('li.selected');
			}
			
			var truncated = newItem.html();
			
			this.displaySpan.removeClass("truncated");
			
			if (this.settings.truncateDisplay && newItem.html().length > this.settings.truncateDisplay){
				truncated = newItem.html().substr(0,this.settings.truncateDisplay) + "...";		
				this.displaySpan.addClass("truncated");
			} 
			
			this.displaySpan.html(truncated);
			this.display.data("Value",this.select.val());
			
			this.currentIndex = index;
			this.adjustWidth();
		},
		
		adjustWidth : function(){
			this.container.width(this.displaySpan.width());
		},
		
		itemVisible : function(item){
			if (!this.isOpen) return true;
			var pos = item.offset().top;
			var top = this.dropDown.offset().top;
			if (pos>top && pos+item.height()<top+this.dropDown.height()){
				return true;
			}
			return false;
		},
		
		jumpToIndex : function(index){
			if (index<this.opts.length){
			
				this.select.get(0).selectedIndex = index;
				this.changeValue();
			
			}
		},
		
		jumpToValue : function(value){
			var index = -1;
			
			this.opts.each(function(i){
				if (this.value==value){
					index = i;
					return false;
				}
			});
			
			if (index!=-1){
				this.select.get(0).selectedIndex = index;
				this.changeValue();
			}
			
			return index;
		},
		
		editOptionText : function(index,text){
			this.opts.eq(index).html(text);
			this.updateList();
		}
	};
})(jQuery);