<!-- $Id: rcTooltip.js,v 1.47 2005/08/25 21:03:53 gaggarwal Exp $ -->

/**
 * Title: DOM Tooltip Library
 * Author: Gautam Aggarwal
 * Credits: Various resources on the web.
 * This is a hybrid toned-down version from various sources and home grown
 *
 * Prototypes have been used on JS objects as opposed to inner
 * functions purely to save on memory and not for OOP hierarchy.
 *
 * Supported Browsers:
 * IE 5.5+, Mozilla, FireFox
 *
 * Usage Options:
 *
 * Each option is followed by the value for that option.  The variable event
 * must be the first parameter, as shown above.  The options avaiable are:
 *
 *      content or contentId(required)
 *      caption (optional)
 *      formName (optional, the name of the form this tool tip have, if any)
 *      direction (optional, defaults to 'bottom-right', options are:
 *                 'left', 'right', 'padded-left', 'padded-right', 'top',
 *                 'page-center', 'bottom', 'top-left', 'top-right' and 'bottom-left'.
 *      width (optional, the width of the tooltip, if desired, else auto adjusts to
 *             a maximum of 300px, based on maxWidthFixed value)
 *      maxWidthFixed (optional, ignored if width set, else if set to true max width
 *                     is 300px, else it it auto adjusts on content)
 *      height (optional, the height of the tooltip, if desired, else auto adjusts)
 *      style (optional, the CSS style prefix to use for the tooltip, default is 'tt')
 *      trail (optional, follow the mouse cursor while tooltip is active, defaults to true)
 *      type (optional, defaults to 'greasy' other options is 'sticky')
 *      closeLink (optional, the Text/Image to be used for close cell, default is 'X')
 *      closeOnClick (optional, boolean flag to determine if tooltip is  to be closed
 *                    on clicking anywhere on the body, default is true)
 *      doOnClose(optional, string that represents the JS method to be executed before Close)
 *      doOnLoad(optional, string that represents the JS method to be executed before Load)
 *      blankPage (optional, the path of the blank image, IE5.5 Hack for HTTPS
 *
 **/


/**
 * Global constants (DO NOT EDIT)
 */

// -- Browsers --
var ua = navigator.userAgent.toLowerCase();
var isMac = navigator.appVersion.indexOf('Mac') != -1 ? 1 : 0;

var isIE = ua.indexOf('msie 5') != -1 || ua.indexOf('msie 6') != -1 || ua.indexOf('msie 7') != -1;
var isIE50 = isIE && ua.indexOf('msie 5.0') != -1;
var isIE55 = isIE && ua.indexOf('msie 5.5') != -1;
var isIE5 = isIE50 || isIE55;

var isGecko = ua.indexOf('gecko/') != -1 ? 1 : 0;
var isMacIE = (isIE && isMac);
var isIE55up = isIE && !isIE50 && !isMacIE;

// -- Abilities --
var isCSS1Mode = (document.compatMode && document.compatMode == 'CSS1Compat');
var isUsable = (isIE55up || isGecko || isMacIE);
var ttCanTimeout = !(isIE55up || isMacIE);

// -- Event Variables --
var ttEvtTo = isIE ? 'toElement' : 'relatedTarget';
var ttPointerStyle = isIE ? 'hand' : 'pointer';
var ttEvtBut = isIE ? 'button' : 'which';

var ttAutoIdCount = 1;
var ttZIndex = 100;
var ttTimeOutCount = 0;
var ttTimeOutStates = new Map();
var UNDEF = 'undefined';

/**************** Mouse PositionMethods *******************/
function getEventPos(evtObj) {
    var evtPos = new Map('x', 0, 'y', 0, 'scroll_x', 0, 'scroll_y', 0, 'size_x', 0, 'size_y', 0);

    // IE varies depending on standard compliance mode
    if (isIE) {
        var doc = (isCSS1Mode ? document.documentElement : document.body);
        if (doc) {
            evtPos.set('x', evtObj.clientX + doc.scrollLeft);
            evtPos.set('y', evtObj.clientY + doc.scrollTop);
            evtPos.set('scroll_x', doc.scrollLeft);
            evtPos.set('scroll_y', doc.scrollTop);
            evtPos.set('size_x', doc.offsetWidth);
            evtPos.set('size_y', doc.offsetHeight);
        }
    } else {
        evtPos.set('x', evtObj.pageX);
        evtPos.set('y', evtObj.pageY);
        evtPos.set('scroll_x', evtObj.pageX - evtObj.clientX);
        evtPos.set('scroll_y', evtObj.pageY - evtObj.clientY);
        evtPos.set('size_x', window.innerWidth);
        evtPos.set('size_y', window.innerHeight);
    }
    return evtPos;
}


/**************** Helper Methods ***********************/
function ttClone(inObj) {
    var copy = {};
    for (var i in inObj) {
        var value = inObj[i];
        try {
            if (value != null && typeof(value) == 'object' && value != window && !value.nodeType) {
                copy[i] = ttClone(value);
            } else {
                copy[i] = value;
            }
        } catch(e) {
            copy[i] = value;
        }
    }
    return copy;
}

function isDescOf(inObj, inAncestor) {
    if (inObj == inAncestor)         {
        return true;
    }
    while (inObj != document.documentElement) {
        try {
            if ((tempObj = inObj.offsetParen) && tempObj == inAncestor) {
                return true;
            } else if ((tempObj = inObj.parentNode) == inAncestor) {
                return true;
            } else {
                inObj = tempObj;
            }
        } catch(e) {
            return false;
        }
    }
    return false;
}

function ttDetColl(inObj) {
    if (!isIE) {
        return;
    }

    if (isIE && inObj) {
        var frameId = "frame_"+ inObj.id;
        var frameObj = document.getElementById(frameId);
        if (frameObj) {
            frameObj.style.left = inObj.style.left;
            frameObj.style.top = inObj.style.top;
            frameObj.style.width = inObj.offsetWidth;
            frameObj.style.height = inObj.offsetHeight;
            frameObj.style.zIndex = inObj.style.zIndex - 1;
            frameObj.style.visibility = "visible";
            frameObj.style.display = "block";
            frameObj.style.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
        }
    }
}

function ttgetOffSets(inObj) {
    var origObj = inObj;
    var origWidth = inObj.offsetWidth;
    var origHeight = inObj.offsetHeight;
    var offsetLeft = 0;
    var offsetTop = 0;

    while (inObj) {
        offsetLeft += inObj.offsetLeft;
        offsetTop += inObj.offsetTop;
        inObj = inObj.offsetParent;
    }

    if (isMacIE) {
        offsetLeft += 10;
        offsetTop += 10;
    }

    return new Map(
        'left', offsetLeft,
        'top', offsetTop,
        'right', offsetLeft + origWidth,
        'bottom', offsetTop + origHeight,
        'leftCenter', offsetLeft + origWidth/2,
        'topCenter', offsetTop + origHeight/2,
        'radius', Math.max(origWidth, origHeight)
    );
}

function ttSetTimeout(inFn, inTimeOut, inArgs) {
    if (typeof(inArgs) == UNDEF) {
        inArgs = [];
    }

    if (inTimeOut < 0) {
        return;
    } else if (inTimeOut == 0) {
        inFn(inArgs);
        return 0;
    }


    var args = ttClone(inArgs);

    if (ttCanTimeout) {
        return setTimeout(
            function() {
                inFn(args);
            },
            inTimeOut
        );
    } else {
        var id = ttTimeOutCount++;
        var data = new Map();
        data.set('function', inFn);
        data.set('args', args);
        ttTimeOutStates.set(id, data);
        data.set('timeoutId', setTimeout('ttTimeOutStates.get(' + id + ').get(\'function\')(ttTimeOutStates.get(' + id + ').get(\'args\')); ttTimeOutStates.remove(' + id + ');', inTimeOut));
        return id;
    }
}


function ttTimeOutClear(inId) {
    if (ttCanTimeout) {
        clearTimeout(inId);
    } else {
        if (ttTimeOutStates.contains(inId)) {
            clearTimeout(ttTimeOutStates.get(inId).get('timeoutId'))
            ttTimeOutStates.remove(inId);
        }
    }
}


/**************** Tool Tip Related Methods ***********************/

/**
 * Global constants (DO NOT EDIT)
 */
var tooltips = new Map();

/**
 * Global Constants (editable)
 */
var _XOffSet = 0;
var _YOffSet = 2;
var _XPad = 25;
var _Ypad = 25;
var _ttMouseHeight = 20;
var _ttScrEdgePad = 2;
var _ttDelay = 250;
var _ttMaxWidth = 300;
var _class_caption_suffix = 'Caption';
var _class_content_suffix = 'Content';

if (isUsable) {
    var ttMousePos = new Map();
    document.onmousemove = function(inEvt) {
        if (typeof(inEvt) == UNDEF) {
            inEvt = event;
        }
        ttMousePos = getEventPos(inEvt);
        if (ttMouseDragDown) {
            ttUpdateDrag(inEvt);
        }
    }
}

function ttActivate(inThis, inEvt) {

    if (!isUsable) {
        return false;
    }

    if (typeof(inEvt) == UNDEF) {
        inEvt = window.event;
    }

    var owner = document.body;

    if (inEvt.type.match(/key|mouse|click|contextmenu/i)) {
        if (inThis.nodeType && inThis.nodeType != document.DOCUMENT_NODE) {
            var owner = inThis;
        }
    } else if (typeof(inThis) != 'object' && !(owner = tooltips.get(inThis))) {
          owner = document.body.appendChild(document.createElement('div'));
          owner.style.display = 'none';
          owner.id = inThis;
    }

    if (!owner.id) {
        owner.id = '_idCount' + ttAutoIdCount++;
    }

    var tooltip = tooltips.get(owner.id);
    if (tooltip) {
        if (tooltip.get('eventType') != inEvt.type) {
            if (tooltip.get('type') == 'greasy') {
                ttHide(owner.id);
            } else if (tooltip.get('status') != 'inactive') {
                if (tooltip.get('direction') == 'page-center') {
                    tooltip.set('status', 'pending');
                    tooltip.set('_actTimeOut', ttSetTimeout(ttRunShow, tooltip.get('delay'), [owner.id, inEvt]));
                }
                tipObj = tooltip.get('node');
                if (tipObj && ((tooltip.get('type') == 'sticky' && inEvt.type == 'click') || tooltip.get('type') == 'greasy')) {
                    ttBringInfront(tipObj);
                }
                return owner.id;
            }
        } else {
            if (tooltip.get('status') == 'inactive' || tooltip.get('direction') == 'page-center') {
                tooltip.set('status', 'pending');
                tooltip.set('_actTimeOut', ttSetTimeout(ttRunShow, tooltip.get('delay'), [owner.id, inEvt]));
            }
            tipObj = tooltip.get('node');
            if (tipObj && ((tooltip.get('type') == 'sticky' && inEvt.type == 'click') || tooltip.get('type') == 'greasy')) {
                ttBringInfront(tipObj);
            }
            return owner.id;
        }
    }

    // load defaults
    var options = new Map(
        'caption', '',
        'content','',
        'contentId','',
        'direction', 'bottom-right',
        'maxWidthFixed', true,
        'type', 'greasy',
        'closeOnClick', true,
        'delay', _ttDelay,
        'trail', true,
        'closeLink', '&nbsp;X&nbsp;',
        'style','tt'
    );

    // load in the options from the function call
    for (var i = 2; i < arguments.length; i += 2) {
        options.set(arguments[i], arguments[i + 1]);
    }

    options.set('eventType', inEvt.type);

    if ((!options.contains('content') || options.get('content')== '' || options.get('content')== null) &&
        (!options.contains('contentId') || options.get('contentId') == '' || options.get('contentId')== null)) {
        if (typeof(owner.onmouseout) != 'function') {
            owner.onmouseout = function(inEvt) {
                ttOnMouseOut(this, inEvt);
            };
        }
        if (typeof(owner.onmousewheel) != 'function') {
            owner.onmousewheel = function(inEvt) {
                ttOnMouseWheel(this, inEvt);
            };
        }
        return owner.id;
    }

    options.set('owner', owner);
    options.set('id', '[rcTT]' + owner.id);

    try {
        ttCreate(options);
    } catch (e) {
        alert(e);
    }

    options.set('delay', inEvt.type.match(/click|mousedown|contextmenu/i) ? 0 : parseInt(options.get('delay')));
    tooltips.set(owner.id, options);
    options.set('status', 'pending');
    options.set('_actTimeOut', ttSetTimeout(ttRunShow, options.get('delay'), [owner.id, inEvt]));
    return owner.id;
}



function ttCreate(inOptions) {
    var tipOwner = inOptions.get('owner');
    var parentObj = document.body;
    var parentDoc = parentObj.ownerDocument || parentObj.document;

    // create the tooltip and hide it
    var tipObj = parentObj.appendChild(parentDoc.createElement('div'));
    tipObj.style.position = 'absolute';
    tipObj.style.left = '0px';
    tipObj.style.top = '0px';
    tipObj.style.visibility = 'hidden';
    tipObj.id = inOptions.get('id');
    tipObj.className = inOptions.get('style');

    // content of tip as object
    var content;

    if (inOptions.get('caption') || (inOptions.get('type') == 'sticky' && inOptions.get('caption') !== false)) {
        var tipLayoutTable = tipObj.appendChild(parentDoc.createElement('table'));
        tipLayoutTable.style.borderCollapse = 'collapse';
        var tipLayoutTbody = tipLayoutTable.appendChild(parentDoc.createElement('tbody'));
        var numCaptionCells = 1;
        var captionRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr'));
        var captionCell = captionRow.appendChild(parentDoc.createElement('td'));
        captionCell.style.padding = '0px';
        var caption = captionCell.appendChild(parentDoc.createElement('div'));
        caption.className = inOptions.get('style') + _class_caption_suffix;
        caption.style.borderRightWidth = '0px';
        caption.style.paddingRight = '0px';
        caption.style.marginRight = '0px';
        caption.style.paddingLeft = '2px';
        caption.style.height = '100%';

        if (inOptions.get('caption').nodeType) {
            caption.appendChild((unescape(inOptions.get('caption'))).cloneNode(1));
        } else {
            caption.innerHTML = unescape(inOptions.get('caption'));
        }

        if (inOptions.get('type') == 'sticky') {
            var numCaptionCells = 2;
            var closeLinkCell = captionRow.appendChild(parentDoc.createElement('td'));
            closeLinkCell.style.padding = '0px';
            var closeLink = closeLinkCell.appendChild(parentDoc.createElement('div'));
            closeLink.className = inOptions.get('style') + _class_caption_suffix;
            closeLink.style.textAlign = 'right';
            closeLink.style.align = 'middle';
            closeLink.style.cursor = ttPointerStyle;
            closeLink.style.borderLeftWidth = '0px';
            closeLink.style.paddingLeft = '0px';
            closeLink.style.marginLeft = '0px';
            closeLink.style.paddingRight = '1px';
            if (!isIE) {
                closeLink.style.paddingTop = '1px';
            } else {
                closeLink.style.paddingTop = '0px';
            }
            if (inOptions.get('closeLink').nodeType) {
                closeLink.appendChild(inOptions.get('closeLink').cloneNode(1));
            } else {
                closeLink.innerHTML = inOptions.get('closeLink');
            }
            closeLink.onclick = function() {
                var onCloseAct = inOptions.get('doOnClose');
                if (onCloseAct && onCloseAct != '' && typeof(onCloseAct) != UNDEF) {
                    eval(onCloseAct); // should not be a blocking close
                }
                closeLink.style.cursor = '';
                ttHide(tipOwner.id);
            };
            closeLink.onmousedown = function(inEvt) {
                if (typeof(inEvt) == UNDEF) {
                    inEvt = event;
                }
                inEvt.cancelBubble = true;
            };
            if (isMacIE) {
                closeLinkCell.appendChild(parentDoc.createTextNode("\n"));
            }
        }
        if (isMacIE) {
            captionCell.appendChild(parentDoc.createTextNode("\n"));
        }


        var contentRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr'));
        var contentCell = contentRow.appendChild(parentDoc.createElement('td'));
        contentCell.style.padding = '0px';
        contentCell.style.height = '100%';
        if (numCaptionCells) {
            if (isIE) {
                contentCell.colSpan = numCaptionCells;
            } else {
                contentCell.setAttribute('colspan', numCaptionCells);
            }
        }

        content = contentCell.appendChild(parentDoc.createElement('div'));
        content.style.height = '100%';
    } else {
        content = tipObj.appendChild(parentDoc.createElement('div'));
    }

    content.className = inOptions.get('style') + _class_content_suffix;

    if (inOptions.contains('contentId') && inOptions.get('contentId') != '' && inOptions.get('contentId') != null) {
        var oId = inOptions.get('contentId');
        var cId = isIE ? parentDoc.all(oId): parentDoc.getElementById(oId);
        if (cId.nodeType) {
            var formName = inOptions.get('formName');
            if (formName && formName != '' && typeof(formName) != UNDEF) {
                var ttForm = parentDoc.createElement('form');
                ttForm.setAttribute('name', formName);
                ttForm.appendChild(cId.cloneNode(1));
                content.appendChild(ttForm);
            } else {
                content.appendChild(cId.cloneNode(1));
            }
        } else {
            content.innerHTML = cId;
        }
    } else {
        if (inOptions.get('content').nodeType) {
            content.appendChild(unescape(inOptions.get('content')).cloneNode(1));
        } else {
            content.innerHTML = unescape(inOptions.get('content'));
        }
    }

    if (inOptions.contains('height')) {
        tipObj.style.height = parseInt(inOptions.get('height')) + 'px';
    }


    if (inOptions.get('maxWidthFixed')) {
        if (tipObj.offsetWidth > _ttMaxWidth) {
            tipObj.style.width = _ttMaxWidth + 'px';
        }
    }

    if (inOptions.contains('width')) { // maxWidthIgnored if width was fixed
        tipObj.style.width = parseInt(inOptions.get('width')) + 'px';
    }

    var offset_x, offset_y;
    switch (inOptions.get('direction')) {
        case 'page-center': //special case, absolute position to page. will be defined later.
            offset_x = (0 - tipObj.offsetWidth)/2;
            offset_y = (0 - tipObj.offsetHeight)/2;
            break;
        case 'left':
            offset_x = 0 - tipObj.offsetWidth - _XOffSet;
            offset_y = (0 - tipObj.offsetHeight + _ttMouseHeight) /2;
            break;
        case 'right':
            offset_x = _XOffSet;
            offset_y = (0 - tipObj.offsetHeight + _ttMouseHeight) /2;
            break;
        case 'padded-left':
            offset_x = 0 - tipObj.offsetWidth - _XOffSet - _Xpad;
            offset_y = (0 - tipObj.offsetHeight + _ttMouseHeight) /2;
            break;
        case 'padded-right':
            offset_x = _XOffSet + _XPad;
            offset_y = (0 - tipObj.offsetHeight + _ttMouseHeight) /2;
            break;
        case 'bottom':
            offset_x = (0 - tipObj.offsetWidth)/2;
            offset_y = _ttMouseHeight + _YOffSet;
            break;
        case 'top':
            offset_x = (0 - tipObj.offsetWidth)/2;
            offset_y = 0 - tipObj.offsetHeight - _YOffSet;
            break;
        case 'top-left':
            offset_x = 0 - tipObj.offsetWidth - _XOffSet;
            offset_y = 0 - tipObj.offsetHeight - _YOffSet;
            break;
        case 'top-right':
            offset_x = _XOffSet;
            offset_y = 0 - tipObj.offsetHeight - _YOffSet;
            break;
        case 'bottom-left':
            offset_x = 0 - tipObj.offsetWidth - _XOffSet;
            offset_y = _ttMouseHeight + _YOffSet;
            break;
        case 'bottom-right':
             default:
            offset_x = _XOffSet;
            offset_y = _ttMouseHeight + _YOffSet;
            break;
    }

    inOptions.set('offsetX', offset_x);
    inOptions.set('offsetY', offset_y);
    inOptions.set('offsetWidth', tipObj.offsetWidth);
    inOptions.set('offsetHeight', tipObj.offsetHeight);

    if (isIE && tipObj) {
        var parentObj = document.body;
        var parentDoc = parentObj.ownerDocument;
        var frameId = "frame_"+ inOptions.get('id');
        var frameObj = document.getElementById(frameId);
        if (!frameObj) {
            if (isIE5) {
                if (inOptions.get('blankPage')) {
                    parentObj.insertAdjacentHTML("beforeEnd", "<iframe id='" + frameId + "' src='" + inOptions.get('blankPage') +"' scrolling='no' frameBorder='0' style='left: 0px; position: absolute; top: 0px'></iframe>");
                } // else let the layering issue on IE exist
            } else {
                parentObj.insertAdjacentHTML("beforeEnd", "<iframe id='" + frameId + "' src='javascript:false;' scrolling='no' frameBorder='0' style='left: 0px; position: absolute; top: 0px'></iframe>");
            }
        }

        frameObj = document.getElementById(frameId);
        if (frameObj) {
            frameObj.style.left = tipObj.style.left;
            frameObj.style.top = tipObj.style.top;
            frameObj.style.visibility = "hidden";
            frameObj.style.display = "none";
            frameObj.style.width = tipObj.offsetWidth;
            frameObj.style.height = tipObj.offsetHeight;
            frameObj.style.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)';
        }
    }
    if (inOptions.get('trail') && typeof(tipOwner.onmousemove) != 'function') {
        tipOwner.onmousemove = function(inEvt) {
            ttOnMouseMove(this, inEvt);
        };
    }

    if (typeof(tipOwner.onmouseout) != 'function') {
        tipOwner.onmouseout = function(inEvt) {
            ttOnMouseOut(this, inEvt);
        };
    }

    if (typeof(tipOwner.onmousewheel) != 'function') {
        tipOwner.onmousewheel = function(inEvt) {
            ttOnMouseWheel(this, inEvt);
        };
    }


    if (inOptions.get('type') == 'sticky') {
        if (isIE) {
            captionRow.onselectstart = function() {
                return false;
            };
        }

        captionRow.onmousedown = function(inEvt) {
            ttStartDrag(tipObj, inEvt);
        };
        captionRow.onmousemove = function(inEvt) {
            ttUpdateDrag(inEvt);
        };
        captionRow.onmouseup = function() {
            ttStopDrag();
        };
        contentRow.onmousedown = function(inEvt) {
            ttBringInfront(tipObj);
        };

        if (inOptions.get('closeOnClick')) {
            contentRow.onclick = function() {
                closeLink.style.cursor = '';
                ttHide(tipOwner.id);
            };
        } else {
            contentRow.onclick = function() {
                ttBringInfront(tipObj);
            };
            if (isIE) {
                contentRow.onkeydown = function() {
                    ttRefresh(tipObj);
                }
            }
        }
    }
    inOptions.set('node', tipObj);
    inOptions.set('status', 'inactive');
}

function ttShow(inOwnerId, inEvt) {
    var tooltip = tooltips.get(inOwnerId);
    var status = tooltip.get('status');
    var tipObj = tooltip.get('node');
    var mouse_x, mouse_y;

    if (tooltip.contains('x') && tooltip.contains('y')) {
        mouse_x = tooltip.get('x');
        mouse_y = tooltip.get('y');
    } else if (tooltip.get('direction') == 'page-center') {
        var evtPos = getEventPos(inEvt);
        mouse_x = evtPos.get('scroll_x') + evtPos.get('size_x')/2;
        mouse_y = evtPos.get('scroll_y') + evtPos.get('size_y')/2;
    } else if (status == 'active' || tooltip.get('delay') == 0) {
        var evtPos = getEventPos(inEvt);
        mouse_x = evtPos.get('x');
        mouse_y = evtPos.get('y');
    } else {
        mouse_x = ttMousePos.get('x');
        mouse_y = ttMousePos.get('y');
    }

    var coordinates = {
        'x' : mouse_x + tooltip.get('offsetX'),
        'y' : mouse_y + tooltip.get('offsetY')
    };

    coordinates = ttFixEdgeCutOff(tooltip.get('offsetWidth'), tooltip.get('offsetHeight'), coordinates.x, coordinates.y, _XOffSet, _YOffSet, tooltip.get('type'), window);
    tipObj.style.left = coordinates.x + 'px';
    tipObj.style.top = coordinates.y + 'px';

    tipObj.style.zIndex = ttZIndex++;
    if (status == 'pending') {
        var onLoadAct = tooltip.get('doOnLoad');
        if (onLoadAct && onLoadAct != '' && typeof(onLoadAct) != UNDEF) {
            eval(onLoadAct); // should not be a blocking load
        }
        tooltip.set('status', 'active');
        tipObj.style.display = '';
        tipObj.style.visibility = 'visible';
    }
    ttDetColl(tipObj);
}

function ttHide(inOwnerId) {
    var tooltip = tooltips.get(inOwnerId);
    if (tooltip) {
        var status = tooltip.get('status');
        if (status == 'pending') {
            ttTimeOutClear(tooltip.get('_actTimeOut'));
            tooltip.set('status', 'inactive');
        } else if (status == 'active') {
            var tipObj = tooltip.get('node');
            tipObj.style.display = 'none';
            var parentObj = document.body.removeChild(tipObj);
            tooltips.remove(inOwnerId);
            tooltip.set('status', 'inactive');
            ttDetColl(tipObj);
        }
    }
}


function ttOnMouseOut(inOwner, inEvt) {
    if (!isUsable) {
        return false;
    }
    if (typeof(inEvt) == UNDEF) {
        inEvt = event;
    }
    var toChild = isDescOf(inEvt[ttEvtTo], inOwner);
    var tooltip = tooltips.get(inOwner.id);
    if (tooltip && (tooltip.get('type') == 'greasy' || tooltip.get('status') != 'active')) {
        if (!toChild) {
            ttHide(inOwner.id);
            try {
                window.status = window.defaultStatus;
            } catch(e) {
            }
        }
    } else if (!toChild) {
        try {
            window.status = window.defaultStatus;
        } catch(e) {
        }
    }
}

function ttOnMouseMove(inOwner, inEvt) {
    if (!isUsable) {
        return false;
    }
    if (typeof(inEvt) == UNDEF) {
        inEvt = event;
    }
    var tooltip = tooltips.get(inOwner.id);
    if (tooltip && tooltip.get('trail') && tooltip.get('status') == 'active' && tooltip.get('type') != 'sticky') {
        ttShow(inOwner.id, inEvt);
    }
}


function ttOnMouseWheel(inOwner, inEvt) {
    ttOnMouseOut(inOwner, inEvt);
}

function ttFixEdgeCutOff(inWidth, inHeight, inX, inY, inXoffSet, inYoffset, inType, inWin) {
    var win = (typeof(inWin) == UNDEF ? window : inWin);
    var doc  = win.document.body;
    if (isCSS1Mode && (isIE || isGecko)) {
        doc = win.document.documentElement;
    }

    var pageHeight = doc.clientHeight;
    var pageWidth = doc.clientWidth;

    var pageYOffset;
    var pageXOffset;
    if (isIE) {
        pageYOffset = doc.scrollTop;
        pageXOffset = doc.scrollLeft;
    } else {
        pageYOffset = win.pageYOffset;
        pageXOffset = win.pageXOffset;
    }

    var rtCutOff = (inX - pageXOffset) + inWidth - (pageWidth - _ttScrEdgePad);
    var bottomCutOff = (inY - pageYOffset) + inHeight - (pageHeight - _ttScrEdgePad);

    // we are cutting off on the right, move tip over to stay on page
    if (rtCutOff > 0) {
        inX -= rtCutOff;
    }

    // we are cutting off on the left, move tip over to stay on page
    if ((inX - pageXOffset) < _ttScrEdgePad) {
        inX = _ttScrEdgePad + pageXOffset;
    }

    if (bottomCutOff > 0) {
        if (inType == 'sticky') {
            inY -= bottomCutOff;
        } else {
            inY -= inHeight + (2 * inYoffset) + _ttMouseHeight;
        }
    }

    if ((inY - pageYOffset) < _ttScrEdgePad) {
        if (inType == 'sticky') {
            inY = _ttScrEdgePad + pageYOffset;
        } else {
            inY += inHeight + (2 * inYoffset) + _ttMouseHeight;
        }
    }

    return {
        'x' : inX,
        'y' : inY
    };
}

// This method is used by the event handling sections to avoid
// the circular memory leaks caused by inner functions

function ttRunShow(args) {
    ttShow(args[0], args[1]);
}

/**************** Drag Related Methods ***********************/

var ttCurrDragTgt;
var ttMouseDragDown;
var ttDragLeftOffSet;
var ttDragTopOffSet;

function ttStartDrag(inThis, inEvt) {
    if (typeof(inEvt) == 'undefined') {
        inEvt = event;
    }

    var evtBut = inEvt[ttEvtBut];
    if (evtBut != 1) {
        return;
    }

    ttCurrDragTgt = inThis;
    inThis.style.cursor = 'move';
    inThis.style.zIndex = ++ttZIndex;
    var evtPos = getEventPos(inEvt);
    var tgtPos = ttgetOffSets(inThis);
    ttDragLeftOffSet = evtPos.get('x') - tgtPos.get('left');
    ttDragTopOffSet = evtPos.get('y') - tgtPos.get('top');
    if (isIE) {
        ttDragWidthOffSet = inThis.offsetWidth;
        ttDragHeightOffSet = inThis.offsetHeight;
    }
    ttMouseDragDown = true;
}


function ttUpdateDrag(inEvt) {
    if (ttMouseDragDown) {
        if (isGecko) {
            window.getSelection().removeAllRanges()
        }
        var evtPos = ttMousePos;
        ttCurrDragTgt.style.left = (evtPos.get('x') - ttDragLeftOffSet) + 'px';
        ttCurrDragTgt.style.top = (evtPos.get('y') - ttDragTopOffSet) + 'px';
        if (isIE) {
            ttCurrDragTgt.style.width = ttDragWidthOffSet + 'px';
            ttCurrDragTgt.style.height = ttDragHeightOffSet + 'px';
        }
        ttDetColl(ttCurrDragTgt);
    }
}

function ttStopDrag() {
    if (ttMouseDragDown) {
        ttMouseDragDown = false;
        ttCurrDragTgt.style.cursor = 'default';
        ttCurrDragTgt = null;
        if (isGecko) {
            window.getSelection().removeAllRanges()
        }
    }
}

function ttBringInfront(inObj) {
    inObj.style.zIndex = ++ttZIndex;
    ttMoveFrameBehind(inObj);
}


function ttMoveFrameBehind(inObj) {
    if (isIE && inObj) {
        var frameId = "frame_"+ inObj.id;
        var frameObj = document.getElementById(frameId);
        if (frameObj) {
            frameObj.style.zIndex = inObj.style.zIndex - 1;
        }
    }
}

function ttRefresh(inObj) {
    inObj.style.zIndex = ++ttZIndex;;
    ttMoveFrameBehind(inObj);
    inObj.style.zIndex = --ttZIndex;;
    ttMoveFrameBehind(inObj);
}

