var BsideTips = new Class({
    options: {
        onShow: function(tip){
            tip.setStyle('visibility', 'visible');
        },
        onHide: function(tip){
            tip.setStyle('visibility', 'hidden');
        },
        maxTitleChars: 30,
        showDelay: 1200,
        hideDelay: 0,
        className: 'tool',
        offsets: {'x': 16, 'y': 16},
        fixed: false,
        allowTitle: false,
        evalScripts: false
    },

    initialize: function(elements, options){
        this.setOptions(options);
        this.toolTip = new Element('div', {
            'class': 'bs_tooltip',
            'styles': {
                'position': 'absolute',
                'top': '0',
                'left': '0',
                'visibility': 'hidden'
            }
        }).inject(document.body);
        
        this.image = new Element('img', { 
            'class': 'bs_pngFix', 
            'id' : 'bs_tipCaptionImageTopLeft',
            'src' : '/images/tooltip-top-left.png',
            'width' : '79px',
            'height' : '25px'
            }
        ).inject(this.toolTip);
        this.image = new Element('img', { 
            'class': 'bs_pngFix', 
            'id' : 'bs_tipCaptionImageTopRight',
            'src' : '/images/tooltip-top-right.png',
            'width' : '79px',
            'height' : '25px'
            }
        ).inject(this.toolTip);
        
        this.wrapper = new Element('div').inject(this.toolTip);
        
        this.image = new Element('img', { 
            'class': 'bs_pngFix', 
            'id' : 'bs_tipCaptionImageBottomLeft',
            'src' : '/images/tooltip-bottom-left.png',
            'width' : '79px',
            'height' : '25px'
            }
        ).inject(this.toolTip);
        this.image = new Element('img', { 
            'class': 'bs_pngFix', 
            'id' : 'bs_tipCaptionImageBottomRight',
            'src' : '/images/tooltip-bottom-right.png',
            'width' : '79px',
            'height' : '25px'
            }
        ).inject(this.toolTip);
        this.tooltipCache = [];
        this.ajaxRequest = null;
        
        $$(elements).each(this.build, this);
        if (this.options.initialize) this.options.initialize.call(this);
    },

    build: function(el){
        // extension by Jebbie, 1 line of code, that is needed to make it compatible to mootools 1.2
        $extend(el, { $tmp: {myTitle: '', myText: '', myIcon: ''}});

        // skip if tooltip attached 
        if (el.getProperty('tooltipAttached') == 'true') return;
        el.setProperty('tooltipAttached','true');
        el.$tmp.myTitle = (el.href && el.getTag() == 'a') ? el.href.replace('http://', '') : (el.rel || false);
        if (el.title){
            var dual = el.title.split('::');
            if (dual.length > 1){
                el.$tmp.myTitle = dual[0].trim();
                el.$tmp.myText = dual[1].trim();
            } else {
                el.$tmp.myText = el.title;
            }
            el.removeAttribute('title');
        } else {
            el.$tmp.myText = false;
        }
        if (el.$tmp.myTitle && el.$tmp.myTitle.length > this.options.maxTitleChars) el.$tmp.myTitle = el.$tmp.myTitle.substr(0, this.options.maxTitleChars - 1) + "&hellip;";
        el.addEvent('mouseenter', function(event){
            this.start(el);
            if (!this.options.fixed) this.locate(event);
            else this.position(el);
        }.bind(this));
        if (!this.options.fixed) el.addEvent('mousemove', this.locate.bindWithEvent(this));
        var end = this.end.bind(this);
        el.addEvent('mouseleave', end);
        el.addEvent('trash', end);
    },

    start: function(el){
        this.wrapper.empty();
        if (this.ajaxRequest) this.ajaxRequest.cancel();
        $clear(this.timer);
        var tooltipUrl = el.getAttribute('tooltipurl');
        if (tooltipUrl) {
            var tooltipText = this.tooltipCache[tooltipUrl];
            if (tooltipText) {
                this.text = new Element('span').inject(new Element('div', {'class': 'bs_tooltipBottom'}).inject(this.wrapper)).setHTML(tooltipText);
                if (this.options.evalScripts) {
                    this.evalScripts(tooltipText);
                }
                this.timer = this.show.delay(this.options.showDelay, this);
            }
            else {
                el.$tmp = new Element('div');
                el.$tmp.myText = "";
                var tooltipThis = this;

                this.ajaxRequest = new Request({
                    method: 'get',
                    url: tooltipUrl,
                    onComplete: function(response) {
                        el.$tmp.innerHTML = response;
                        tooltipText = el.$tmp.innerHTML;
                        tooltipThis.text = new Element('span').inject(new Element('div', {'class': 'bs_tooltipBottom'}).inject(tooltipThis.wrapper)).setHTML(tooltipText);
                        if (tooltipThis.options.evalScripts) {
                            tooltipThis.evalScripts(tooltipText);
                        }
                        tooltipThis.tooltipCache[tooltipUrl] = tooltipText;
                        tooltipThis.timer = tooltipThis.show.delay(tooltipThis.options.showDelay, tooltipThis);
                    }
                });

                // YG: Request would remove scripts from response after processing, so we override it.
                this.ajaxRequest.processScripts = function(text){
                    if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
                    return text; 
                }
                this.ajaxRequest.send();
            }
        }
        else {
            if (el.$tmp.myTitle && this.options.allowTitle){
                this.title = new Element('span').inject(new Element('div', {'class': this.options.className + '-title'}).inject(this.wrapper)).setHTML(el.$tmp.myTitle);
            }
            if (el.$tmp.myText){
                this.text = new Element('span').inject(new Element('div', {'class': 'bs_tooltipBottom'}).inject(this.wrapper)).setHTML(el.$tmp.myText);
            }
            this.timer = this.show.delay(this.options.showDelay, this);
        }
    },
    
    end: function(event){
        if (this.ajaxRequest) this.ajaxRequest.cancel();
        $clear(this.timer);
        this.timer = this.hide.delay(this.options.hideDelay, this);
    },
    
    evalScripts: function(text) {
        var scripts = [];
        var regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
        while ((script = regexp.exec(text))) scripts.push(script[1]);
        scripts = scripts.join('\n');
        if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0);
    },

    position: function(element){
        var pos = element.getPosition();
        this.toolTip.setStyles({
            'left': pos.x + this.options.offsets.x,
            'top': pos.y + this.options.offsets.y
        });
    },

    locate: function(event){
        // this may happen on fireEvent
        if (!event) {
            return;
        }
        var onTop = true;
        var onLeft = true;
        var win = {'x': window.getWidth(), 'y': window.getHeight()};
        var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
        var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
        var prop = {'x': 'left', 'y': 'top'};

        for (var z in prop){

            var originalPosition = event.page[z] + this.options.offsets[z];
            var newPosition = originalPosition;
            
            if ((originalPosition + tip[z] - scroll[z]) > win[z]) { 
            	
            	newPosition = event.page[z] - this.options.offsets[z] - tip[z]; 
                if(z == 'x') onLeft = false;
                
                if(z == 'y') {
                	
                	if (newPosition < scroll[z]) {
                		// don't correct the y position if it will make the popup
                		// go off the top of the viewport
                		newPosition = originalPosition;
                	} else {
                		onTop = false;
                	}
                }
            } 
            this.toolTip.setStyle(prop[z], newPosition);
        };
        this.toolTip.removeClass('bs_tooltipTopLeft');
        this.toolTip.removeClass('bs_tooltipTopRight');
        this.toolTip.removeClass('bs_tooltipBottomLeft');
        this.toolTip.removeClass('bs_tooltipBottomRight');

        this.toolTip.addClass( onTop ? (onLeft ? 'bs_tooltipTopLeft' : 'bs_tooltipTopRight') : (onLeft ? 'bs_tooltipBottomLeft' : 'bs_tooltipBottomRight') );
    },

    show: function(){
        if (this.options.timeout) this.timer = this.hide.delay(this.options.timeout, this);
        this.fireEvent('onShow', [this.toolTip]);
    },

    hide: function(){
        this.fireEvent('onHide', [this.toolTip]);
    }
});

BsideTips.implement(new Events, new Options);

var bsideTips, mapTips;

// Google Map tooltip gets initialized (but not visualized) on first mouseenter event.
// We invoke fireEvent to show the tooltip. Tooltip consists of div container for the map
// and javascript initialization. evalScripts parameter forces javascript evaluation after
// DOM is updated with div container. Different layouts produced in different modes. 
// "print" mode uses url from "href", regular "map" (i.e. tooltip) uses url from "tooltipurl".
// tooltipAttached flag is set by BsideTips class in order to avoid double-processing.
window.mapToolTip = function (event) {
    var element = event.target ? event.target : event.srcElement;
    if (element.getAttribute('tooltipAttached') == 'true') return;

    // initialize map tooltip (only once)
    if (typeof(mapTips) == 'undefined') {
        mapTips = new BsideTips([$(element)], {
            showDelay: 500,
            className: 'bs_tool',
            evalScripts: true,
            initialize:function(){
                this.fx = new Fx.Style(this.toolTip, 'opacity', {duration: 500, wait: false}).set(0);
            },
            onShow: function(toolTip) {
                this.fx.start(1);
            },
            onHide: function(toolTip) {
                this.fx.start(0);
            }
        });
    }

    // replace "/print" with "/map" to get url for tooltip
    element.setAttribute("tooltipurl", element.getAttribute("href").replace("/print","/map"));

    // build tooltip (initialization)
    [$(element)].each(mapTips.build, mapTips);

    // show tooltip right away
    element.fireEvent('mouseenter');
}

function initBsideTips() {
    // IE6 does not handle domready correctly here, and we cannot 
    // use load event on re-init as it only fires once when the page is loaded.
    // Moving "new BsideTips ..." to a function prevent it from working,
    // so we have this code twice.
    if (window.ie6 && (typeof(bsideTips) != 'undefined')) {
        bsideTips = new BsideTips($$('.bs_toolTipAware'), {
            showDelay: 500,
            hideDelay: 0,
            className: 'bs_tool',
            allowTitle: false,
            initialize:function(){
                this.fx = new Fx.Style(this.toolTip, 'opacity', {duration: 500, wait: false}).set(0);
            },
            onShow: function(toolTip) {
                this.fx.start(1);
            },
            onHide: function(toolTip) {
                this.fx.start(0);
            }
        });
    }
    else { 
        // IE6 does not handle domready correctly here, so use load event. 
        window.addEvent( window.ie6 ? 'load' : 'domready', function() {
            bsideTips = new BsideTips($$('.bs_toolTipAware'), {
                showDelay: 500,
                hideDelay: 0,
                className: 'bs_tool',
                allowTitle: false,
                initialize:function(){
                    this.fx = new Fx.Style(this.toolTip, 'opacity', {duration: 500, wait: false}).set(0);
                },
                onShow: function(toolTip) {
                    this.fx.start(1);
                },
                onHide: function(toolTip) {
                    this.fx.start(0);
                }
            });
        } );
    }
}

function refreshBsideTipsInPanel(id) {
    var panel = document.getElementById(id);
    $(panel).getElements('.bs_toolTipAware').each(bsideTips.build, bsideTips);
    if ($(panel).hasClass('bs_toolTipAware')) {
        bsideTips.build($(panel));
    }
}

// initialize tooltips
initBsideTips();
