			(function($) {


				jQuery.fn.kaSelect = function(options) {

					return this.each(function() {
						var defaults = {
							checkboxes: false,
							item_height: 20,
							width: 100,
							height: 50,
							padding: 5,
							margin: [0, 0, $.browser.msie ? 7 : 12, 0],
							override_selection: 'none',
							select_all_name: 'Select all',
							default_select_all: false,
							change: null
						};
						var opts = $.extend({}, defaults, options || {});						

						
						$select = $(this);
						var clicked = false;
						// Various dimensions to replicate in the new custom select
						var box_left = $select.offset().left;
						var box_top = $select.offset().top;
						var box_width = opts.width;
						var box_height = opts.height;
						var box_outer_height = opts.height + opts.padding * 2 + opts.margin[0] + opts.margin[2];
						var box_padding_top = opts.padding;
						var box_padding_right = opts.padding;
						var box_padding_bottom = opts.padding;
						var box_padding_left = 6;
						var box_margin_top = opts.margin[0];
						var box_margin_right = opts.margin[1];
						var box_margin_bottom = opts.margin[2];
						var box_margin_left = opts.margin[3];
						// Make the select box
						var $outer = $('<div>');
						var outer_id = $select.attr('id') + '_replaced';
						var list_id = $select.attr('id') + '_list';
						$outer.attr('id', outer_id);
						$outer.addClass('kaselect');
//						$outer.addClass('clearfix');
						$outer.css({
							'position': 'relative',
							'width': box_width,
							'height': box_height + box_padding_top + box_padding_bottom,
							'margin-top': box_margin_top,
							'margin-right': box_margin_right,
							'margin-bottom': box_margin_bottom,
							'margin-left': box_margin_left,
							'z-index': 10,
							'cursor': 'default'
						});
						
						
						var $result_input = $('<input type="hidden" />').attr('name', $select.attr('name'));
						$outer.append($result_input);
						var $container = $('<div>');
						$container.css({
							'width': box_width - 27 - box_padding_left - box_padding_right,
							'height': box_height,
							'padding-top': box_padding_top,
							'padding-right': box_padding_right,
							'padding-bottom': box_padding_bottom,
							'padding-left': box_padding_left,
							'background': 'url(/images/dropdown-left.png) top left no-repeat',
							'overflow': 'hidden',
							'white-space': 'nowrap'
						})
						// The button on the right of the box
						var $button = $('<div>');
						$button.css({
							'background': 'url(/images/dropdown-right.png) top right no-repeat',
							'position': 'absolute',
							'top': 0,
							'right': 0,
							'width': '27px',
							'height': '26px'
						});
						$outer.append($container);
						$outer.append($button);
						// Make the item list						
						var $list = $('<div>');
						var list_css = {
							'position': 'absolute',
							'left': box_left + 3,
							'top': box_top + box_outer_height - 6,
							'padding-top': '6px',
							'min-width': box_width - 8,
							'border': '1px solid #888',
							'border-top': 'none',
							'display': 'none',
							'z-index': 11,
							'background': 'white',
							'cursor': 'default',
							'max-height': '220px',
							'overflow': 'auto',
							'white-space': 'nowrap'
						};
						if ($.browser.msie) {
							list_css['width'] = box_width - 8;
						}

						$list.attr('id', list_id);
						$list.addClass('dropdownlist');
						$list.css(list_css);

						// This thing stores the current state of this box, including all items
						var state = {
							selected_items: [],
							items: {},
							item_count: 0
						};

						function item_select(key) {
							state.selected_items.push(key);
							update_text();
						}
						function item_deselect(key) {
							for (var i in state.selected_items) {
								if (state.selected_items[i] == key) {
									state.selected_items.splice(i, 1);
									update_text();
									return;
								}
							}
						}
						
						function item_select_all() {
							state.selected_items = [];
							for (var i in state.items) {
								state.selected_items.push(i);
							}
							update_text();
						}
						
						function item_deselect_all() {
							state.selected_items = [];
							update_text();
						}
						
						function item_single_select(key) {
							state.selected_items = [key];
							update_text();
						}
						
						function close_list() {
							$list.fadeOut(100);
							$iframe.remove();
						}
						
						// Populate the items with the options from the select. Figure out which ones were selected as well.
						$select.find('option').each(function() {
							state.item_count++;
							state.items[$(this).val()] = $(this).text();
							if ((opts.override_selection == 'none' && $(this).is(':selected')) || opts.override_selection == 'all') {
								state.selected_items.push($(this).val());
							}
						});
						
						if (opts.default_select_all && state.selected_items.length === 0) {
							for (var key in state.items) {
								state.selected_items.push(key);
							}
						}
						
						var $iframe = $('<iframe>');
						$iframe.css($.extend(list_css, {
							'border': 'none',
							'width': box_width - 6,
							'height': opts.item_height * state.item_count + 1
						}));
						
						// Update the text shown in the box with text of the selected items.
						function update_text() {
							var items_texts = [];
							for (var i in state.selected_items) {
								items_texts.push(state.items[state.selected_items[i]]);
							}
							var all_selected = true;
							for (var i in state.items) {
								if ($.inArray(i, state.selected_items) < 0) {
									all_selected = false;
									break;
								}
							}
							if (all_selected) {
								var text = opts.select_all_name;
							}
							else {
								var text = items_texts.join(', ');
							}
							$container.text(text);
							$result_input.val(state.selected_items.join(','));
							if (clicked)
							{
								opts.change && opts.change(state.selected_items);	
							}
						}
						
						update_text();
						
						var any_unselected = false;
						
						// Create item rows to put in the list
						for (var key in state.items) {
							var $row = $('<div>');
							$row.css({
								'height': opts.item_height
							})

							if (opts.checkboxes) {
								var $checkbox = $('<input type="checkbox" />');
								$checkbox.addClass('kaselect-checkbox');
								$checkbox.css('margin', '4px 4px');
								$checkbox.attr('name', $select.attr('name') + '__ITEM_' + key).attr('value', key	);
								
								if ($.inArray(key, state.selected_items) >= 0) {
									$checkbox.attr('checked', 'checked');
									$checkbox.attr('defaultChecked', 'true');	// IE6
								}
								else {
									any_unselected = true;
								}
								
								$row.append($checkbox);
							}
							else {
								$row.css({
									'padding-left': '4px'
								})
							}

							$row.append(state.items[key]);

							$row.hover(function() {
								$(this).css('background-color', '#eef');
							}, function() {
								$(this).css('background-color', '#fff');
							});

							$row.data('key', key);
							
							// Select behavior different if using checkboxes. Check/uncheck the boxes + alter current selection. Don't close the list.
							if (opts.checkboxes) {

								$row.click(function(e) {
									clicked = true;
									var cb = $(this).find('input');
									if (e.target == cb.get(0)) {
										if (cb.is(':checked')) {
											item_select($(this).data('key'));
											$(this).find('input').attr('checked', 'checked');
										}
										else {
											item_deselect($(this).data('key'));
											$(this).find('input').attr('checked', '');
										}
									}
									else {
										if (cb.is(':checked')) {
											cb.attr('checked', '');
											item_deselect($(this).data('key'));
											$(this).find('input').attr('checked', '');
										}
										else {
											cb.attr('checked', 'checked');
											item_select($(this).data('key'));
											$(this).find('input').attr('checked', 'checked');
										}
									}
									
									if ($(this).parent().find('input:not(.select-all-checkbox):not(:checked)').length) {
										$(this).parent().find('input.select-all-checkbox').attr('checked', '');
									}
									else {
 										$(this).parent().find('input.select-all-checkbox').attr('checked', 'checked');
									}
									
								});
							}
							else {
								$row.click(function(e) {
									clicked = true;
									item_single_select($(this).data('key'));
									close_list();
								});
							}
							
							$list.append($row);
						}
						
						if (opts.checkboxes && opts.select_all) {
							var $sa_row = $('<div>');
							$sa_row.css({
								'height': opts.item_height
							});
							
							var $checkbox = $('<input type="checkbox" />"');
							
							$checkbox.addClass('kaselect-checkbox');
								$checkbox.css('margin', '4px 4px');
							$checkbox.attr('name', $select.attr('name') + '__SELECT_ALL').attr('value', '').addClass('select-all-checkbox');
													
							if (!any_unselected) {
								$checkbox.attr('checked', 'checked');
								$checkbox.attr('defaultChecked', 'true');	// IE6
							}
														
							$sa_row.append($checkbox);
							
							$sa_row.append(opts.select_all_name);
							
							$sa_row.hover(function() {
								$(this).css('background-color', '#eef');
							}, function() {
								$(this).css('background-color', '#fff');
							});
							
							$sa_row.click(function(e) {
								var cb = $(this).find('input');
								if (e.target == cb.get(0)) {
									if (cb.is(':checked')) {
										item_select_all();
										$(this).parent().find('input').attr('checked', 'checked');
									}
									else {
										item_deselect_all();
										$(this).parent().find('input').attr('checked', '');
									}
								}
								else {
									if (cb.is(':checked')) {
										cb.attr('checked', '');
										item_deselect_all();
										$(this).parent().find('input').attr('checked', '');
									}
									else {
										cb.attr('checked', 'checked');
										item_select_all();
										$(this).parent().find('input').attr('checked', 'checked');
									}
								}
							});
							
							$list.prepend($sa_row);
						}
						
						$outer.click(function() {
							if ($list.is(':visible')) {
								$list.fadeOut(100);
								$iframe.remove();
								return false;
							}
							$list.css({
								left: $outer.offset().left + 3,
								top: ($outer.offset().top + opts.height + opts.padding * 2) - 2
							});
							$iframe.css({
								left: $outer.offset().left + 3,
								top: ($outer.offset().top + opts.height + opts.padding * 2) - 2
							});
							$iframe.slideDown(150);
							$list.slideDown(150, function() {
								$(this).css('overflow', 'auto');
								$(this).css('overflow-x', 'hidden');
							});
						});
						
						$(document).click(function(e) {

							if(!$(e.target).parents('#' + outer_id).length && !$(e.target).parents('#' + list_id).length) {

								if($list.is(':visible')) {

									$list.fadeOut(100);
									$iframe.remove();
								}
							}
						});
						
						$outer.mousedown(function() {return false;});
						$list.mousedown(function() {return false;});
						
						$('body').append($iframe);
						$('body').append($list);
						$select.replaceWith($outer);
					});
				}
			})(jQuery);
