$.fn.xselect = function(options) {

    // options 
    var visibleRows = 7;
    var rowHeight   = 23;

    // "globals"
    var $this = this;
    var id = $this.attr('id');

    var msdd      = $('#'+id+'_msdd');
    var title     = $('#'+id+'_title');
    var titletext = $('#'+id+'_titletext');
    var arrow     = $('#'+id+'_arrow');
    var child     = $('#'+id+'_child');
    
    var inside = false;

	// DOM event handlers
    var document_keydown = function(event) {
        var  keyCode = event.keyCode;
        var charCode = String.fromCharCode(event.keyCode ? event.keyCode : event.charCode);
        charCode = charCode.toUpperCase();
        // down 
        if (keyCode == 40) {
        	event.preventDefault();
        	event.stopPropagation();
        	next_item();
        }
        // up
        else if (keyCode == 38) { // up
        	event.preventDefault();
        	event.stopPropagation();
        	prev_item();
        }
        // A-Z
        else if (charCode.match(/[A-Z]/)) {
        	event.preventDefault();
        	event.stopPropagation();
        	find_item(charCode);
        }
        else {
			//if ($('#'+id).attr("onkeydown") != undefined) {
			//	document.getElementById(id).onkeydown();
        	//}
		}
    };
    var document_mouseup = function() {
    	if (!inside) {
    		close();
    	}
    };
    var title_click = function() {
        if (child.css('display') == 'none') {
        	open();
        }
        else {
        	close();
        }
    };
    var title_mouseover = function() {
    	inside = true;
    	arrow.css({backgroundPosition:'0 -28px'});
    };
    var title_mouseout = function() {
    	inside = false;
    	arrow.css({backgroundPosition:'0 0'});
    };
    var child_mouseover = function() {
    	inside = true;
    };
    var child_mouseout = function() {
    	inside = false;
    };
    
    // functions
    var open = function() {
        child.css('display', 'block');
        child.css('z-index', 9999);
           
    	var child_id = child.attr('id');
   		var all_a = $('#'+child_id+' a.enabled');
   		var islct = selected_index();
   		var curr_a = all_a[islct];
   		set_position(curr_a);
           
        $(document).bind('keydown', function(event) {document_keydown(event);});
        $(document).bind('mouseup', function(event) {document_mouseup(event);});
    };
    var close = function() {
		child.css('display', 'none');
        child.css('z-index', 0);
            
        $(document).unbind('keydown');
        $(document).unbind("mouseup");
    };
    var selected_index = function() {
    	var child_id = child.attr('id');
    	var all_a = $('#'+child_id+' a.enabled');
        for (var index = 0; index < all_a.length; index++) {
    		var curr_a = all_a[index];
    		if ($(curr_a).hasClass('selected')) {
    			return index;
    		}
    	}
    	return -1;
    };
    var set_position = function(curr_a) {
    	var child_id = child.attr('id');
	    var child_e = document.getElementById(child_id);
	    
	    $(curr_a).addClass('selected');
	    titletext.html($(curr_a).html());
	    
   		if (parseInt($(curr_a).position().top) < child_e.scrollTop) {
   		    child_e.scrollTop = $(curr_a).position().top;
   		}
   		else if (parseInt($(curr_a).position().top + $(curr_a).outerHeight(true)) > parseInt(child.outerHeight(true) + child_e.scrollTop)) {
   		    child_e.scrollTop = ($(curr_a).position().top + $(curr_a).outerHeight(true)) - child.outerHeight(true);
   		}
    };
    var next_item = function() {
    	var child_id = child.attr('id');
    	var all_a = $('#'+child_id+' a.enabled');
    	var islct = selected_index();
    	if (islct < 0 || islct >= all_a.length-1) {
    		return;
   		}
   		var slct_a = all_a[islct];
   		var next_a = all_a[islct+1];
   		$(slct_a).removeClass('selected');
   		set_position(next_a);
    };
    var prev_item = function() {
    	var child_id = child.attr('id');
    	var all_a = $('#'+child_id+' a.enabled');
    	var islct = selected_index();
    	if (islct <= 0 || islct > all_a.length-1) {
    		return;
    	}
   		var slct_a = all_a[islct];
   		var prev_a = all_a[islct-1];
   		$(slct_a).removeClass('selected');
   		set_position(prev_a);
    };
    var find_item = function(charCode) {
    	var child_id = child.attr('id');
    	var all_a = $('#'+child_id+' a.enabled');
    	var islct = selected_index();
    	if (islct < 0 || islct > all_a.length-1) {
    		return;
    	}
        for (var index = 1; index <= all_a.length; index++) {
        	var curr_a = all_a[(islct+index)%all_a.length];
			// var value  = $(curr_a).html().replace(/^(.|\r|\n)*<span .*>(.*)<\/span>(.|\r|\n)*$/mi,"$2");
			var value = $.trim($(curr_a).text());
			var first_char = value.substring(0, 1).toUpperCase();
			if (first_char == charCode) {
				var slct_a = all_a[islct];
    			$(slct_a).removeClass('selected');
				set_position(curr_a);
				break;
			}
        }
    };

    // "locals"
    var height;
    var width = $this.width();
    var optionsCount = child.children().length/2; // {a, input} pairs
    var first_a = $('#'+id+'_child a:first');
    // var margin = parseInt(first_a.css("padding-bottom")) + parseInt(first_a.css("padding-top"));
    var margin = first_a.outerHeight(false) - first_a.height();

    // CSS
    msdd.css('width', (width+2)+'px');
    child.css('width', width+'px');
    msdd.addClass(options.mainCSS);

    if (optionsCount > visibleRows) {
        height = rowHeight*visibleRows - margin;
    }
    else {
        height = rowHeight*optionsCount - margin;
    }
    child.css('height', height+'px');

    // DOM events
    title.bind('click',     function(event) {title_click();});
    title.bind('mouseover', function(event) {title_mouseover();});
    title.bind('mouseout',  function(event) {title_mouseout();});
    child.bind('mouseover', function(event) {child_mouseover();});
    child.bind('mouseout',  function(event) {child_mouseout();});
}


