//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2008 Valerio Proietti, <http://mad4milk.net>, MIT Style License.

/*
Script: Tips.js
    Class for creating nice tips that follow the mouse cursor when hovering an element.

License:
    MIT-style license.
*/

var Tips = new Class({

    Implements: [Events, Options],

    options: {
        onShow: function(tip){
            tip.setStyle('visibility', 'visible');
        },
        onHide: function(tip){
            tip.setStyle('visibility', 'hidden');
        },
        showDelay: 100,
        hideDelay: 100,
        className: null,
        offsets: {x: 16, y: 16},
        fixed: false
    },

    initialize: function(){
        var params = Array.link(arguments, {options: Object.type, elements: $defined});
        this.setOptions(params.options || null);
        
        this.tip = new Element('div').inject(document.body);
        
        if (this.options.className) this.tip.addClass(this.options.className);
        
        var top = new Element('div', {'class': 'tip-top'}).inject(this.tip);
        this.container = new Element('div', {'class': 'tip'}).inject(this.tip);
        var bottom = new Element('div', {'class': 'tip-bottom'}).inject(this.tip);

        this.tip.setStyles({position: 'absolute', top: 0, left: 0, visibility: 'hidden'});
        
        if (params.elements) this.attach(params.elements);
    },
    
    attach: function(elements){
        $$(elements).each(function(element){
            var title = element.retrieve('tip:title', element.get('title'));
            var text = element.retrieve('tip:text', element.get('rel') || element.get('href'));
            var enter = element.retrieve('tip:enter', this.elementEnter.bindWithEvent(this, element));
            var leave = element.retrieve('tip:leave', this.elementLeave.bindWithEvent(this, element));
            element.addEvents({mouseenter: enter, mouseleave: leave});
            if (!this.options.fixed){
                var move = element.retrieve('tip:move', this.elementMove.bindWithEvent(this, element));
                element.addEvent('mousemove', move);
            }
            element.store('tip:native', element.get('title'));
            element.erase('title');
        }, this);
        return this;
    },
    
    detach: function(elements){
        $$(elements).each(function(element){
            element.removeEvent('mouseenter', element.retrieve('tip:enter') || $empty);
            element.removeEvent('mouseleave', element.retrieve('tip:leave') || $empty);
            element.removeEvent('mousemove', element.retrieve('tip:move') || $empty);
            element.eliminate('tip:enter').eliminate('tip:leave').eliminate('tip:move');
            var original = element.retrieve('tip:native');
            if (original) element.set('title', original);
        });
        return this;
    },
    
    elementEnter: function(event, element){
        
        $A(this.container.childNodes).each(Element.dispose);
        
        var title = element.retrieve('tip:title');
        
        if (title){
            this.titleElement = new Element('div', {'class': 'tip-title'}).inject(this.container);
            this.fill(this.titleElement, title);
        }
        
        var text = element.retrieve('tip:text');
        if (text){
            this.textElement = new Element('div', {'class': 'tip-text'}).inject(this.container);
            this.fill(this.textElement, text);
        }
        
        this.timer = $clear(this.timer);
        this.timer = this.show.delay(this.options.showDelay, this);

        this.position((!this.options.fixed) ? event : {page: element.getPosition()});
    },
    
    elementLeave: function(event){
        $clear(this.timer);
        this.timer = this.hide.delay(this.options.hideDelay, this);
    },
    
    elementMove: function(event){
        this.position(event);
    },
    
    position: function(event){
        var size = window.getSize(), scroll = window.getScroll();
        var tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight};
        var props = {x: 'left', y: 'top'};
        for (var z in props){
            var pos = event.page[z] + this.options.offsets[z];
            if ((pos + tip[z] - scroll[z]) > size[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
            this.tip.setStyle(props[z], pos);
        }
    },
    
    fill: function(element, contents){
        (typeof contents == 'string') ? element.set('html', contents) : element.adopt(contents);
    },

    show: function(){
        this.fireEvent('show', this.tip);
    },

    hide: function(){
        this.fireEvent('hide', this.tip);
    }

});