// MSDropDown - jquery.dd.js
// author: Marghoob Suleman - http://www.marghoobsuleman.com/
// Date: 10 Nov, 2012
// Version: 3.0
// Revision: 16
// web: www.marghoobsuleman.com
/*
// msDropDown is free jQuery Plugin: you can redistribute it and/or modify
// it under the terms of the either the MIT License or the Gnu General Public License (GPL) Version 2
*/
var msBeautify = msBeautify || {};
(function ($) {
msBeautify = {
	version: '3.0',
	author: "Marghoob Suleman",
	counter: 20,
	debug: function (v) {
		if (v !== false) {
			$(".ddOutOfVision").css({height: 'auto', position: 'relative'});
		} else {
			$(".ddOutOfVision").css({height: '0px', position: 'absolute'});
		}
	},
	oldDiv: '',
	create: function (id, settings, type) {
		type = type || "dropdown";
		var data;
		switch (type.toLowerCase()) {
		case "dropdown":
		case "select":
			data = $(id).msDropdown(settings).data("dd");
			break;
		}
		return data;
	}
};

$.msDropDown = {};
$.msDropdown = {};
$.extend(true, $.msDropDown, msBeautify);
$.extend(true, $.msDropdown, msBeautify);
// make compatibiliy with old and new jquery
if ($.fn.prop === undefined) {$.fn.prop = $.fn.attr;}
if ($.fn.on === undefined) {$.fn.on = $.fn.bind;$.fn.off = $.fn.unbind;}
if (typeof $.expr.createPseudo === 'function') {
	//jQuery 1.8  or greater
	$.expr[':'].Contains = $.expr.createPseudo(function (arg) {return function (elem) { return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0; }; });
} else {
	//lower version
	$.expr[':'].Contains = function (a, i, m) {return $(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0; };
}
//dropdown class
function dd(element, settings) {
	var _settings = $.extend(true,{byJson: {data: null, selectedIndex: 0, name: null, size: 0, multiple: false, width: 250},
		mainCSS: 'dd',
		height: 120, //not using currently
		visibleRows: 7,
		rowHeight: 0,
		showIcon: true,
		zIndex: 9999,
		useSprite: false,
		animStyle: 'slideDown',
		event:'click',
		openDirection: 'auto', //auto || alwaysUp
		jsonTitle: true,
		style: '',
		disabledOpacity: 0.7,
		disabledOptionEvents: true,
		on: {create: null,open: null,close: null,add: null,remove: null,change: null,blur: null,click: null,dblclick: null,mousemove: null,mouseover: null,mouseout: null,focus: null,mousedown: null,mouseup: null}
		}, settings);								  
	var _this = this; //this class	 
	var _holderId = {postElementHolder: '_msddHolder', postID: '_msdd', postTitleID: '_title',postTitleTextID: '_titleText', postChildID: '_child'};
	var _styles = {dd:_settings.mainCSS, ddTitle: 'ddTitle', arrow: 'arrow arrowoff', ddChild: 'ddChild', ddTitleText: 'ddTitleText',disabled: 'disabled', enabled: 'enabled', ddOutOfVision: 'ddOutOfVision', borderTop: 'borderTop', noBorderTop: 'noBorderTop', selected: 'selected', divider: 'divider', optgroup: "optgroup", optgroupTitle: "optgroupTitle", description: "description", label: "ddlabel",hover: 'hover',disabledAll: 'disabledAll'};
	var _styles_i = {li: '_msddli_',borderRadiusTp: 'borderRadiusTp',ddChildMore: 'border shadow',fnone: "fnone"};
	var _isList = false, _isMultiple=false,_isDisabled=false, _cacheElement = {}, _element, _orginial, _isOpen=false;
	var DOWN_ARROW = 40, UP_ARROW = 38, LEFT_ARROW=37, RIGHT_ARROW=39, ESCAPE = 27, ENTER = 13, ALPHABETS_START = 47, SHIFT=16 , CONTROL = 17;
	var _shiftHolded=false, _controlHolded=false,_lastTarget=null,_forcedTrigger=false, _oldSelected, _isCreated = false;
	var _doc = document;
	var getElement = function(ele) {
		if (_cacheElement[ele] === undefined) {
			_cacheElement[ele] = _doc.getElementById(ele);
		}
		return _cacheElement[ele];
	}; 	
	var _getIndex = function(opt) {
		var childid = _getPostID("postChildID"); 
		return $("#"+childid + " li."+_styles_i.li).index(opt);
	};
	var _createByJson = function() {
		if (_settings.byJson.data) {
				var validData = ["description","image",  "title"];
				try {
					if (!element.id) {
						element.id = "dropdown"+msBeautify.counter;
					};
					_settings.byJson.data = eval(_settings.byJson.data);
					//change element
					var id = "msdropdown"+(msBeautify.counter++);
					var obj = {};
					obj.id = id;
					obj.name = _settings.byJson.name || element.id; //its name
					if (_settings.byJson.size>0) {
						obj.size = _settings.byJson.size;
					};
					obj.multiple = _settings.byJson.multiple;					
					var oSelect = _createElement("select", obj);
					for(var i=0;i<_settings.byJson.data.length;i++) {
						var current = _settings.byJson.data[i];
						var opt = new Option(current.text, current.value);
						for(var p in current) { 
							if (p.toLowerCase() != 'text') { 
								var key = ($.inArray(p.toLowerCase(), validData)!=-1) ? "data-" : "";
								opt.setAttribute(key+p, current[p]);
							};
						};
						oSelect.options[i] = opt;
					};
					getElement(element.id).appendChild(oSelect);
					oSelect.selectedIndex = _settings.byJson.selectedIndex;
					$(oSelect).css({width: _settings.byJson.width+'px'});
					//now change element for access other things
					element = oSelect;
				} catch(e) {
					throw "There is an error in json data.";
				};
		};			
	};
	var _construct = function() {		
		 //set properties
		 _createByJson();
		if (!element.id) {
			element.id = "msdrpdd"+(msBeautify.counter++);
		};						
		_element = element.id;
		_this._element = _element;
		_isDisabled = getElement(_element).disabled;
		_isList = (getElement(_element).size>1 || getElement(_element).multiple==true) ? true : false;
		var hasMainCSS = $("#"+_element).data("maincss");
		if(hasMainCSS){
			_styles.dd = hasMainCSS;
		};
		//trace("_isList "+_isList);
		if (_isList) {_isMultiple = getElement(_element).multiple;};			
		_mergeAllProp();
		_overrideMethods();
		//create layout
		_createLayout();
		//set ui prop
		_updateProp("uiData", _getDataAndUI());
		_updateProp("selectedOptions", $("#"+_element +" option:selected"));
	 };	
	 /********************************************************************************************/	
	var _getPostID = function (id) {
		return _element+_holderId[id];
	};
	var _getInternalStyle = function(ele) {		 
		 var s = (ele.style === undefined) ? "" : ele.style.cssText;
		 return s;
	};
	var _parseOption = function(opt) {
		var imagePath = '', title ='', description='', value=-1, text='', className='', imagecss = '';
		if (opt !== undefined) {
			var attrTitle = opt.title || "";
			//data-title
			if (attrTitle!="") {
				var reg = /^\{.*\}$/;
				var isJson = reg.test(attrTitle);
				if (isJson && _settings.jsonTitle) {
					var obj =  eval("["+attrTitle+"]");	
				};				 
				title = (isJson && _settings.jsonTitle) ? obj[0].title : title;
				description = (isJson && _settings.jsonTitle) ? obj[0].description : description;
				imagePath = (isJson && _settings.jsonTitle) ? obj[0].image : attrTitle;
				imagecss = (isJson && _settings.jsonTitle) ? obj[0].imagecss : imagecss;
			};

			text = opt.text || '';
			value = opt.value || '';
			className = opt.className || "";
			//ignore title attribute if playing with data tags			
			title = $(opt).prop("data-title") || $(opt).data("title") || (title || "");
			description = $(opt).prop("data-description") || $(opt).data("description") || (description || "");
			imagePath = $(opt).prop("data-image") || $(opt).data("image") || (imagePath || "");
			imagecss = $(opt).prop("data-imagecss") || $(opt).data("imagecss") || (imagecss || "");
			
		};
		var o = {image: imagePath, title: title, description: description, value: value, text: text, className: className, imagecss:imagecss};
		return o;
	};	 
	var _createElement = function(nm, attr, html) {
		var tag = _doc.createElement(nm);
		if (attr) {
		 for(var i in attr) {
			 switch(i) {
				 case "style":
					tag.style.cssText  = attr[i];
				 break;
				 default:
					tag[i]  = attr[i];
				 break;
			 };	
		 };
		};
		if (html) {
		 tag.innerHTML = html;
		};
		return tag;
	};
	 /********************************************************************************************/
	  /*********************** <layout> *************************************/
	var _hideOriginal = function() {
		var hidid = _getPostID("postElementHolder");
		if ($("#"+hidid).length==0) {			 
			var obj = {style: 'height: 0px;overflow: hidden;position: absolute;',className: _styles.ddOutOfVision};
			obj.id = hidid;
			var oDiv = _createElement("div", obj);	
			$("#"+_element).after(oDiv);
			$("#"+_element).appendTo($("#"+hidid));
		} else {
			$("#"+hidid).css({height: 0,overflow: 'hidden',position: 'absolute'});
		};
	};
	var _createWrapper = function () {
		var obj = {
			className: _styles.dd + " ddcommon borderRadius"
		};
		var styles = _getInternalStyle(getElement(_element));
		var w = $("#" + _element).outerWidth();
		obj.style = "width: " + w + "px;";
		if (styles.length > 0) {
			obj.style = obj.style + "" + styles;
		};
		obj.id = _getPostID("postID");
		var oDiv = _createElement("div", obj);
		return oDiv;
	};
	var _createTitle = function () {
		var selectedOption;
		if(getElement(_element).selectedIndex>=0) {
			selectedOption = getElement(_element).options[getElement(_element).selectedIndex];
		} else {
			selectedOption = {value:'', text:''};
		}
		var spriteClass = "", selectedClass = "";
		//check sprite
		var useSprite = $("#"+_element).data("usesprite");
		if(useSprite) { _settings.useSprite = useSprite; };
		if (_settings.useSprite != false) {
			spriteClass = " " + _settings.useSprite;
			selectedClass = " " + selectedOption.className;
		};
		var oTitle = _createElement("div", {className: _styles.ddTitle + spriteClass + " " + _styles_i.borderRadiusTp});
		//divider
		var oDivider = _createElement("span", {className: _styles.divider});
		//arrow
		var oArrow = _createElement("span", {className: _styles.arrow});
		//title Text
		var titleid = _getPostID("postTitleID");
		var oTitleText = _createElement("span", {className: _styles.ddTitleText + selectedClass, id: titleid});
	
		var parsed = _parseOption(selectedOption);
		var arrowPath = parsed.image;
		var sText = parsed.text || "";
		if (arrowPath != "" && _settings.showIcon) {
			var oIcon = _createElement("img");
			oIcon.src = arrowPath;
			if(parsed.imagecss!="") {
				oIcon.className = parsed.imagecss+" ";
			};
		};
		var oTitleText_in = _createElement("span", {className: _styles.label}, sText);
		oTitle.appendChild(oDivider);
		oTitle.appendChild(oArrow);
		if (oIcon) {
			oTitleText.appendChild(oIcon);
		};
		oTitleText.appendChild(oTitleText_in);
		oTitle.appendChild(oTitleText);
		var oDescription = _createElement("span", {className: _styles.description}, parsed.description);
		oTitleText.appendChild(oDescription);
		return oTitle;
	};
	var _createFilterBox = function () {
		var tid = _getPostID("postTitleTextID");
		var sText = _createElement("input", {id: tid, type: 'text', value: '', autocomplete: 'off', className: 'text shadow borderRadius', style: 'display: none'});
		return sText;
	};
	var _createChild = function (opt) {
		var obj = {};
		var styles = _getInternalStyle(opt);
		if (styles.length > 0) {obj.style = styles; };
		var css = (opt.disabled) ? _styles.disabled : _styles.enabled;
		css = (opt.selected) ? (css + " " + _styles.selected) : css;
		css = css + " " + _styles_i.li;
		obj.className = css;
		if (_settings.useSprite != false) {
			obj.className = css + " " + opt.className;
		};
		var li = _createElement("li", obj);
		var parsed = _parseOption(opt);
		if (parsed.title != "") {
			li.title = parsed.title;
		};
		var arrowPath = parsed.image;
		if (arrowPath != "" && _settings.showIcon) {
			var oIcon = _createElement("img");
			oIcon.src = arrowPath;
			if(parsed.imagecss!="") {
				oIcon.className = parsed.imagecss+" ";
			};
		};
		if (parsed.description != "") {
			var oDescription = _createElement("span", {
				className: _styles.description
			}, parsed.description);
		};
		var sText = opt.text || "";
		var oTitleText = _createElement("span", {
			className: _styles.label
		}, sText);
		if (oIcon) {
			li.appendChild(oIcon);
		};
		li.appendChild(oTitleText);
		if (oDescription) {
			li.appendChild(oDescription);
		} else {
			if (oIcon) {
				oIcon.className = oIcon.className+_styles_i.fnone;
			};
		};
		var oClear = _createElement("div", {className: 'clear'});
		li.appendChild(oClear);
		return li;
	};
	var _createChildren = function () {
		var childid = _getPostID("postChildID");
		var obj = {className: _styles.ddChild + " ddchild_ " + _styles_i.ddChildMore, id: childid};
		if (_isList == false) {
			obj.style = "z-index: " + _settings.zIndex;
		};
		var oDiv = _createElement("div", obj);
		var ul = _createElement("ul");
		if (_settings.useSprite != false) {
			ul.className = _settings.useSprite;
		};
		var allOptions = getElement(_element).children;
		for (var i = 0; i < allOptions.length; i++) {
			var current = allOptions[i];
			var li;
			if (current.nodeName.toLowerCase() == "optgroup") {
				//create ul
				li = _createElement("li", {className: _styles.optgroup});
				var span = _createElement("span", {className: _styles.optgroupTitle}, current.label);
				li.appendChild(span);
				var optChildren = current.children;
				var optul = _createElement("ul");
				for (var j = 0; j < optChildren.length; j++) {
					var opt_li = _createChild(optChildren[j]);
					optul.appendChild(opt_li);
				};
				li.appendChild(optul);
			} else {
				li = _createChild(current);
			};
			ul.appendChild(li);
		};
		oDiv.appendChild(ul);		
		return oDiv;
	};
	var _childHeight = function (val) {
		var childid = _getPostID("postChildID");
		if (val) {
			if (val == -1) { //auto
				$("#"+childid).css({height: "auto", overflow: "auto"});
			} else {				
				$("#"+childid).css("height", val+"px");
			};
			return false;
		};
		//else return height
		var iHeight;
		if (getElement(_element).options.length > _settings.visibleRows) {
			var margin = parseInt($("#" + childid + " li:first").css("padding-bottom")) + parseInt($("#" + childid + " li:first").css("padding-top"));
			if(_settings.rowHeight===0) {
				$("#" + childid).css({visibility:'hidden',display:'block'}); //hack for first child
				_settings.rowHeight = Math.round($("#" + childid + " li:first").height());
				$("#" + childid).css({visibility:'visible'});
				if(!_isList) {
					$("#" + childid).css({display:'none'});
				};
			};
			iHeight = ((_settings.rowHeight + margin) * _settings.visibleRows);
		} else if (_isList) {
			iHeight = $("#" + _element).height(); //get height from original element
		};		
		return iHeight;
	};
	var _applyChildEvents = function () {
		var childid = _getPostID("postChildID");
		$("#" + childid).on("click", function (e) {
			if (_isDisabled == true) return false;
			//prevent body click
			e.preventDefault();
			e.stopPropagation();
			if (_isList) {
				_bind_on_events();
			};
		});
		$("#" + childid + " li." + _styles.enabled).on("click", function (e) {
			_close(this);
		});
		$("#" + childid + " li." + _styles.enabled).on("mousedown", function (e) {
			if (_isDisabled == true) return false;
			_oldSelected = $("#" + childid + " li." + _styles.selected);
			_lastTarget = this;
			e.preventDefault();
			e.stopPropagation();
			if (_isList === true) {
				if (_isMultiple) {
					if (_shiftHolded === true) {
						$(this).addClass(_styles.selected);
						var selected = $("#" + childid + " li." + _styles.selected);
						var lastIndex = _getIndex(this);
						if (selected.length > 1) {
							var items = $("#" + childid + " li." + _styles_i.li);
							var ind1 = _getIndex(selected[0]);
							var ind2 = _getIndex(selected[1]);
							if (lastIndex > ind2) {
								ind1 = (lastIndex);
								ind2 = ind2 + 1;
							};
							for (var i = Math.min(ind1, ind2); i <= Math.max(ind1, ind2); i++) {
								var current = items[i];
								if ($(current).hasClass(_styles.enabled)) {
									$(current).addClass(_styles.selected);
								};
							};
						};
					} else if (_controlHolded === true) {
						$(this).toggleClass(_styles.selected);
					} else {
						$("#" + childid + " li." + _styles.selected).removeClass(_styles.selected);
						$(this).addClass(_styles.selected);
					};
				} else {
					$("#" + childid + " li." + _styles.selected).removeClass(_styles.selected);
					$(this).addClass(_styles.selected);
				};
				//fire event on mouseup
			} else {
				$("#" + childid + " li." + _styles.selected).removeClass(_styles.selected);
				$(this).addClass(_styles.selected);
			};
	
	
		});
		$("#" + childid + " li." + _styles.enabled).on("mouseenter", function (e) {
			if (_isDisabled == true) return false;
			e.preventDefault();
			e.stopPropagation();
			if (_lastTarget != null) {
				if (_isMultiple) {
					$(this).addClass(_styles.selected);
				};
			};
		});
	
		$("#" + childid + " li." + _styles.enabled).on("mouseover", function (e) {
			if (_isDisabled == true) return false;
			$(this).addClass(_styles.hover);
		});
		$("#" + childid + " li." + _styles.enabled).on("mouseout", function (e) {
			if (_isDisabled == true) return false;
			$("#" + childid + " li." + _styles.hover).removeClass(_styles.hover);
		});
	
		$("#" + childid + " li." + _styles.enabled).on("mouseup", function (e) {
			if (_isDisabled == true) return false;
			e.preventDefault();
			e.stopPropagation();
			var selected = $("#" + childid + " li." + _styles.selected).length;
			_forcedTrigger = (_oldSelected.length != selected || selected == 0) ? true : false;
			//trace(" _forcedTrigger "+_forcedTrigger)
			_fireAfterItemClicked();
			_unbind_on_events(); //remove old one			 
			_bind_on_events();
			_lastTarget = null;
		});
	
		/* options events */
		if (_settings.disabledOptionEvents == false) {
			$("#" + childid + " li." + _styles_i.li).on("click", function (e) {
				if (_isDisabled == true) return false;
				fireOptionEventIfExist(this, "click");
			});
			$("#" + childid + " li." + _styles_i.li).on("mouseenter", function (e) {
				if (_isDisabled == true) return false;
				fireOptionEventIfExist(this, "mouseenter");
			});
			$("#" + childid + " li." + _styles_i.li).on("mouseover", function (e) {
				if (_isDisabled == true) return false;
				fireOptionEventIfExist(this, "mouseover");
			});
			$("#" + childid + " li." + _styles_i.li).on("mouseout", function (e) {
				if (_isDisabled == true) return false;
				fireOptionEventIfExist(this, "mouseout");
			});
			$("#" + childid + " li." + _styles_i.li).on("mousedown", function (e) {
				if (_isDisabled == true) return false;
				fireOptionEventIfExist(this, "mousedown");
			});
			$("#" + childid + " li." + _styles_i.li).on("mouseup", function (e) {
				if (_isDisabled == true) return false;
				fireOptionEventIfExist(this, "mouseup");
			});
		};
	};
	var _removeChildEvents = function () {
		var childid = _getPostID("postChildID");
		$("#" + childid).off("click");
		$("#" + childid + " li." + _styles.enabled).off("mouseenter");
		$("#" + childid + " li." + _styles.enabled).off("click");
		$("#" + childid + " li." + _styles.enabled).off("mouseover");
		$("#" + childid + " li." + _styles.enabled).off("mouseout");
		$("#" + childid + " li." + _styles.enabled).off("mousedown");
		$("#" + childid + " li." + _styles.enabled).off("mouseup");
	};
	var _applyEvents = function () {
		var id = _getPostID("postID");
		var childid = _getPostID("postChildID");		
		$("#" + id).on(_settings.event, function (e) {			
			if (_isDisabled == true) return false;
			fireEventIfExist("click");
			//prevent body click
			e.preventDefault();
			e.stopPropagation();
			_open(e);
		});
		_applyChildEvents();		
		$("#" + id).on("dblclick", on_dblclick);
		$("#" + id).on("mousemove", on_mousemove);
		$("#" + id).on("mouseenter", on_mouseover);
		$("#" + id).on("mouseleave", on_mouseout);
		$("#" + id).on("mousedown", on_mousedown);
		$("#" + id).on("mouseup", on_mouseup);
	};
	//after create
	var _fixedForList = function () {
		var id = _getPostID("postID");
		var childid = _getPostID("postChildID");		
		if (_isList === true) {
			$("#" + id + " ." + _styles.ddTitle).hide();
			$("#" + childid).css({display: 'block', position: 'relative'});	
			//_open();
		} else {
			_isMultiple = false; //set multiple off if this is not a list
			$("#" + id + " ." + _styles.ddTitle).show();

			// $("#" + childid).css({display: 'none', position: 'absolute'});
            // remove absolute positioning
			$("#" + childid).css({display: 'none'});
			//set value
			var first = $("#" + childid + " li." + _styles.selected)[0];
			$("#" + childid + " li." + _styles.selected).removeClass(_styles.selected);
			var index = _getIndex($(first).addClass(_styles.selected));
			_setValue(index);
		};
		_childHeight(_childHeight()); //get and set height 
	};
	var _fixedForDisabled = function () {
		var id = _getPostID("postID");
		var opc = (_isDisabled == true) ? _settings.disabledOpacity : 1;
		if (_isDisabled === true) {
			$("#" + id).addClass(_styles.disabledAll);
		} else {
			$("#" + id).removeClass(_styles.disabledAll);
		};
	};
	var _fixedSomeUI = function () {
		//auto filter
		var tid = _getPostID("postTitleTextID");
		$("#" + tid).on("keyup", _applyFilters);
		//if is list
		_fixedForList();
		_fixedForDisabled();
	};
	var _createLayout = function () {		
		var oDiv = _createWrapper();
		var oTitle = _createTitle();
		oDiv.appendChild(oTitle);
		//auto filter box
		var oFilterBox = _createFilterBox();
		oDiv.appendChild(oFilterBox);
	
		var oChildren = _createChildren();
		oDiv.appendChild(oChildren);
		$("#" + _element).after(oDiv);
		_hideOriginal(); //hideOriginal
		_fixedSomeUI();
		_applyEvents();
		if (typeof _settings.on.create == "function") {
			_settings.on.create.apply(_this, arguments);
		};
	};
	var _selectMutipleOptions = function (bySelected) {
		var childid = _getPostID("postChildID");
		var selected = bySelected || $("#" + childid + " li." + _styles.selected);
		for (var i = 0; i < selected.length; i++) {
			var ind = _getIndex(selected[i]);
			getElement(_element).options[ind].selected = "selected";
		};
	};
	var _fireAfterItemClicked = function () {
		var childid = _getPostID("postChildID");
		var selected = $("#" + childid + " li." + _styles.selected);
		if (_isMultiple && (_shiftHolded || _controlHolded) || _forcedTrigger) {
			getElement(_element).selectedIndex = -1; //reset old
		};
		if (selected.length == 0) {
			index = -1;
		} else if (selected.length > 1) {
			//selected multiple
			_selectMutipleOptions(selected);
			var index = $("#" + childid + " li." + _styles.selected);
		} else {
			//if one selected
			var index = _getIndex($("#" + childid + " li." + _styles.selected));
		};
		if (getElement(_element).selectedIndex != index || _forcedTrigger) {
			_setValue(index);
			$("#" + _element).trigger("change");
		};
	};
	var _setValue = function (index, byvalue) {
		if (index !== undefined) {
			var selectedIndex, value, selectedText;
			if (index == -1) {
				selectedIndex = -1;
				value = "";
				selectedText = "";
				_updateTitleUI(-1);
			} else {
				if (typeof index != "object") {
					var opt = getElement(_element).options[index];
					getElement(_element).selectedIndex = index;
					selectedIndex = index;
					value = _parseOption(opt);
					selectedText = (index >= 0) ? getElement(_element).options[index].text : "";
					_updateTitleUI(undefined, value);
					value = value.value; //for bottom
				} else {
					//this is multiple
					selectedIndex = getElement(_element).selectedIndex;
					value = getElement(_element).value;
					selectedText = getElement(_element).options[getElement(_element).selectedIndex].text || "";
				};
			};
			_updateProp("selectedIndex", selectedIndex);
			_updateProp("value", value);
			_updateProp("selectedText", selectedText);
			_updateProp("children", getElement(_element).children);
			_updateProp("uiData", _getDataAndUI());
			_updateProp("selectedOptions", $("#" + _element + " option:selected"));
		};
	};
	var has_handler = function (name) {
		//True if a handler has been added in the html.
		var evt = {byElement: false, byJQuery: false, hasEvent: false};
		var obj = $("#" + _element);
		if (obj.prop("on" + name) != undefined) {
			evt.hasEvent = true;
			evt.byElement = true;
		};
		// True if a handler has been added using jQuery.
		var evs;
		if (typeof $._data == "function") { //1.8
			evs = $._data(obj[0], "events");
		} else {
			evs = obj.data("events");
		};
		if (evs && evs[name]) {
			evt.hasEvent = true;
			evt.byJQuery = true;
		};
		return evt;
	};
	var _bind_on_events = function () {
		_unbind_on_events();
		$("body").on("click", _close);
		//bind more events		 
		$(document).on("keydown", on_keydown);
		$(document).on("keyup", on_keyup);
		//focus will work on this	 		 
	};
	var _unbind_on_events = function () {
		$("body").off("click", _close);
		//bind more events
		$(document).off("keydown", on_keydown);
		$(document).off("keyup", on_keyup);
	};
	var _applyFilters = function () {
		var childid = _getPostID("postChildID");
		var tid = _getPostID("postTitleTextID");
		var sText = getElement(tid).value;
		if (sText.length == 0) {
			$("#" + childid + " li:hidden").show(); //show if hidden
			_childHeight(_childHeight());
		} else {
			$("#" + childid + " li").hide();
			$("#" + childid + " li:Contains('" + sText + "')").show();	
			if ($("#" + childid + " li:visible").length <= _settings.visibleRows) {
				_childHeight(-1); //set autoheight
			};
		};		
	};
	var _showFilterBox = function () {
		var tid = _getPostID("postTitleTextID");
		if ($("#" + tid + ":hidden").length > 0 && _controlHolded == false) {
			$("#" + tid + ":hidden").show().val("");
			getElement(tid).focus();
		};
	};
	var _hideFilterBox = function () {
		var tid = _getPostID("postTitleTextID");
		if ($("#" + tid + ":visible").length > 0) {
			$("#" + tid + ":visible").hide();
			getElement(tid).blur();
		};
	};
	var on_keydown = function (evt) {
		var tid = _getPostID("postTitleTextID");
		switch (evt.keyCode) {
			case DOWN_ARROW:
			case RIGHT_ARROW:
				evt.preventDefault();
				evt.stopPropagation();
				//_hideFilterBox();
				_next();				
				break;
			case UP_ARROW:
			case LEFT_ARROW:
				evt.preventDefault();
				evt.stopPropagation();
				//_hideFilterBox();
				_previous();
				break;
			case ESCAPE:
			case ENTER:
				evt.preventDefault();
				evt.stopPropagation();
				_close();				
				break;
			case SHIFT:
				_shiftHolded = true;
				break;
			case CONTROL:
				_controlHolded = true;
				break;
			default:
				if (evt.keyCode >= ALPHABETS_START && _isList === false) {
					_showFilterBox();
				};
				break;
		};
		if (_isDisabled == true) return false;
		fireEventIfExist("keydown");
	};
	var on_keyup = function (evt) {
		switch (evt.keyCode) {
			case SHIFT:
				_shiftHolded = false;
				break;
			case CONTROL:
				_controlHolded = false;
				break;
		};
		if (_isDisabled == true) return false;
		fireEventIfExist("keyup");
	};
	var on_dblclick = function (evt) {
		if (_isDisabled == true) return false;
		fireEventIfExist("dblclick");
	};
	var on_mousemove = function (evt) {
		if (_isDisabled == true) return false;
		fireEventIfExist("mousemove");
	};
	
	var on_mouseover = function (evt) {
		if (_isDisabled == true) return false;
		evt.preventDefault();
		fireEventIfExist("mouseover");
	};
	var on_mouseout = function (evt) {
		if (_isDisabled == true) return false;
		evt.preventDefault();
		fireEventIfExist("mouseout");
	};
	var on_mousedown = function (evt) {
		if (_isDisabled == true) return false;
		fireEventIfExist("mousedown");
	};
	var on_mouseup = function (evt) {
		if (_isDisabled == true) return false;
		fireEventIfExist("mouseup");
	};
	var option_has_handler = function (opt, name) {
		//True if a handler has been added in the html.
		var evt = {byElement: false, byJQuery: false, hasEvent: false};
		if ($(opt).prop("on" + name) != undefined) {
			evt.hasEvent = true;
			evt.byElement = true;
		};
		// True if a handler has been added using jQuery.
		var evs = $(opt).data("events");
		if (evs && evs[name]) {
			evt.hasEvent = true;
			evt.byJQuery = true;
		};
		return evt;
	};
	var fireOptionEventIfExist = function (li, evt_n) {
		if (_settings.disabledOptionEvents == false) {
			var opt = getElement(_element).options[_getIndex(li)];
			//check if original has some
			if (option_has_handler(opt, evt_n).hasEvent === true) {
				if (option_has_handler(opt, evt_n).byElement === true) {
					opt["on" + evt_n]();
				};
				if (option_has_handler(opt, evt_n).byJQuery === true) {
					switch (evt_n) {
						case "keydown":
						case "keyup":
							//key down/up will check later
							break;
						default:
							$(opt).trigger(evt_n);
							break;
					};
				};
				return false;
			};
		};
	};
	var fireEventIfExist = function (evt_n) {
		//local
		if (typeof _settings.on[evt_n] == "function") {
			_settings.on[evt_n].apply(this, arguments);
		};
		//check if original has some
		if (has_handler(evt_n).hasEvent === true) {
			if (has_handler(evt_n).byElement === true) {
				getElement(_element)["on" + evt_n]();
			};
			if (has_handler(evt_n).byJQuery === true) {
				switch (evt_n) {
					case "keydown":
					case "keyup":
						//key down/up will check later
						break;
					default:
						$("#" + _element).trigger(evt_n);
						break;
				};
			};
			return false;
		};
	};
	/******************************* navigation **********************************************/
	var _scrollToIfNeeded = function (opt) {
		var childid = _getPostID("postChildID");
		//if scroll is needed
		opt = (opt !== undefined) ? opt : $("#" + childid + " li." + _styles.selected);
		if (opt.length > 0) {
			var pos = parseInt(($(opt).position().top));
			var ch = parseInt($("#" + childid).height());
			if (pos > ch) {
				var top = pos + $("#" + childid).scrollTop() - (ch/2);
				$("#" + childid).animate({scrollTop:top}, 500);
			};
		};
	};
	var _next = function () {
		var childid = _getPostID("postChildID");
		var items = $("#" + childid + " li:visible." + _styles_i.li);
		var selected = $("#" + childid + " li:visible." + _styles.selected);
		selected = (selected.length==0) ? items[0] : selected;
		var index = $("#" + childid + " li:visible." + _styles_i.li).index(selected);
		if ((index < items.length - 1)) {
			index = getNext(index);
			if (index < items.length) { //check again - hack for last disabled 
				if (!_shiftHolded || !_isList || !_isMultiple) {
					$("#" + childid + " ." + _styles.selected).removeClass(_styles.selected);
				};
				$(items[index]).addClass(_styles.selected);
				_updateTitleUI(index);
				if (_isList == true) {
					_fireAfterItemClicked();
				};
				_scrollToIfNeeded($(items[index]));
			};
			if (!_isList) {
				_adjustOpen();
			};
		};	
		function getNext(ind) {
			ind = ind + 1;
			if (ind > items.length) {
				return ind;
			};
			if ($(items[ind]).hasClass(_styles.enabled) === true) {
				return ind;
			};
			return ind = getNext(ind);
		};
	};
	var _previous = function () {
		var childid = _getPostID("postChildID");
		var selected = $("#" + childid + " li:visible." + _styles.selected);
		var items = $("#" + childid + " li:visible." + _styles_i.li);
		var index = $("#" + childid + " li:visible." + _styles_i.li).index(selected[0]);
		if (index >= 0) {
			index = getPrev(index);
			if (index >= 0) { //check again - hack for disabled 
				if (!_shiftHolded || !_isList || !_isMultiple) {
					$("#" + childid + " ." + _styles.selected).removeClass(_styles.selected);
				};
				$(items[index]).addClass(_styles.selected);
				_updateTitleUI(index);
				if (_isList == true) {
					_fireAfterItemClicked();
				};
				if (parseInt(($(items[index]).position().top + $(items[index]).height())) <= 0) {
					var top = ($("#" + childid).scrollTop() - $("#" + childid).height()) - $(items[index]).height();
					$("#" + childid).animate({scrollTop: top}, 500);
				};
			};
			if (!_isList) {
				_adjustOpen();
			};
		};
	
		function getPrev(ind) {
			ind = ind - 1;
			if (ind < 0) {
				return ind;
			};
			if ($(items[ind]).hasClass(_styles.enabled) === true) {
				return ind;
			};
			return ind = getPrev(ind);
		};
	};
	var _adjustOpen = function () {
		var id = _getPostID("postID");
		var childid = _getPostID("postChildID");
		var pos = $("#" + id).offset();
		var mH = $("#" + id).height();
		var wH = $(window).height();
		var st = $(window).scrollTop();
		var cH = $("#" + childid).height();
		var top = $("#" + id).height(); //this close so its title height
		if ((wH + st) < Math.floor(cH + mH + pos.top) || _settings.openDirection.toLowerCase() == 'alwaysup') {
			top = cH;
			$("#" + childid).css({top: "-" + top + "px", display: 'block', zIndex: _settings.zIndex});
			$("#" + id).removeClass("borderRadius borderRadiusTp").addClass("borderRadiusBtm");
			var top = $("#" + childid).offset().top;
			if (top < -10) {
				$("#" + childid).css({top: (parseInt($("#" + childid).css("top")) - top + 20 + st) + "px", zIndex: _settings.zIndex});
				$("#" + id).removeClass("borderRadiusBtm borderRadiusTp").addClass("borderRadius");
			};
		} else {
			$("#" + childid).css({top: top + "px", zIndex: _settings.zIndex});
			$("#" + id).removeClass("borderRadius borderRadiusBtm").addClass("borderRadiusTp");
		};
	};
	var _open = function (e) {
		if (_isDisabled == true) return false;
		var id = _getPostID("postID");
		var childid = _getPostID("postChildID");
		if (!_isOpen) {
			_isOpen = true;
			if (msBeautify.oldDiv != '') {
				$("#" + msBeautify.oldDiv).css({display: "none"}); //hide all 
			};
			msBeautify.oldDiv = childid;
			$("#" + childid + " li:hidden").show(); //show if hidden
			_adjustOpen();
			var animStyle = _settings.animStyle;
			if(animStyle=="" || animStyle=="none") {
				$("#" + childid).css({display:"block"});
				_scrollToIfNeeded();
				if (typeof _settings.on.open == "function") {
					var d = _getDataAndUI();
					_settings.on.open(d.data, d.ui);
				};
			} else {				
				$("#" + childid)[animStyle]("fast", function () {
					_scrollToIfNeeded();
					if (typeof _settings.on.open == "function") {
						var d = _getDataAndUI();
						_settings.on.open(d.data, d.ui);
					};
				});
			};
			_bind_on_events();
		} else {
			if(_settings.event!=='mouseover') {
				_close();
			};
		};
	};
	var _close = function (e) {
		_isOpen = false;
		var id = _getPostID("postID");
		var childid = _getPostID("postChildID");
		if (_isList === false) {
			$("#" + childid).css({display: "none"});
			$("#" + id).removeClass("borderRadiusTp borderRadiusBtm").addClass("borderRadius");
			//do it onclick
			_fireAfterItemClicked();
		};
		_unbind_on_events();
		if (typeof _settings.on.close == "function") {
			var d = _getDataAndUI();
			_settings.on.close(d.data, d.ui);
		};
		//rest some old stuff
		_hideFilterBox();
		_childHeight(_childHeight()); //its needed after filter applied
		$("#" + childid).css({zIndex:1})		
	};
	/*********************** </layout> *************************************/
	var on_change = function () {
		if (_orginial.onchange != null) {
			_orginial.onchange.apply(this, arguments)
		};
		_this.selectedIndex = this.selectedIndex;
		_this.value = this.value;
		_this.selectedText = (this.selectedIndex >= 0) ? this.options[this.selectedIndex].text : "";
		if (typeof _settings.on.change == "function") {
			var d = _getDataAndUI();
			_settings.on.change(d.data, d.ui);
		};
	};
	var _overrideMethods = function () {
		//override old change	
		getElement(_element).onchange = on_change;
	};
	
	var _mergeAllProp = function () {
		_orginial = $.extend(true, {}, getElement(_element));
		for (var i in _orginial) {
			if (typeof _orginial[i] != "function") {
				_this[i] = _orginial[i]; //properties
			};
		};
		_this.selectedText = (_orginial.selectedIndex >= 0) ? _orginial.options[_orginial.selectedIndex].text : "";
		_this.version = msBeautify.version;
		_this.author = msBeautify.author;
	};
	var _getDataAndUIByOption = function (opt) {
		if (opt != null && typeof opt != "undefined") {
			var childid = _getPostID("postChildID");
			var data = _parseOption(opt);
			var ui = $("#" + childid + " li." + _styles_i.li + ":eq(" + (opt.index) + ")");
			return {data: data, ui: ui, option: opt, index: opt.index};
		};
		return null;
	};
	var _getDataAndUI = function () {
		var childid = _getPostID("postChildID");
		var ele = getElement(_element);
		var data, ui, option, index;
		if (ele.selectedIndex == -1) {
			data = null;
			ui = null;
			option = null;
			index = -1;
		} else {
			ui = $("#" + childid + " li." + _styles.selected);
			if (ui.length > 1) {
				var d = [], op = [], ind = [];
				for (var i = 0; i < ui.length; i++) {
					var pd = _getIndex(ui[i]);
					d.push(pd);
					op.push(ele.options[pd]);
				};
				data = d;
				option = op;
				index = d;
			} else {
				option = ele.options[ele.selectedIndex];
				data = _parseOption(option);
				index = ele.selectedIndex;
			};
		};
		return {data: data, ui: ui, index: index, option: option};
	};
	var _updateTitleUI = function (index, byvalue) {
		var titleid = _getPostID("postTitleID");
		var value = {};
		if (index == -1) {
			value.text = "&nbsp;";
			value.className = "";
			value.description = "";
			value.image = "";
		} else if (typeof index != "undefined") {
			var opt = getElement(_element).options[index];
			value = _parseOption(opt);
		} else {
			value = byvalue;
		};
		//update title and current
		$("#" + titleid).find("." + _styles.label).html(value.text);
		getElement(titleid).className = _styles.ddTitleText + " " + value.className;
		//update desction		 
		if (value.description != "") {
			$("#" + titleid).find("." + _styles.description).html(value.description).show();
		} else {
			$("#" + titleid).find("." + _styles.description).html("").hide();
		};
		//update icon
		var img = $("#" + titleid).find("img");
		if (img.length > 0) {
			$(img).remove();
		};
		if (value.image != "" && _settings.showIcon) {
			img = _createElement("img", {src: value.image});
			$("#" + titleid).prepend(img);
			if(value.imagecss!="") {
				img.className = value.imagecss+" ";
			};
			if (value.description == "") {
				img.className = img.className+_styles_i.fnone;
			};
		};
	};
	var _updateProp = function (p, v) {
		_this[p] = v;
	};
	var _updateUI = function (a, opt, i) { //action, index, opt
		var childid = _getPostID("postChildID");
		var wasSelected = false;
		switch (a) {
			case "add":
				var li = _createChild(opt || getElement(_element).options[i]);				
				var index;
				if (arguments.length == 3) {
					index = i;
				} else {
					index = $("#" + childid + " li." + _styles_i.li).length - 1;
				};				
				if (index < 0 || !index) {
					$("#" + childid + " ul").append(li);
				} else {
					var at = $("#" + childid + " li." + _styles_i.li)[index];
					$(at).before(li);
				};
				_removeChildEvents();
				_applyChildEvents();
				if (_settings.on.add != null) {
					_settings.on.add.apply(this, arguments);
				};
				break;
			case "remove":
				wasSelected = $($("#" + childid + " li." + _styles_i.li)[i]).hasClass(_styles.selected);
				$("#" + childid + " li." + _styles_i.li + ":eq(" + i + ")").remove();
				var items = $("#" + childid + " li." + _styles.enabled);
				if (wasSelected == true) {
					if (items.length > 0) {
						$(items[0]).addClass(_styles.selected);
						var ind = $("#" + childid + " li." + _styles_i.li).index(items[0]);
						_setValue(ind);
					};
				};
				if (items.length == 0) {
					_setValue(-1);
				};
				if ($("#" + childid + " li." + _styles_i.li).length < _settings.visibleRows && !_isList) {
					_childHeight(-1); //set autoheight
				};
				if (_settings.on.remove != null) {
					_settings.on.remove.apply(this, arguments);
				};
				break;
		};	
	};
	/************************** public methods/events **********************/
	this.act = function () {
		var action = arguments[0];
		Array.prototype.shift.call(arguments);
		switch (action) {
			case "add":
				_this.add.apply(this, arguments);
				break;
			case "remove":
				_this.remove.apply(this, arguments);
				break;
			default:
				try {
					getElement(_element)[action].apply(getElement(_element), arguments);
				} catch (e) {
					//there is some error.
				};
				break;
		};
	};
	
	this.add = function () {
		var text, value, title, image, description;
		var obj = arguments[0];
		if (obj instanceof HTMLOptionElement) {
			opt = obj; // i need to check if this works in ie6
		} else if (typeof obj == "string") {
			text = obj;
			value = text;
			opt = new Option(text, value);
		} else {
			text = obj.text || '';
			value = obj.value || text;
			title = obj.title || '';
			image = obj.image || '';
			description = obj.description || '';
			//image:imagePath, title:title, description:description, value:opt.value, text:opt.text, className:opt.className||""
			opt = new Option(text, value);
			$(opt).data("description", description);
			$(opt).data("image", image);
			$(opt).data("title", title);
		};
		arguments[0] = opt; //this option
		getElement(_element).add.apply(getElement(_element), arguments);
		_updateProp("children", getElement(_element)["children"]);
		_updateProp("length", getElement(_element).length);
		_updateUI("add", opt, arguments[1]);
	};
	this.remove = function (i) {
		getElement(_element).remove(i);
		_updateProp("children", getElement(_element)["children"]);
		_updateProp("length", getElement(_element).length);
		_updateUI("remove", undefined, i);
	};
	this.set = function (prop, val) {
		if (typeof prop == "undefined" || typeof val == "undefined") return false;
		prop = prop.toString();
		try {
			_updateProp(prop, val);
		} catch (e) {/*this is ready only */};
		
		switch (prop) {
			case "size":
				getElement(_element)[prop] = val;
				if (val == 0) {
					getElement(_element).multiple = false;
				};
				_isList = (getElement(_element).size > 1 || getElement(_element).multiple == true) ? true : false;
				_fixedForList();
				break;
			case "multiple":
				_isList = (getElement(_element).size > 1 || getElement(_element).multiple == true) ? true : false;
				_isMultiple = getElement(_element).multiple;
				_fixedForList();
				_updateProp(prop, val);
				break;
			case "disabled":
				getElement(_element)[prop] = val;
				_isDisabled = val;
				_fixedForDisabled();
				break;
			case "selectedIndex":
			case "value":
				getElement(_element)[prop] = val;
				var childid = _getPostID("postChildID");
				$("#" + childid + " li." + _styles_i.li).removeClass(_styles.selected);
				$($("#" + childid + " li." + _styles_i.li)[getElement(_element).selectedIndex]).addClass(_styles.selected);
				_setValue(getElement(_element).selectedIndex);
				break;
			case "length":
				var childid = _getPostID("postChildID");
				if (val < getElement(_element).length) {
					getElement(_element)[prop] = val;
					if (val == 0) {
						$("#" + childid + " li." + _styles_i.li).remove();
						_setValue(-1);
					} else {
						$("#" + childid + " li." + _styles_i.li + ":gt(" + (val - 1) + ")").remove();
						if ($("#" + childid + " li." + _styles.selected).length == 0) {
							$("#" + childid + " li." + _styles.enabled + ":eq(0)").addClass(_styles.selected);
						};
					};
					_updateProp(prop, val);
					_updateProp("children", getElement(_element)["children"]);
				};
				break;
			case "id":
				//please i need this. so preventing to change it. will work on this later
				break;
			default:
				//check if this is not a readonly properties
				try {
					getElement(_element)[prop] = val;
					_updateProp(prop, val);
				} catch (e) {
					//silent
				};
				break;
		}
	};
	this.get = function (prop) {
		return _this[prop] || getElement(_element)[prop]; //return if local else from original
	};
	this.visible = function (val) {
		var id = _getPostID("postID");
		if (val == true) {
			$("#" + id).show();
		} else if (val == false) {
			$("#" + id).hide();
		} else {
			return $("#" + id).css("display");
		};
	};
	this.debug = function (v) {
		msBeautify.debug(v);
	};
	this.close = function () {
		_close();
	};
	this.open = function () {
		_open();
	};
	this.showRows = function (r) {
		if (typeof r == "undefined" || r == 0) {
			return false;
		};
		_settings.visibleRows = r;
		_childHeight(_childHeight());
	};
	this.visibleRows = this.showRows;
	this.on = function (type, fn) {
		$("#" + _element).on(type, fn);
	};
	this.off = function (type, fn) {
		$("#" + _element).off(type, fn);
	};
	this.addMyEvent = this.on;
	this.getData = function () {
		return _getDataAndUI()
	};
	this.namedItem = function () {
		var opt = getElement(_element).namedItem.apply(getElement(_element), arguments);
		return _getDataAndUIByOption(opt);
	};
	this.item = function () {
		var opt = getElement(_element).item.apply(getElement(_element), arguments);
		return _getDataAndUIByOption(opt);
	};	
	this.destory = function () {
		var hidid = _getPostID("postElementHolder");
		var id = _getPostID("postID");
		$("#" + id + ", #" + id + " *").off();
		$("#" + id).remove();
		$("#" + _element).parent().replaceWith($("#" + _element));
		getElement(_element).onchange = function () { //restore
			if (_orginial.onchange != null) {
				_orginial.onchange.apply(this, arguments)
			};
		};
		$("#" + _element).data("dd", null);
	};
	//Create msDropDown		
	_construct();
};
//bind in jquery
$.fn.extend({
			msDropDown: function(settings)
			{
				return this.each(function()
				{
					if (!$(this).data('dd')){
						var mydropdown = new dd(this, settings);
						$(this).data('dd', mydropdown);
					};
				});
			}
});
$.fn.msDropdown = $.fn.msDropDown; //make a copy
})(jQuery);