
// remove functionality from IE6
if(Browser.Engine.trident && Browser.Engine.trident4) {
    var SelectTips = new Class({});
}
else {

var SelectTips = new Class({

    Implements: Options,
    
    // select element ID we're working on
    str_select_id: null,
    
    // cached selected attributes (dimensions and coordinates) for speedier operations
    obj_select_coordinates: null,
    int_select_width: null,
    int_select_option_height: null,
    
    // cached options array for quick indexed access
    arr_select_options: null,
    
    // tooltip element
    elm_tooltip: null,
    
    // boolean as to whether the tooltip is currently visible or not (saves constantly
    // lookuping up the DOM style.display property
    boo_tooltip_visible: false,
    
    // customisable attributes
    options: {
        
        tooltip: {
        
            // wrapper tooltip class
            str_class: 'tooltip',
            
            // how far to position the tooltip from the mouse cursor (px)
            int_offset_x: 16,
            int_offset_y: 16
        }
    },
    
    
    
    /**
     * Constructor
     *
     * Instantiates the tooltip element and makes some pre-calculations such as where each option is
     * in terms of its y-coordinate in the select area for a quick lookup of which tooltip the user
     * requires.
     *
     * @param str str_select_id  ID of the select area to apply the tooltips to
     * @param obj obj_options    Overwritable options
     * @return void
     */
    initialize: function(str_select_id, obj_options) {

        this.setOptions(obj_options);

        // store the select element's id
        this.str_select_id = str_select_id;
        
        // width (content width - excludes scrollbar) of the select area
        this.int_select_width = $(this.str_select_id).getScrollSize().x;
        
        // calculate an individual option's height (we have to do it this manual way since IE
        // returns a 0 height property for option elements - doh!)
        this.arr_select_options = $(this.str_select_id).getElements('*');
        this.int_select_option_height = $(this.str_select_id).getScrollSize().y.round() / this.arr_select_options.length;

        // create tooltip html element
        this._create_tooltip();

        // iterate through each option and extract the title attribute, storing the title and text
        // within the element itself
        for(var i = 0, ilen = this.arr_select_options.length; i < ilen; i++) {

            var elm_option = this.arr_select_options[i];

            // only proceed if this is an option (e.g. not an optgroup)
            if(elm_option.get('tag') == 'option') {

                var str_title = elm_option.getProperty('title');
                
                // only proceed if there's a title set, otherwise ignore
                if(str_title) {
                
                    // replace html entities with the proper tags
                    // Required? Doesn't seem to be but why not, just in case...
                    str_title.replace(/&lt;/gi, '<');
                    str_title.replace(/&gt;/gi, '>');
                
	                // locate the title:text ':' delimiter (if it exists)
	                var int_split_idx = str_title.indexOf(':');
	                
	                var str_tip_title = '';
	                var str_tip_text = '';
	                
	                // no delimiter? the title is the text and there is no title
	                if(int_split_idx == -1) {
	                   str_tip_text = str_title;
	                }
	                
	                // there is a title and text - assign appropriately
	                else {
	                   str_tip_title = str_title.substring(0, int_split_idx - 1);
	                   str_tip_text = str_title.substring(int_split_idx + 1);
	                }

	                // store the attirbutes within the element
	                elm_option.store('title', str_tip_title.trim());
	                elm_option.store('text', str_tip_text.trim());
	                
	                // remove the original title attribute
	                elm_option.removeProperty('title');
	            }
            }
        }
        
        // allow the select area chance to initialise
        this._get_coords.delay(200, this);
        
        // listen to mouse movements on the select area so we can perform tooltips in all browsers
        $(this.str_select_id).addEvent('mousemove', this._event_mousemove.bindWithEvent(this));
        $(this.str_select_id).addEvent('mouseout', this._event_mouseout.bindWithEvent(this));
    },
    
    
    
    /**
     * Utility method to create the div html structure for the tooltip. Follows MooTools tips
     * structure for CSS compatibility (see here: http://docs.mootools.net/Plugins/Tips)
     *
     * @return void
     */
    _create_tooltip: function() {

        // create the tooltip element
        this.elm_tooltip = new Element('div', {
            'class': this.options.tooltip.str_class,
            'styles': {
                'position': 'absolute',
                'display': 'none'        
            }
        }).inject($(document.body), 'bottom');
        
        // create tip-top element
        (new Element('div', {
            'class': 'tip-top'
        })).inject(this.elm_tooltip);
        
        // create main tip wrapper
        var elm_tip_body = new Element('div', {
            'class': 'tip'
        });
        
        // create title element
        (new Element('div', {
            'class': 'tip-title'
        })).inject(elm_tip_body);
        
        // create content/text element
        (new Element('div', {
            'class': 'tip-text'
        })).inject(elm_tip_body, 'bottom');
        
        elm_tip_body.inject(this.elm_tooltip);
        
        // create tip-bottom element
        (new Element('div', {
            'class': 'tip-bottom'
        })).inject(this.elm_tooltip);
    },
    
    
    
    /**
     * Hides or shows the tooltip.
     *
     * @param boo boo  True to show the tooltip, false otherwise
     * @return void
     */
    _show_tooltip: function(boo) {
        
        if(boo == true && this.boo_tooltip_visible == false) {
            this.boo_tooltip_visible = true;
            this.elm_tooltip.setStyle('display', 'block');
        }
        
        else if(boo == false && this.boo_tooltip_visible == true) {
            this.boo_tooltip_visible = false;
            this.elm_tooltip.setStyle('display', 'none');
        }
    },

    
    /**
     * Retrieves and stores current coordinates of the select area (including scroll).
     *
     * @return object
     */
    _get_coords: function() {
    
        // store select's coordinates - Note: If we're wrapped in any relative divs, the
        // MooTools getCoordinates() method fails in IE. As a workaround, we're calling
        // the DOM method getBoundingClientRect for IE only (other browsers themselves
        // have issues with this method).
        // See: http://www.quirksmode.org/dom/w3c_cssom.html#elementview
        if(Browser.Engine.trident) {
            this.obj_select_coordinates = $(this.str_select_id).getBoundingClientRect();
        }
        else {
            this.obj_select_coordinates = $(this.str_select_id).getCoordinates();
        }
        
        // initially scroll the select to the top to prevent calculation bugs (but store so we can
        // move the select back to the correct position)
        var obj_scroll_current = $(this.str_select_id).getScroll();

        // need to "fix" the above coordinates to take into account the scroll since this throws
        // things off
        this.obj_select_coordinates.top += obj_scroll_current.y;
        this.obj_select_coordinates.left += obj_scroll_current.x;
    },
    
    
    /**
     * Event fired whenever the mouse moves over the select area.
     * We extract the coordinates, calculate them relative to the select area's height
     * and scroll offset and determine whether or not the given option requires the tooltip
     * to show.
     *
     * @param obj obj_event  Event object
     * @return void
     */
    _event_mousemove: function(obj_event) {

        // we only do this once - the reason we're doing it here is in order to give the select
        // area chance to initialise itself. Calling this in the constructor can lead to
        // unpredictable results
        if(!this.obj_select_coordinates) {

	        this._get_coords();
        }

        // retrieve x and y coordinates
        var int_x = obj_event.page.x;
        var int_y = obj_event.page.y;
        
        // check we're within bounds of the select content (not the scrollbar) horizontally
        if((int_x - this.obj_select_coordinates.left) > this.int_select_width) {
        
            // we're on the scrollbar; hide the tooltip and return, nothing more to do here
            this._show_tooltip(false);

            return;
        }
        
        var obj_options_tooltip = this.options.tooltip;
        
        // calculate coordinate within the select coodinates system
        var int_select_y = int_y - this.obj_select_coordinates.top;
        
        // calculate the current internal offset of the select element (e.g. how much it's scrolled)
        var int_select_offset = $(this.str_select_id).getScroll().y;
        
        // calculate which option is highlighted
        var int_option_idx = (((int_select_offset + int_select_y) / this.int_select_option_height)).floor();
        
        // is this an option (i.e. not an optgroup)?
        var elm_option = this.arr_select_options[int_option_idx];
        
        if(elm_option && elm_option.get('tag') == 'option') {
        
            var str_title = elm_option.retrieve('title');
            var str_text = elm_option.retrieve('text');
        
            if(str_title) {
        
	            this.elm_tooltip.getElement('.tip-title').set('html', str_title);
	            this.elm_tooltip.getElement('.tip-text').set('html', str_text);
	            
	            // move the tooltip to the mouse position
	            this.elm_tooltip.setStyles({top: obj_event.page.y + obj_options_tooltip.int_offset_y, left: obj_event.page.x + obj_options_tooltip.int_offset_x});
	        
	            // ensure the tooltip is showing
	            this._show_tooltip(true);
	        }
	        else {
	        
	           // no tooltip associated with this option
	           this._show_tooltip(false);
	        }
        }
        else {
        
            // we're over an optiongroup - hide the tooltip
            this._show_tooltip(false);
        } 
    },
    
    
    
    /**
     * Event fired whenever the mouse moves out of the select area.
     * We basically hide the tooltip in this circumstance.
     *
     * @param obj obj_event  Event object
     * @return void
     */
    _event_mouseout: function(obj_event) {

        // retrieve x and y coordinates
        var int_x = obj_event.page.x;
        var int_y = obj_event.page.y;

        // this event seems to be fired when crossing over from one option to
        // another (e.g. not a real mouseout). We're checking here to see if that's
        // the case and ignoring it if so
        var obj_c = this.obj_select_coordinates;
 
        if(int_x > obj_c.left && int_x < obj_c.right && int_y > obj_c.top && int_y < obj_c.bottom) {
            return;
        }

        // we've left the select area, hide the tooltip
        this._show_tooltip(false);
    }
});

}