;(function($) {

/*

    * ui.dropdownchecklist

    *

    * Copyright (c) 2008-2010 Adrian Tosca, Copyright (c) 2010-2011 Ittrium LLC

    * Dual licensed under the MIT (MIT-LICENSE.txt) OR GPL (GPL-LICENSE.txt) licenses.

    *

*/

    // The dropdown check list jQuery plugin transforms a regular select html element into a dropdown check list.

    $.widget("ui.dropdownchecklist", {

    	// Some globlals

    	// $.ui.dropdownchecklist.gLastOpened - keeps track of last opened dropdowncheck list so we can close it

    	// $.ui.dropdownchecklist.gIDCounter - simple counter to provide a unique ID as needed

        version: function() {

            alert('DropDownCheckList v1.4');

        },    	

        // Creates the drop container that keeps the items and appends it to the document

        _appendDropContainer: function( controlItem ) {

            var wrapper = $("<div/>");

            // the container is wrapped in a div

            wrapper.addClass("ui-dropdownchecklist ui-dropdownchecklist-dropcontainer-wrapper");

            wrapper.addClass("ui-widget");

            // assign an id

            wrapper.attr("id",controlItem.attr("id") + '-ddw');

            // initially positioned way off screen to prevent it from displaying

            // NOTE absolute position to enable width/height calculation

            wrapper.css({ position: 'absolute', left: "-33000px", top: "-33000px"  });

            

            var container = $("<div/>"); // the actual container

            container.addClass("ui-dropdownchecklist-dropcontainer ui-widget-content");

            container.css("overflow-y", "auto");

            wrapper.append(container);

            

            // insert the dropdown after the master control to try to keep the tab order intact

            // if you just add it to the end, tabbing out of the drop down takes focus off the page

            // @todo 22Sept2010 - check if size calculation is thrown off if the parent of the

            //		selector is hidden.  We may need to add it to the end of the document here, 

            //		calculate the size, and then move it back into proper position???

			//$(document.body).append(wrapper);

            wrapper.insertAfter(controlItem);



            // flag that tells if the drop container is shown or not

            wrapper.isOpen = false;

            return wrapper;

        },

        // Look for browser standard 'open' on a closed selector

		_isDropDownKeyShortcut: function(e,keycode) {

			return e.altKey && ($.ui.keyCode.DOWN == keycode);// Alt + Down Arrow

		},

		// Look for key that will tell us to close the open dropdown

		_isDropDownCloseKey: function(e,keycode) {

			return ($.ui.keyCode.ESCAPE == keycode) || ($.ui.keyCode.ENTER == keycode);

		},

		// Handler to change the active focus based on a keystroke, moving some count of

		// items from the element that has the current focus

		_keyFocusChange: function(target,delta,limitToItems) {

			// Find item with current focus

			var focusables = $(":focusable");

			var index = focusables.index(target);

			if ( index >= 0 ) {

				index += delta;

				if ( limitToItems ) {

					// Bound change to list of input elements

	            	var allCheckboxes = this.dropWrapper.find("input:not([disabled])");

	            	var firstIndex = focusables.index(allCheckboxes.get(0));

	            	var lastIndex = focusables.index(allCheckboxes.get(allCheckboxes.length-1));

	            	if ( index < firstIndex ) {

	            		index = lastIndex;

	            	} else if ( index > lastIndex ) {

	            		index = firstIndex;

	            	}

	            }

				focusables.get(index).focus();

			}

		},

		// Look for navigation, open, close (wired to keyup)

		_handleKeyboard: function(e) {

			var self = this;

			var keyCode = (e.keyCode || e.which);

			if (!self.dropWrapper.isOpen && self._isDropDownKeyShortcut(e, keyCode)) {

				// Key command to open the dropdown

				e.stopImmediatePropagation();

				self._toggleDropContainer(true);

			} else if (self.dropWrapper.isOpen && self._isDropDownCloseKey(e, keyCode)) {

				// Key command to close the dropdown (but we retain focus in the control)

				e.stopImmediatePropagation();

				self._toggleDropContainer(false);

				self.controlSelector.focus();

			} else if (self.dropWrapper.isOpen 

					&& (e.target.type == 'checkbox')

					&& ((keyCode == $.ui.keyCode.DOWN) || (keyCode == $.ui.keyCode.UP)) ) {

				// Up/Down to cycle throught the open items

				e.stopImmediatePropagation();

				self._keyFocusChange(e.target, (keyCode == $.ui.keyCode.DOWN) ? 1 : -1, true);

			} else if (self.dropWrapper.isOpen && (keyCode == $.ui.keyCode.TAB) ) {

				// I wanted to adjust normal 'tab' processing here, but research indicates

				// that TAB key processing is NOT a cancelable event. You have to use a timer

				// hack to pull the focus back to where you want it after browser tab

				// processing completes.  Not going to work for us.

				//e.stopImmediatePropagation();

				//self._keyFocusChange(e.target, (e.shiftKey) ? -1 : 1, true);

           }

		},

		// Look for change of focus

		_handleFocus: function(e,focusIn,forDropdown) {

			var self = this;

			if (forDropdown && !self.dropWrapper.isOpen) {

				// if the focus changes when the control is NOT open, mark it to show where the focus is/is not

				e.stopImmediatePropagation();

				if (focusIn) {

					self.controlSelector.addClass("ui-state-hover");

					if ($.ui.dropdownchecklist.gLastOpened != null) {

						$.ui.dropdownchecklist.gLastOpened._toggleDropContainer( false );

					}

				} else {

					self.controlSelector.removeClass("ui-state-hover");

				}

           	} else if (!forDropdown && !focusIn) {

           		// The dropdown is open, and an item (NOT the dropdown) has just lost the focus.

           		// we really need a reliable method to see who has the focus as we process the blur,

           		// but that mechanism does not seem to exist.  Instead we rely on a delay before

           		// posting the blur, with a focus event cancelling it before the delay expires.

				if ( e != null ) { e.stopImmediatePropagation(); }

				self.controlSelector.removeClass("ui-state-hover");

				self._toggleDropContainer( false );	        	

           	}

		},

		// Clear the pending change of focus, which keeps us 'in' the control

		_cancelBlur: function(e) {

			var self = this;

			if (self.blurringItem != null) {

				clearTimeout(self.blurringItem);

				self.blurringItem = null;

			} 

		},

        // Creates the control that will replace the source select and appends it to the document

        // The control resembles a regular select with single selection

        _appendControl: function() {

            var self = this, sourceSelect = this.sourceSelect, options = this.options;



            // the control is wrapped in a basic container

            // inline-block at this level seems to give us better size control

            var wrapper = $("<span/>");

            wrapper.addClass("ui-dropdownchecklist ui-dropdownchecklist-selector-wrapper ui-widget");

            wrapper.css( { display: "inline-block", cursor: "default", overflow: "hidden" } );

            

            // assign an ID 

            var baseID = sourceSelect.attr("id");

            if ((baseID == null) || (baseID == "")) {

            	baseID = "ddcl-" + $.ui.dropdownchecklist.gIDCounter++;

            } else {

            	baseID = "ddcl-" + baseID;

			}

			wrapper.attr("id",baseID);

			

            // the actual control which you can style

            // inline-block needed to enable 'width' but has interesting problems cross browser

            var control = $("<span/>");

            control.addClass("ui-dropdownchecklist-selector ui-state-default");

            control.css( { display: "inline-block", overflow: "hidden", 'white-space': 'nowrap'} );

            // Setting a tab index means we are interested in the tab sequence

            var tabIndex = sourceSelect.attr("tabIndex");

            if ( tabIndex == null ) {

            	tabIndex = 0;

            } else {

            	tabIndex = parseInt(tabIndex);

            	if ( tabIndex < 0 ) {

            		tabIndex = 0;

            	}

            }

			control.attr("tabIndex", tabIndex);

			control.keyup(function(e) {self._handleKeyboard(e);});

			control.focus(function(e) {self._handleFocus(e,true,true);});

			control.blur(function(e) {self._handleFocus(e,false,true);});

            wrapper.append(control);



			// the optional icon (which is inherently a block) which we can float

			if (options.icon != null) {

				var iconPlacement = (options.icon.placement == null) ? "left" : options.icon.placement;

	            var anIcon = $("<div/>");

	            anIcon.addClass("ui-icon");

	            anIcon.addClass( (options.icon.toOpen != null) ? options.icon.toOpen : "ui-icon-triangle-1-e");

	            anIcon.css({ 'float': iconPlacement });

	            control.append(anIcon);

			}

            // the text container keeps the control text that is built from the selected (checked) items

            // inline-block needed to prevent long text from wrapping to next line when icon is active

            var textContainer = $("<span/>");

            textContainer.addClass("ui-dropdownchecklist-text");

            textContainer.css( {  display: "inline-block", 'white-space': "nowrap", overflow: "hidden" } );

            control.append(textContainer);



            // add the hover styles to the control

            wrapper.hover(

	            function() {

	                if (!self.disabled) {

	                    control.addClass("ui-state-hover");

	                }

	            }

	        , 	function() {

	                if (!self.disabled) {

	                    control.removeClass("ui-state-hover");

	                }

	            }

	        );

            // clicking on the control toggles the drop container

            wrapper.click(function(event) {

                if (!self.disabled) {

                    event.stopImmediatePropagation();

                    self._toggleDropContainer( !self.dropWrapper.isOpen );

                }

            });

            wrapper.insertAfter(sourceSelect);



			// Watch for a window resize and adjust the control if open

            $(window).resize(function() {

                if (!self.disabled && self.dropWrapper.isOpen) {

                	// Reopen yourself to get the position right

                    self._toggleDropContainer(true);

                }

            });       

            return wrapper;

        },

        // Creates a drop item that coresponds to an option element in the source select

        _createDropItem: function(index, tabIndex, value, text, optCss, checked, disabled, indent) {

            var self = this, options = this.options, sourceSelect = this.sourceSelect, controlWrapper = this.controlWrapper;

            // the item contains a div that contains a checkbox input and a lable for the text

            // the div

            var item = $("<div/>");

            item.addClass("ui-dropdownchecklist-item");

            item.css({'white-space': "nowrap"});

            var checkedString = checked ? ' checked="checked"' : '';

			var classString = disabled ? ' class="inactive"' : ' class="active"';

			

			// generated id must be a bit unique to keep from colliding

			var idBase = controlWrapper.attr("id");

			var id = idBase + '-i' + index;

            var checkBox;

            

            // all items start out disabled to keep them out of the tab order

            if (self.isMultiple) { // the checkbox

                checkBox = $('<input disabled type="checkbox" id="' + id + '"' + checkedString + classString + ' tabindex="' + tabIndex + '" />');

            } else { // the radiobutton

                checkBox = $('<input disabled type="radio" id="' + id + '" name="' + idBase + '"' + checkedString + classString + ' tabindex="' + tabIndex + '" />');

            }

            checkBox = checkBox.attr("index", index).val(value);

            item.append(checkBox);

            

            // the text

            var label = $("<label for=" + id + "/>");

            label.addClass("ui-dropdownchecklist-text");

            if ( optCss != null ) label.attr('style',optCss);

            label.css({ cursor: "default" });

            label.html(text);

			if (indent) {

				item.addClass("ui-dropdownchecklist-indent");

			}

			item.addClass("ui-state-default");

			if (disabled) {

				item.addClass("ui-state-disabled");

			}

	        label.click(function(e) {e.stopImmediatePropagation();});

            item.append(label);

            

           	// active items display themselves with hover

            item.hover(

            	function(e) {

            		var anItem = $(this);

                	if (!anItem.hasClass("ui-state-disabled")) { anItem.addClass("ui-state-hover"); }

            	}

            , 	function(e) {

            		var anItem = $(this);

                	anItem.removeClass("ui-state-hover");

            	}

            );

            // clicking on the checkbox synchronizes the source select

	        checkBox.click(function(e) {

	        	var aCheckBox = $(this);

				e.stopImmediatePropagation();

				if (aCheckBox.hasClass("active") ) {

					// Active checkboxes take active action

	                var callback = self.options.onItemClick;

	                if ($.isFunction(callback)) try {

                        callback.call(self,aCheckBox,sourceSelect.get(0));

                    } catch (ex) {

                        // reject the change on any error

                        aCheckBox.prop("checked",!aCheckBox.prop("checked"));

	                	self._syncSelected(aCheckBox);

                        return;

                    } 

	                self._syncSelected(aCheckBox);

	                self.sourceSelect.trigger("change", 'ddcl_internal');

	                if (!self.isMultiple && options.closeRadioOnClick) {

	                	self._toggleDropContainer(false);

	                }

				}

	        });

	        // we are interested in the focus leaving the check box

	        // but we need to detect the focus leaving one check box but

	        // entering another. There is no reliable way to detect who

	        // received the focus on a blur, so post the blur in the future,

	        // knowing we will cancel it if we capture the focus in a timely manner

	        // 23Sept2010 - unfortunately, IE 7+ and Chrome like to post a blur

	        // 				event to the current item with focus when the user

	        //				clicks in the scroll bar. So if you have a scrollable

	        //				dropdown with focus on an item, clicking in the scroll

	        //				will close the drop down.

	        //				I have no solution for blur processing at this time.

/*********

			var timerFunction = function(){ 

				// I had a hell of a time getting setTimeout to fire this, do not try to

				// define it within the blur function

				try { self._handleFocus(null,false,false); } catch(ex){ alert('timer failed: '+ex);}

			};

			checkBox.blur(function(e) { 

				self.blurringItem = setTimeout( timerFunction, 200 ); 

			});

			checkBox.focus(function(e) {self._cancelBlur();});

**********/	

	        // check/uncheck the item on clicks on the entire item div

	        item.click(function(e) {

	        	var anItem = $(this);

                e.stopImmediatePropagation();

				if (!anItem.hasClass("ui-state-disabled") ) {

					// check/uncheck the underlying control

					var aCheckBox = anItem.find("input");

	                var checked = aCheckBox.prop("checked");

	                aCheckBox.prop("checked", !checked);

	                

	                var callback = self.options.onItemClick;

	                if ($.isFunction(callback)) try {

                        callback.call(self,aCheckBox,sourceSelect.get(0));

                    } catch (ex) {

                        // reject the change on any error

                        aCheckBox.prop("checked",checked);

	                	self._syncSelected(aCheckBox);

                        return;

                    } 

	                self._syncSelected(aCheckBox);

	                self.sourceSelect.trigger("change", 'ddcl_internal');

	                if (!checked && !self.isMultiple && options.closeRadioOnClick) {

	                	self._toggleDropContainer(false);

	                }

				} else {

					// retain the focus even if disabled

					anItem.focus();

					self._cancelBlur();

				}

	        });

	        // do not let the focus wander around

			item.focus(function(e) { 

	        	var anItem = $(this);

                e.stopImmediatePropagation();

            });

			item.keyup(function(e) {self._handleKeyboard(e);});

            return item;

        },

		_createGroupItem: function(text,disabled) {

			var self = this;

			var group = $("<div />");

			group.addClass("ui-dropdownchecklist-group ui-widget-header");

			if (disabled) {

				group.addClass("ui-state-disabled");

			}

			group.css({'white-space': "nowrap"});

			

            var label = $("<span/>");

            label.addClass("ui-dropdownchecklist-text");

            label.css( { cursor: "default" });

            label.text(text);

			group.append(label);

			

			// anything interesting when you click the group???

	        group.click(function(e) {

	        	var aGroup= $(this);

                e.stopImmediatePropagation();

                // retain the focus even if no action is taken

                aGroup.focus();

                self._cancelBlur();

            });

	        // do not let the focus wander around

			group.focus(function(e) { 

	        	var aGroup = $(this);

                e.stopImmediatePropagation();

            });

			return group;

		},

		_createCloseItem: function(text) {

			var self = this;

			var closeItem = $("<div />");

			closeItem.addClass("ui-state-default ui-dropdownchecklist-close ui-dropdownchecklist-item");

			closeItem.css({'white-space': 'nowrap', 'text-align': 'right'});

			

            var label = $("<span/>");

            label.addClass("ui-dropdownchecklist-text");

            label.css( { cursor: "default" });

            label.html(text);

			closeItem.append(label);

			

			// close the control on click

	        closeItem.click(function(e) {

	        	var aGroup= $(this);

                e.stopImmediatePropagation();

                // retain the focus even if no action is taken

                aGroup.focus();

                self._toggleDropContainer( false );

            });

            closeItem.hover(

            	function(e) { $(this).addClass("ui-state-hover"); }

            , 	function(e) { $(this).removeClass("ui-state-hover"); }

            );

	        // do not let the focus wander around

			closeItem.focus(function(e) { 

	        	var aGroup = $(this);

                e.stopImmediatePropagation();

            });

			return closeItem;

		},

        // Creates the drop items and appends them to the drop container

        // Also calculates the size needed by the drop container and returns it

        _appendItems: function() {

            var self = this, config = this.options, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper;

            var dropContainerDiv = dropWrapper.find(".ui-dropdownchecklist-dropcontainer");

			sourceSelect.children().each(function(index) { // when the select has groups

				var opt = $(this);

                if (opt.is("option")) {

                    self._appendOption(opt, dropContainerDiv, index, false, false);

                } else if (opt.is("optgroup")) {

					var disabled = opt.prop("disabled");

                    var text = opt.attr("label");

                    if (text != "") {

	                    var group = self._createGroupItem(text,disabled);

	                    dropContainerDiv.append(group);

	                }

                    self._appendOptions(opt, dropContainerDiv, index, true, disabled);

                }

			});

			if ( config.explicitClose != null ) {

				var closeItem = self._createCloseItem(config.explicitClose);

				dropContainerDiv.append(closeItem);

			}

            var divWidth = dropContainerDiv.outerWidth();

            var divHeight = dropContainerDiv.outerHeight();

            return { width: divWidth, height: divHeight };

        },

		_appendOptions: function(parent, container, parentIndex, indent, forceDisabled) {

			var self = this;

			parent.children("option").each(function(index) {

                var option = $(this);

                var childIndex = (parentIndex + "." + index);

                self._appendOption(option, container, childIndex, indent, forceDisabled);

            });

		},

        _appendOption: function(option, container, index, indent, forceDisabled) {

            var self = this;

            // Note that the browsers destroy any html structure within the OPTION

            var text = option.html();

            if ( (text != null) && (text != '') ) {

            	var value = option.val();

            	var optCss = option.attr('style');

            	var selected = option.prop("selected");

				var disabled = (forceDisabled || option.prop("disabled"));

				// Use the same tab index as the selector replacement

				var tabIndex = self.controlSelector.attr("tabindex");

            	var item = self._createDropItem(index, tabIndex, value, text, optCss, selected, disabled, indent);

            	container.append(item);

            }

        },

        // Synchronizes the items checked and the source select

        // When firstItemChecksAll option is active also synchronizes the checked items

        // senderCheckbox parameters is the checkbox input that generated the synchronization

        _syncSelected: function(senderCheckbox) {

            var self = this, options = this.options, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper;

            var selectOptions = sourceSelect.get(0).options;

            var allCheckboxes = dropWrapper.find("input.active");

            if (options.firstItemChecksAll == 'exclusive') {

            	if ((senderCheckbox == null) && $(selectOptions[0]).prop("selected") ) {

            		// Initialization call with first item active

                    allCheckboxes.prop("checked", false);

                    $(allCheckboxes[0]).prop("checked", true);

                } else if ((senderCheckbox != null) && (senderCheckbox.attr("index") == 0)) {

                	// Action on the first, so all other checkboxes NOT active

                	var firstIsActive = senderCheckbox.prop("checked");

                    allCheckboxes.prop("checked", false);

                    $(allCheckboxes[0]).prop("checked", firstIsActive);

                } else  {

                    // check the first checkbox if all the other checkboxes are checked

                    var allChecked = true;

                    var firstCheckbox = null;

                    allCheckboxes.each(function(index) {

                        if (index > 0) {

                            var checked = $(this).prop("checked");

                            if (!checked) { allChecked = false; }

                        } else {

                        	firstCheckbox = $(this);

                        }

                    });

                    if ( firstCheckbox != null ) {

                    	if ( allChecked ) {

                    		// when all are checked, only the first left checked

                    		allCheckboxes.prop("checked", false);

                    	}

                    	firstCheckbox.prop("checked", allChecked );

                    }

                }

            } else if (options.firstItemChecksAll) {

            	if ((senderCheckbox == null) && $(selectOptions[0]).prop("selected") ) {

            		// Initialization call with first item active so force all to be active

                    allCheckboxes.prop("checked", true);

                } else if ((senderCheckbox != null) && (senderCheckbox.attr("index") == 0)) {

                	// Check all checkboxes if the first one is checked

                    allCheckboxes.prop("checked", senderCheckbox.prop("checked"));

                } else  {

                    // check the first checkbox if all the other checkboxes are checked

                    var allChecked = true;

                    var firstCheckbox = null;

                    allCheckboxes.each(function(index) {

                        if (index > 0) {

                            var checked = $(this).prop("checked");

                            if (!checked) { allChecked = false; }

                        } else {

                        	firstCheckbox = $(this);

                        }

                    });

                    if ( firstCheckbox != null ) {

                    	firstCheckbox.prop("checked", allChecked );

                    }

                }

            }

            // do the actual synch with the source select

            var empties = 0;

            allCheckboxes = dropWrapper.find("input");

            allCheckboxes.each(function(index) {

            	var anOption = $(selectOptions[index + empties]);

            	var optionText = anOption.html();

            	if ( (optionText == null) || (optionText == '') ) {

                    empties += 1;

                    anOption = $(selectOptions[index + empties]);

            	}

                anOption.prop("selected", $(this).prop("checked"));

            });

            // update the text shown in the control

            self._updateControlText();

        	

        	// Ensure the focus stays pointing where the user is working

        	if ( senderCheckbox != null) { senderCheckbox.focus(); }

        },

        _sourceSelectChangeHandler: function(event) {

            var self = this, dropWrapper = this.dropWrapper;

            dropWrapper.find("input").val(self.sourceSelect.val());



        	// update the text shown in the control

        	self._updateControlText();

        },

        // Updates the text shown in the control depending on the checked (selected) items

        _updateControlText: function() {

            var self = this, sourceSelect = this.sourceSelect, options = this.options, controlWrapper = this.controlWrapper;

            var firstOption = sourceSelect.find("option:first");

            var selectOptions = sourceSelect.find("option");

            var text = self._formatText(selectOptions, options.firstItemChecksAll, firstOption);

            var controlLabel = controlWrapper.find(".ui-dropdownchecklist-text");

            controlLabel.html(text);

            // the attribute needs naked text, not html

            controlLabel.attr("title", controlLabel.text());

        },

        // Formats the text that is shown in the control

        _formatText: function(selectOptions, firstItemChecksAll, firstOption) {

            var text;

            if ( $.isFunction(this.options.textFormatFunction) ) {

            	// let the callback do the formatting, but do not allow it to fail

            	try {

                	text = this.options.textFormatFunction(selectOptions);

                } catch(ex) {

                	alert( 'textFormatFunction failed: ' + ex );

                }

            } else if (firstItemChecksAll && (firstOption != null) && firstOption.prop("selected")) {

                // just set the text from the first item

                text = firstOption.html();

            } else {

                // concatenate the text from the checked items

                text = "";

                selectOptions.each(function() {

                    if ($(this).prop("selected")) {

                        if ( text != "" ) { text += ", "; }

                        /* NOTE use of .html versus .text, which can screw up ampersands for IE */

                        var optCss = $(this).attr('style');

                        var tempspan = $('<span/>');

                        tempspan.html( $(this).html() );

                        if ( optCss == null ) {

                        	text += tempspan.html();

                        } else {

                        	tempspan.attr('style',optCss);

                        	text += $("<span/>").append(tempspan).html();

                        }

                    }

                });

                if ( text == "" ) {

                    text = (this.options.emptyText != null) ? this.options.emptyText : "&nbsp;";

                }

            }

            return text;

        },

        // Shows and hides the drop container

        _toggleDropContainer: function( makeOpen ) {

            var self = this;

            // hides the last shown drop container

            var hide = function(instance) {

                if ((instance != null) && instance.dropWrapper.isOpen ){

                    instance.dropWrapper.isOpen = false;

                    $.ui.dropdownchecklist.gLastOpened = null;



	            	var config = instance.options;

                    instance.dropWrapper.css({

                        top: "-33000px",

                        left: "-33000px"

                    });

                    var aControl = instance.controlSelector;

	                aControl.removeClass("ui-state-active");

	                aControl.removeClass("ui-state-hover");



                    var anIcon = instance.controlWrapper.find(".ui-icon");

                    if ( anIcon.length > 0 ) {

                    	anIcon.removeClass( (config.icon.toClose != null) ? config.icon.toClose : "ui-icon-triangle-1-s");

                    	anIcon.addClass( (config.icon.toOpen != null) ? config.icon.toOpen : "ui-icon-triangle-1-e");

                    }

                    $(document).unbind("click", hide);

                    

                    // keep the items out of the tab order by disabling them

                    instance.dropWrapper.find("input.active").prop("disabled",true);

                    

                    // the following blur just does not fire???  because it is hidden???  because it does not have focus???

			  		//instance.sourceSelect.trigger("blur");

			  		//instance.sourceSelect.triggerHandler("blur");

			  		if($.isFunction(config.onComplete)) { try {

			     		config.onComplete.call(instance,instance.sourceSelect.get(0));

                    } catch(ex) {

                    	alert( 'callback failed: ' + ex );

                    }}

                }

            };

            // shows the given drop container instance

            var show = function(instance) {

            	if ( !instance.dropWrapper.isOpen ) {

	                instance.dropWrapper.isOpen = true;

	                $.ui.dropdownchecklist.gLastOpened = instance;



	            	var config = instance.options;

/**** Issue127 (and the like) to correct positioning when parent element is relative

 ****	This positioning only worked with simple, non-relative parent position

	                instance.dropWrapper.css({

	                    top: instance.controlWrapper.offset().top + instance.controlWrapper.outerHeight() + "px",

	                    left: instance.controlWrapper.offset().left + "px"

	                });

****/

             		if ((config.positionHow == null) || (config.positionHow == 'absolute')) {

             			/** Floats above subsequent content, but does NOT scroll */

		                instance.dropWrapper.css({

		                    position: 'absolute'

		                ,   top: instance.controlWrapper.position().top + instance.controlWrapper.outerHeight() + "px"

		                ,   left: instance.controlWrapper.position().left + "px"

		                });

		            } else if (config.positionHow == 'relative') {

		            	/** Scrolls with the parent but does NOT float above subsequent content */

		                instance.dropWrapper.css({

		                    position: 'relative'

		                ,   top: "0px"

		                ,   left: "0px"

		                });

					}

					var zIndex = 0;

					if (config.zIndex == null) {

						var ancestorsZIndexes = instance.controlWrapper.parents().map(

							function() {

								var zIndex = $(this).css("z-index");

								return isNaN(zIndex) ? 0 : zIndex; }

							).get();

						var parentZIndex = Math.max.apply(Math, ancestorsZIndexes);

						if ( parentZIndex >= 0) zIndex = parentZIndex+1;

					} else {

						/* Explicit set from the optins */

						zIndex = parseInt(config.zIndex);

					}

					if (zIndex > 0) {

						instance.dropWrapper.css( { 'z-index': zIndex } );

					}



	                var aControl = instance.controlSelector;

	                aControl.addClass("ui-state-active");

	                aControl.removeClass("ui-state-hover");

	                

	                var anIcon = instance.controlWrapper.find(".ui-icon");

	                if ( anIcon.length > 0 ) {

	                	anIcon.removeClass( (config.icon.toOpen != null) ? config.icon.toOpen : "ui-icon-triangle-1-e");

	                	anIcon.addClass( (config.icon.toClose != null) ? config.icon.toClose : "ui-icon-triangle-1-s");

	                }

	                $(document).bind("click", function(e) {hide(instance);} );

	                

                    // insert the items back into the tab order by enabling all active ones

                    var activeItems = instance.dropWrapper.find("input.active");

                    activeItems.prop("disabled",false);

                    

                    // we want the focus on the first active input item

                    var firstActiveItem = activeItems.get(0);

                    if ( firstActiveItem != null ) {

                    	firstActiveItem.focus();

                    }

			    }

            };

            if ( makeOpen ) {

            	hide($.ui.dropdownchecklist.gLastOpened);

            	show(self);

            } else {

            	hide(self);

            }

        },

        // Set the size of the control and of the drop container

        _setSize: function(dropCalculatedSize) {

            var options = this.options, dropWrapper = this.dropWrapper, controlWrapper = this.controlWrapper;



            // use the width from config options if set, otherwise set the same width as the drop container

            var controlWidth = dropCalculatedSize.width;

            if (options.width != null) {

                controlWidth = parseInt(options.width);

            } else if (options.minWidth != null) {

                var minWidth = parseInt(options.minWidth);

                // if the width is too small (usually when there are no items) set a minimum width

                if (controlWidth < minWidth) {

                    controlWidth = minWidth;

                }

            }

            var control = this.controlSelector;

            control.css({ width: controlWidth + "px" });

            

            // if we size the text, then Firefox places icons to the right properly

            // and we do not wrap on long lines

            var controlText = control.find(".ui-dropdownchecklist-text");

            var controlIcon = control.find(".ui-icon");

            if ( controlIcon != null ) {

            	// Must be an inner/outer/border problem, but IE6 needs an extra bit of space,

            	// otherwise you can get text pushed down into a second line when icons are active

            	controlWidth -= (controlIcon.outerWidth() + 4);

            	controlText.css( { width: controlWidth + "px" } );

            }

            // Account for padding, borders, etc

            controlWidth = controlWrapper.outerWidth();

            

            // the drop container height can be set from options

            var maxDropHeight = (options.maxDropHeight != null)

            					? parseInt(options.maxDropHeight)

            					: -1;

            var dropHeight = ((maxDropHeight > 0) && (dropCalculatedSize.height > maxDropHeight))

            					? maxDropHeight 

            					: dropCalculatedSize.height;

            // ensure the drop container is not less than the control width (would be ugly)

            var dropWidth = dropCalculatedSize.width < controlWidth ? controlWidth : dropCalculatedSize.width;



            $(dropWrapper).css({

                height: dropHeight + "px",

                width: dropWidth + "px"

            });

            dropWrapper.find(".ui-dropdownchecklist-dropcontainer").css({

                height: dropHeight + "px"

            });

        },

        // Initializes the plugin

        _init: function() {

            var self = this, options = this.options;

			if ( $.ui.dropdownchecklist.gIDCounter == null) {

				$.ui.dropdownchecklist.gIDCounter = 1;

			}

            // item blurring relies on a cancelable timer

            self.blurringItem = null;



            // sourceSelect is the select on which the plugin is applied

            var sourceSelect = self.element;

            self.initialDisplay = sourceSelect.css("display");

            sourceSelect.css("display", "none");

            self.initialMultiple = sourceSelect.prop("multiple");

            self.isMultiple = self.initialMultiple;

            if (options.forceMultiple != null) { self.isMultiple = options.forceMultiple; }

            sourceSelect.prop("multiple", true);

            self.sourceSelect = sourceSelect;



            // append the control that resembles a single selection select

            var controlWrapper = self._appendControl();

            self.controlWrapper = controlWrapper;

            self.controlSelector = controlWrapper.find(".ui-dropdownchecklist-selector");



            // create the drop container where the items are shown

            var dropWrapper = self._appendDropContainer(controlWrapper);

            self.dropWrapper = dropWrapper;



            // append the items from the source select element

            var dropCalculatedSize = self._appendItems();



            // updates the text shown in the control

            self._updateControlText(controlWrapper, dropWrapper, sourceSelect);



            // set the sizes of control and drop container

            self._setSize(dropCalculatedSize);

            

            // look for possible auto-check needed on first item

			if ( options.firstItemChecksAll ) {

				self._syncSelected(null);

			}

            // BGIFrame for IE6

			if (options.bgiframe && typeof self.dropWrapper.bgiframe == "function") {

				self.dropWrapper.bgiframe();

			}

          	// listen for change events on the source select element

          	// ensure we avoid processing internally triggered changes

          	self.sourceSelect.change(function(event, eventName) {

	            if (eventName != 'ddcl_internal') {

	                self._sourceSelectChangeHandler(event);

	            }

	        });

        },

        // Refresh the disable and check state from the underlying control

        _refreshOption: function(item,disabled,selected) {

			var aParent = item.parent();

			// account for enabled/disabled

            if ( disabled ) {

            	item.prop("disabled",true);

            	item.removeClass("active");

            	item.addClass("inactive");

            	aParent.addClass("ui-state-disabled");

            } else {

            	item.prop("disabled",false);

            	item.removeClass("inactive");

            	item.addClass("active");

            	aParent.removeClass("ui-state-disabled");

            }

            // adjust the checkbox state

            item.prop("checked",selected);

        },

        _refreshGroup: function(group,disabled) {

            if ( disabled ) {

            	group.addClass("ui-state-disabled");

            } else {

            	group.removeClass("ui-state-disabled");

            }

        },

        // External command to explicitly close the dropdown

        close: function() {

			this._toggleDropContainer(false);

        },

        // External command to refresh the ddcl from the underlying selector

        refresh: function() {

            var self = this, sourceSelect = this.sourceSelect, dropWrapper = this.dropWrapper;

            

            var allCheckBoxes = dropWrapper.find("input");

            var allGroups = dropWrapper.find(".ui-dropdownchecklist-group");

            

            var groupCount = 0;

            var optionCount = 0;

			sourceSelect.children().each(function(index) {

				var opt = $(this);

				var disabled = opt.prop("disabled");

                if (opt.is("option")) {

                	var selected = opt.prop("selected");

                	var anItem = $(allCheckBoxes[optionCount]);

                    self._refreshOption(anItem, disabled, selected);

                    optionCount += 1;

                } else if (opt.is("optgroup")) {

                    var text = opt.attr("label");

                    if (text != "") {

                    	var aGroup = $(allGroups[groupCount]);

                    	self._refreshGroup(aGroup, disabled);

                    	groupCount += 1;

	                }

					opt.children("option").each(function() {

		                var subopt = $(this);

						var subdisabled = (disabled || subopt.prop("disabled"));

                		var selected = subopt.prop("selected");

                		var subItem = $(allCheckBoxes[optionCount]);

		                self._refreshOption(subItem, subdisabled, selected );

		                optionCount += 1;

		            });

                }

			});

			// sync will handle firstItemChecksAll and updateControlText

			self._syncSelected(null);

        },

        // External command to enable the ddcl control

        enable: function() {

            this.controlSelector.removeClass("ui-state-disabled");

            this.disabled = false;

        },

        // External command to disable the ddcl control

        disable: function() {

            this.controlSelector.addClass("ui-state-disabled");

            this.disabled = true;

        },

        // External command to destroy all traces of the ddcl control

        destroy: function() {

            $.Widget.prototype.destroy.apply(this, arguments);

            this.sourceSelect.css("display", this.initialDisplay);

            this.sourceSelect.prop("multiple", this.initialMultiple);

            this.controlWrapper.unbind().remove();

            this.dropWrapper.remove();

        }

    });



    $.extend($.ui.dropdownchecklist, {

        defaults: {

            width: null

        ,   maxDropHeight: null

        ,   firstItemChecksAll: false

        ,   closeRadioOnClick: false

        ,   minWidth: 50

        ,   positionHow: 'absolute'

        ,   bgiframe: false

        ,	explicitClose: null

        }

    });



})(jQuery);