/**
 * @fileoverview Tooltip class with all necessary helper functions
 *
 * @author      Marc-Oliver Stühmer
 * @version     1.0.20081107
 */


/**
 * Attach an event handler to an element's event
 *
 * @param   {Node} element              The element to attach the event handler to
 * @param   {String} eventname          The name of the event (without 'on')
 * @param   {Function} handler          The event handler function to add
 */
function addEventHandler(element, eventname, handler)
{
    if (element.addEventListener) {
        element.addEventListener(eventname, handler, false);   // DOM version
    } else if (element.attachEvent) {
        element.attachEvent('on' + eventname, handler);   // IE version
    }
}

/**
 * Determine the document size and scrollbar positions
 *
 * @return  {Object}                    The document dimensions (height, width, scrollWidth, scrollHeight, offsetX, offsetY)
 */
function getDocumentDimensions()
{
    var width, height, sWidth, sHeight, offsetX, offsetY;

    if (document.compatMode && document.compatMode != 'BackCompat'
        && navigator.userAgent.search('KHTML|AppleWebKit|Safari') != -1)
    {
        width   = document.documentElement.clientWidth;
        height  = document.documentElement.clientHeight;
        offsetX = document.body.scrollLeft;
        offsetY = document.body.scrollTop;
        sWidth  = document.documentElement.scrollWidth;
        sHeight = document.documentElement.scrollHeight;
    } else if (document.compatMode && document.compatMode != 'BackCompat'
        && navigator.userAgent.indexOf('Opera') == -1)
    {
        width   = document.documentElement.clientWidth;
        height  = document.documentElement.clientHeight;
        offsetX = document.documentElement.scrollLeft;
        offsetY = document.documentElement.scrollTop;
        sWidth  = document.documentElement.scrollWidth;
        sHeight = document.documentElement.scrollHeight;
    } else {
        width   = document.body.clientWidth;
        height  = document.body.clientHeight;
        offsetX = document.body.scrollLeft;
        offsetY = document.body.scrollTop;
        sWidth  = document.body.scrollWidth;
        sHeight = document.body.scrollHeight;
    }

    return {
        'width'        : width,
        'height'       : height,
        'scrollWidth'  : sWidth,
        'scrollHeight' : sHeight,
        'offsetX'      : offsetX,
        'offsetY'      : offsetY
    };
}

/**
 * Set the opacity of the given element
 *
 * @param   {Node, String} element      Element or ID of the element to set the opacity of
 * @param   {Number} opacity            The opacity value to set (0-100)
 */
function setOpacity(element, opacity)
{
    if (typeof element != 'object') {
        element = document.getElementById(element);
    }
    if (opacity > 100) {
        opacity = 100;
    }
    if (opacity < 0) {
        opacity = 0;
    }

    element.style.filter       = 'alpha(opacity:' + opacity + ')';
    element.style.KHTMLOpacity = opacity / 100;
    element.style.MozOpacity   = opacity / 100;
    element.style.opacity      = opacity / 100;
}


/**
 * @class       Mouse cursor position class
 * @static
 */
CursorPos = {

    /**
     * The X value of the current cursor position
     * @static
     * @type    Number
     */
    x : null,
    /**
     * The Y value of the current cursor position
     * @static
     * @type    Number
     */
    y : null,

    /**
     * Start to acquire the cursor position from the document object
     * @static
     */
    init : function ()
    {
        var oldHandler = document.onmousemove;
        document.onmousemove = function (ev) {
            if (oldHandler) {
                oldHandler(ev);
            }
            CursorPos._detectCoords(ev);
        }
    },

    /**
     * Determine the current mouse cursor coordinates
     * @private
     * @static
     *
     * @param   {Event} ev                  The calling event
     */
    _detectCoords : function (ev)
    {
        if (!ev) {   // IE version
            if (document.compatMode && document.compatMode != 'BackCompat') {
                var x = document.documentElement.scrollLeft + window.event.clientX;
                var y = document.documentElement.scrollTop + window.event.clientY;
            } else {
                var x = document.body.scrollLeft + window.event.clientX;
                var y = document.body.scrollTop + window.event.clientY;
            }
        } else {   // DOM version
            var x = ev.pageX;
            var y = ev.pageY;
        }
        CursorPos.x = x;
        CursorPos.y = y;
    }

};


/**
 * @class       Tooltip class
 * @static
 */
Tooltip = {

    /**
     * The X offset of the tooltip relative to the cursor position
     * @static
     * @type    Number
     */
    offsetX : 0,
    /**
     * The Y offset of the tooltip relative to the cursor position
     * @static
     * @type    Number
     */
    offsetY : 18,
    /**
     * The fade-in time [msec], 0 to disable fade-in effect
     * @static
     * @type    Number
     */
    fadeInTime : 300,
    /**
     * The fade-out time [msec], 0 to disable fade-out effect
     * @static
     * @type    Number
     */
    fadeOutTime : 400,
    /**
     * Enable tooltip to overlap select boxes in IE6?<br />
     * This will automatically disable the fade effects for IE6!
     * @static
     * @type    Boolean
     */
    avoidIE6OverlapBug : true,

    /**
     * Display the tooltip at the current cursor position
     * @static
     *
     * @param   {Node, String} source       Element or ID of the element to get the tooltip's content from
     */
    show : function (source)
    {
        if (!Tooltip._docDim) {
            return;
        }

        var div = document.getElementById('tooltip');
        if (!div) {
            div = document.createElement('div');
            div.setAttribute('id', 'tooltip');
            div.style.display  = 'none';
            div.style.position = 'absolute';
            div.style.zIndex   = '1000';
            document.body.appendChild(div);
        }
        if (Tooltip.avoidIE6OverlapBug) {
            // Dummy IFrame for IE 6 to cover select boxes
            var iframe = document.getElementById('if_tooltip');
            if (!iframe) {
                iframe = document.createElement('iframe');
                iframe.setAttribute('id', 'if_tooltip');
                iframe.style.display  = 'none';
                iframe.style.position = 'absolute';
                iframe.style.zIndex   = '999';
                iframe.style.border   = '0';
                document.body.appendChild(iframe);
            }
        }
        if (typeof source != 'object') {
            source = document.getElementById(source);
        }
        div.innerHTML = source.innerHTML;

        div.style.display = '';   // Temporarily show DIV to determine its size
        var divWidth  = div.offsetWidth;
        var divHeight = div.offsetHeight;
        div.style.display = 'none';

        if (CursorPos.x + Tooltip.offsetX + divWidth - Tooltip._docDim.offsetX > Tooltip._docDim.width) {
            var x = Tooltip._docDim.width - divWidth + Tooltip._docDim.offsetX;
        } else if (CursorPos.x + Tooltip.offsetX - Tooltip._docDim.offsetX < 0) {
            var x = Tooltip._docDim.offsetX;
        } else {
            var x = CursorPos.x + Tooltip.offsetX;
        }
        if (CursorPos.y + Tooltip.offsetY + divHeight - Tooltip._docDim.offsetY > Tooltip._docDim.height) {
            var y = CursorPos.y - divHeight - 8;
        } else if (CursorPos.y + Tooltip.offsetY - Tooltip._docDim.offsetY < 0) {
            var y = CursorPos.y + 18;
        } else {
            var y = CursorPos.y + Tooltip.offsetY;
        }

        div.style.left = x + 'px';
        div.style.top  = y + 'px';
        div.style.display = '';
        if (!Tooltip.avoidIE6OverlapBug) {
            if (Tooltip.fadeInTime) {
                if (!Tooltip._fadingIn) {
                    Tooltip._fadingIn = true;
                    Tooltip._fadeIn(div);
                }
            } else {
                clearTimeout(Tooltip._fadeTimer);
                Tooltip._opacity = 100;
                setOpacity(div, Tooltip._opacity);
            }
        } else {
            iframe.style.left   = x + 'px';
            iframe.style.top    = y + 'px';
            iframe.style.width  = div.offsetWidth + 'px';
            iframe.style.height = div.offsetHeight + 'px';
            iframe.style.display = '';
        }
    },

    /**
     * Hide the tooltip
     * @static
     */
    hide : function ()
    {
        Tooltip._fadingIn = false;

        var div = document.getElementById('tooltip');
        if (!div) {
            return;
        }

        if (Tooltip.fadeOutTime && !Tooltip.avoidIE6OverlapBug) {
            Tooltip._fadeOut(div);
        } else {
            div.style.display = 'none';

            var iframe = document.getElementById('if_tooltip');
            if (iframe) {
                iframe.style.display = 'none';
            }
            clearTimeout(Tooltip._fadeTimer);
        }
        if (!Tooltip.fadeOutTime) {
            Tooltip._opacity = 0;
        }
    },

    /**
     * Initialize the tooltip's properties
     * @static
     */
    init : function ()
    {
        Tooltip._opacity = 0;
        Tooltip.avoidIE6OverlapBug &= (
            navigator.userAgent.indexOf('MSIE 6.0') != -1
                && navigator.userAgent.search(/MSIE [7-9]\.0/) == -1);

        CursorPos.init();
        Tooltip._determineDocDimensions();
        addEventHandler(window, 'resize', Tooltip._determineDocDimensions);
        addEventHandler(window, 'scroll', Tooltip._determineDocDimensions);
    },

    /**
     * Fade the tooltip in smoothly
     * @private
     * @static
     *
     * @param   {Node} div                  The tooltip DIV to fade in
     */
    _fadeIn : function (div)
    {
        var steps = 20;   // Fade-in steps per second

        function _fade()
        {
            if (Tooltip._opacity >= 100) {
                Tooltip._opacity = 100;
                Tooltip._fadingIn = false;
                return;
            }
            Tooltip._opacity += 100 / (Tooltip.fadeInTime / 1000) / steps;
            setOpacity(div, Tooltip._opacity);
            clearTimeout(Tooltip._fadeTimer);
            Tooltip._fadeTimer = setTimeout(_fade, 1000 / steps);
        }

        setOpacity(div, Tooltip._opacity);
        _fade();
    },

    /**
     * Fade the tooltip out smoothly
     * @private
     * @static
     *
     * @param   {Node} div                  The tooltip DIV to fade out
     */
    _fadeOut : function (div)
    {
        var steps = 20;   // Fade-out steps per second

        function _fade()
        {
            if (Tooltip._opacity <= 0) {
                Tooltip._opacity = 0;
                div.style.display = 'none';
                return;
            }
            Tooltip._opacity -= 100 / (Tooltip.fadeOutTime / 1000) / steps;
            setOpacity(div, Tooltip._opacity);
            clearTimeout(Tooltip._fadeTimer);
            Tooltip._fadeTimer = setTimeout(_fade, 1000 / steps);
        }

        setOpacity(div, Tooltip._opacity);
        _fade();
    },

    /**
     * Determine the size of the document
     * @private
     * @static
     */
    _determineDocDimensions : function ()
    {
        Tooltip._docDim = getDocumentDimensions();
    }

};
