/// <summary>
/// Creates a Menu
/// </summary>
/// <param name="el">The Menu Element - Generally a UL with class 'c_m'</param>
/// <param name="elSource">This is element the menu is docked relative
/// It also closes the menu if a user shift tabs off of it.
/// If you want the shift tab off the first link to stay open add more stuff to your elSource and peers</param>
/// <param name="loc">int: this will set the location of the menu (see domutils.dodock)</param>
/// <param name="offset">int/point: this will determin how far (in pixels) away the menu is from the source elemnt</param>
/// <param name="alt">bool: uses an alternate layout method, try using this if the menu does not find you element (1 or 0 works too)</param>
/// <param name="nofocus">bool: set to true if you don't want to automatically set focus in the menu</param>
/// <param name="eventType">string name of event ("onclick", "onfocus") that occurs on elSource that will trigger the menu behavior</param>
/// <param name="posabs">optional: point: {x:0,y:0} </param>
function $menu(el,elSource,loc,offset,alt,nofocus,eventType,posabs)
{
    loc = loc||null;
    
    // strings are assigned to variables for better compression once we have run through jscrunch
    var _this = this,
        px = "px",
        visibility = "visibility",
        display = "display",
        hidden = "hidden",
        block = "block",
        visible = "visible",
        cn = "className",
        ns = "nextSibling",
        none = "none",
        okd = "onkeydown",
        oku = "onkeyup",
        blur = "onblur",
        addEvent = $f.addEvent,
        remEvent = $f.removeEvent,
        _linkSrc = null,
        _shft,
        firstLink,
        lastLink,
        allLinks,
        shadowEl,
        frameElement,
        fNeedsDocked = 1,
        _isRecalc,
        isEmpty = 1,
        isOpen,
        es = el.style,
        ie6 = $B.ie == 6,
        ss = {display:0,visibility:0},fs = ss, // create a dummy style object, so it can be used right away
        _selected = 0,  // The # link that is selected (arrow key nav.)
        _selectedEl,
        _linksLength = 0,
        _isElSourceInput, // bool to denote whether the source element is of INPUT type or not
        _inputValue,
        _defaultSelectedEl,
        _focusClassName,
        _defaultSelectedClassName = 'sel';

    this.parentEl = null;
    
    var _state = 
    {
        blurSrc: null,
        lastKeyCode: null,
        isShift: false
    }
    
    function init()
    {
        el.binding = _this;
        
        // attach needed event handling
        addEvent(el,okd,onkeydown);          // Used for the menu itself to close when tabbing off of the last/first element
        addEvent(elSource,okd,onkeydown);    // Determines if the source el is the one blurred from
        addEvent(elSource,blur,onblur);          // Closes the menu if you shift tab off of the source element
        addEvent($f.doc,"onmouseup",doc_onmouseup);  // Closes menu if the document is clicked.
        addEvent($f.doc,"onkeyup",doc_onkeyup);      // Closes menu if the keyup event happens elsewhere on the doc

        // store elSource type
        _isElSourceInput = elSource.tagName == "INPUT";
        _focusClassName = _isElSourceInput ? 'c_dark' : 'c_light';

        // This us used to attach the toggleEvent to the event that did the initial binding; example onfocus or onclick
        window.setTimeout(function(){addEvent(elSource,"on"+eventType,_this.toggleState);},0);

        calcLinks();
        doDock();
        
        es[display] = none;
        
        // during a resize a new docking position is determined.
        addEvent(window, "onresize", onresize);
    }

    function calcLinks()
    {
        // gather all links up on the menu
        allLinks = el.getElementsByTagName("A");
        
        // We have to close the menu if we blur off of the first or last link
        var n = _linksLength = allLinks.length,
            b,
            foundSelected; // defaults to false
            
        if (n > 0)
        {
            if (isEmpty && isOpen)
            {
                internalShowMenu();
            }
            isEmpty = 0;
            
            firstLink = allLinks[0];
            lastLink = allLinks[n - 1];
            addEvent(firstLink, blur, onblur);
            addEvent(lastLink, blur, onblur);
            // provide focus hightlighting when tabbing through menu.
            // only works if the menu matches the common menu pattern: <li><a (elSource)>menu item</a></li>
            // this only happens on init so it's only executed once.
            while (n > 0)
            {
                n--;
                b = false;
                var linkEl = allLinks[n];
                try { b = linkEl.parentNode.tagName == "LI"; } catch (e) { }
                if (b)
                {
                    // this is for a relacl
                    remEvent(linkEl, "onfocus", light);
                    remEvent(linkEl, blur, light);

                    // all events are cleaned up during onunload.
                    addEvent(linkEl, "onfocus", light);
                    addEvent(linkEl, blur, light);

                    if (!_isRecalc && $css.has(linkEl, _defaultSelectedClassName))
                    {
                        _defaultSelectedEl = linkEl;
                    }

                    // Cant actually compare elements since header throws them away so compare id
                    if (_selectedEl && _selectedEl.id == linkEl.id)
                    {
                        foundSelected = 1;
                        setSelection(n);
                    }
                }
            }
        }
        else
        {
            internalHideMenu();
            isEmpty = 1;
        }

        if (!foundSelected && _defaultSelectedEl)
        {
            setSelection(-1);
        }
    }

    this.update = function()
    {
        _isRecalc = true;
        remEvent(firstLink, blur, onblur);
        remEvent(lastLink, blur, onblur);
        calcLinks();
        doDock();
        _isRecalc = false;
    }
    
    // Used to handle the focus/blur events fired from the menu anchor tags for commmon menus
    function light(ev)
    {
        if (!_isElSourceInput)
        {
            ev = ev || event;
            var src = ev.target || ev.srcElement;

            ev.type == "focus" ? $css.add(src, _focusClassName) : $css.remove(src, _focusClassName);
        }
    }
    
    function onresize(ev)
    {
        ev=ev||event||{type:null};
        fNeedsDocked = true;
        // add noresize to the classname to keep the menu open during resize events
        if( !$css.has(el,"noresize") )
        {
            hideMe();
        }
    }

    

// Encapsulates the docking of the menu to it's sourceElement.
    function doDock(ev)
    {
        if (isEmpty)
        {
            return;
        }

        var shadowOffset = 3,
            firstRun = (!shadowEl);

        // I assume that the menu el is display:none and position:absolute
        // We interanHideMenu() if it's supposed to be closed later.
        fs[visibility] = ss[visibility] = es[visibility] = hidden;
        fs[display] = ss[display] = es[display] = block;
    
        // Create the shadow element if it does not exist.    
        if( !shadowEl )
        {
            // fix for Firefox in some cases where the shadow cause the element to move slightly
            shadowEl=el;
            
            while(shadowEl[cn] != "c_shad" && shadowEl[ns]){shadowEl=shadowEl[ns]};
            if( !shadowEl || shadowEl[cn] != "c_shad" )
            {
                shadowEl = document.createElement("div");
                ss = shadowEl.style;
                ss.position = "absolute"; // fix for safari; because it doesn't redraw when appending adding a div;
                shadowEl[cn] = "c_shad";
                el.parentNode.appendChild(shadowEl);
                
                // In IE6 we need an iframe behind the menu element in order to hide any other framed elements.
                // Only fs should be referenced outside this block.
                if( ie6 )
                {
                    // we end up placing the frameElement in the same manner as the shadow element in IE6.
                    frameElement = document.createElement("IFRAME");
                    frameElement.frameBorder = "no";
                    frameElement.src = "javascript:''";
                    frameElement.scrolling = "no";
                    fs = frameElement.style;
                    fs.position = "absolute"; // fix for safari; because it doesn't redraw when appending adding a div;
                    el.parentNode.appendChild(frameElement);
                }
            }
            ss = shadowEl.style; // I have to re-map the style after attaching to the document? 
            ss[display] = none;
            ss.backgroundColor = "#000";
            setOpacity(shadowEl,30);
        }
        
        // deal with the offsets
        var d = $f.dockIt(el,elSource,loc,offset,alt,posabs);
        
        // This fix is in order to slip the time when the calculation is done for the size/position of the menu.
        // This fixes an RTL bug when menus are used: #711136
        var setupShadow = function(){
            var loc2 = $f.getLocation(el);
            
            // set the shadow element width/height/position.
            ss[visibility] = hidden;
            ss.width = loc2.width+px;
            ss.height = loc2.height+px;
            ss.left = (d.x+(rtl ? -shadowOffset : shadowOffset))+px;
            ss.top = (d.y+shadowOffset)+px;
            ss[visibility] = visible;
            
            if( ie6 )
            {
                fs[visibility] = hidden;
                fs.width = (loc2.width+shadowOffset)+px;
                fs.height = (loc2.height+shadowOffset)+px;
                fs.left = (rtl ? (d.x-shadowOffset) : d.x)+px;
                fs.top = d.y+px;
            }
            
        };            
        setupShadow();
        
        // we need this because of some redraw issues in IE6 when the menu has content that is dynamically populated and in RTL markets.
        if(ie6 && firstRun)
        {
            addEvent(el,"onresize",setupShadow);
        }
        
        if (!isOpen)
        {
            // set back the classes
            internalHideMenu();
        }
        else if( _isRecalc )
        {
            // Why is this opening it?
            _this.show();
        }

        fNeedsDocked=false;
    }
    
    function timeHasPassed()
    {
        return (new Date().getTime() - _lastToggle > 100)
    }

    function internalHideMenu()
    {
        // Just CSS changes no state change
        $css.remove(el, "on");
        fs[display] = ss[display] = es[display] = none;
        fs[visibility] = ss[visibility] = es[visibility] = hidden;
    }

    function internalShowMenu()
    {
        // Just CSS changes no state change
        $css.add(el, "on");
        fs[display] = ss[display] = es[display] = block;
        fs[visibility] = ss[visibility] = es[visibility] = visible;
    }

    function hideMe(ev,fForce)
    {
        if(fForce || (timeHasPassed() && isOpen))
        {
            if (!isEmpty)
            {
                internalHideMenu();
            }
            isOpen = 0;
        }
    }
    this.hide = hideMe;

    this.show = function()
    {
        $menu.current = _this;
        if (!isEmpty)
        {
            internalShowMenu();
        }
        isOpen = 1;
    }
    
    var _lastToggle = 0;
    // called to toggle the menu on/off.
    this.toggleState = function()
    {
        // This tick calculation is because of the document.onclick issue, we have to weed out the double call;
        if(timeHasPassed())
        {
            _lastToggle = new Date().getTime();
            if( !isOpen && ( !$f.ie || fNeedsDocked ))
            {
                // This is to fix a bug for the shadow and menu position, when text size is increased in firefox.
                // Work around was to reload the page, this will fix it when re-openning the menu
                // docking is slow in IE and not so slow in FF, we only re-dock onopen in FF 
                doDock();
            }
            (!isOpen || _isElSourceInput) ? _this.show() : hideMe(0,1);
        }
    }
    
    // Close menu if On Mouse Up happens outside Menu and Menu Source Element
    function doc_onmouseup(ev)
    {
        // NOTE: IE: document.onmouseup event is called before the onclick; both events occur;
        // Also the event is not called from the same sourceEl in most cases.
        ev = ev || event;
        var src = ev.target || ev.srcElement;
        
        if (isOpen && !$f.isChildOf(el, src) && elSource != src) // instead of != should we use !isChildOf(elSource, src) or !isChildOf(parent, src)
        {
            _this.hide();
        }
    }
    
    // Close menu if <esc> is pressed
    // if noFocus is false that means that when you click enter on on the elSource to open the menu
    // that we should give focus to the first link
    // if you click with your mouse to open the menu it wont happen.
    // Thats why the focus is here instead of in show()
    // Notice that this is called after show() for this focus behavior.
    function doc_onkeyup(ev)
    {
        ev=ev||event;
        var esc = 27,
        src = ev.target || ev.srcElement;
        if( isOpen )
        {
            if( ev.keyCode == esc )
            {
                // keep track of input value
                _inputValue = src.value;
                _this.hide();
            }
            else if( (!_shft && _linkSrc == elSource) && firstLink && !nofocus )
            {
                try{firstLink.focus()}catch(e){};
            }
        }
        
        // open menu depending on input value
        if (_isElSourceInput && src == elSource)
        {
            if (!isOpen && src.value != _inputValue)
            {
                _this.show();
            }
        }
    }

    // this onkeydown is for all menu elements
    // record <shift> and linkSrc for onblur 
    // This helps us know if you shift tab off the firstLink/elSource or tab off lastLink
    function onkeydown(ev)
    {
        ev = ev||event;
        var src = ev.target || ev.srcElement,
        key = ev.keyCode || ev.which,
        tab = key == 9;
        _shft = ev.shiftKey;
        _linkSrc = src;

        if (_isElSourceInput)
        {
            // only navigate if the source is the input box,
            // we don't want to navigate through the menu if focus is on one of the menu items
            if (src == elSource)
            {
                if (key == 40) //down
                {
                    move(1);
                }
                else if (key == 38) //up
                {
                    move(-1);
                }
                else if (key == 13) //enter
                {
                    if (_selectedEl)
                    {
                        _selectedEl.focus();
                    }
                    else
                    {
                        _defaultSelectedEl.focus();
                    }
                }
                else if (tab && !_shft)
                {
                    // Tab out of Text box into Menu
                    setSelection(0);
                }
            }
            else if (tab)
            {
                if (!_shft)
                {
                    if (_linkSrc != lastLink)
                    {
                        // Tab through Links
                        setSelection(_selected + 1);
                    }
                    else
                    {
                        // Tab out of menu
                        setSelection(-1);
                    }
                } 
                else if (_shft)
                {
                    // Shift Tab through Links (even to Text box)
                    setSelection(_selected - 1);
                } 
            }
        }
    }

    // direction is 1 when moving down, -1 when moving up
    // For Arrow wrapping
    function move(direction)
    {
        // make sure we have links to work with
        if (_linksLength)
        {   
            var newSelection = _selected + direction;

            if (newSelection >= _linksLength)
            {
                newSelection = 0;
            }
            else if (newSelection < 0)
            {
                newSelection = _linksLength - 1;
            }

            setSelection(newSelection);
        }
    }

    // set selection and clear old one
    // -1 = Go to Default Selection
    function setSelection(newSelection)
    {
        if (_linksLength)
        {
            // clear old selection
            if (_selectedEl)
            {
                $css.remove(_selectedEl, _focusClassName);
            }

            _selected = newSelection;
            
            if (_selected > -1)
            {
                _selectedEl = allLinks[_selected];
                $css.add(_selectedEl, _focusClassName);
                if (_defaultSelectedEl != _selectedEl)
                {
                    $css.remove(_defaultSelectedEl, _defaultSelectedClassName);
                }
            }
            else
            {
                _selectedEl = null;
                $css.add(_defaultSelectedEl, _defaultSelectedClassName);
            }
        }
    }

    // Close if <shift>+<tab> off elSource
    // Close if <tab> off last link
    // Close if <shift>+<tab> off first link
    // <shift> and linkSrc is known from onkeydown
    function onblur(ev)
    {
        if (_shft && _linkSrc == elSource)
        {
            _this.hide();
        }
        else if (!isEmpty && ((!_shft && _linkSrc == lastLink) || (_shft && _linkSrc == firstLink)))
        {
            _this.hide();
        }
    }

    function setOpacity(el,value)
    {
        // Determine what opacity value to set.
        var s = ("undefined" == typeof el.style.filter) ? "opacity" : "filter";

        // update style with new value;
        el.style[s] = (s == "filter" ? "alpha(opacity="+value+")" : (0.01 * value));
    }
    
    init();
}

/// <summary>
/// Allows a public interface to close the currently openned menu.
/// </summary>
$menu.closeCurrent = function()
{
    if( $menu.current )
    {
        $menu.current.hide(0,1);
    }
}
$menu.current = null;


/// <summary>
/// Creates a binding and docks a menu element to a link or source element
/// </summary>
/// <param name="ev">event pass the event (window.event)</param>
/// <param name="loc">int: this will set the location of the menu (see domutils.dodock)</param>
/// <param name="offset">int: this will determin how far (in pixels) away the menu is from the source elemnt</param>
/// <param name="alt">bool: uses an alternate layout method, try using this if the menu does not find you element (1 or 0 works too)</param>
/// <param name="nofocus">bool: set to true if you don't want to automatically set focus in the menu</param>
$menu.bind = function(ev,loc,offset,alt,nofocus,posabs)
{
    // Requirements: Use the class selectors c_ml, c_mcp, c_m as follows
    // c_ml     (menu link) is set on the menu link 
    //          Recommended usage: onclick="try{$menu.bind(event);}catch(e){}return false;"
    // c_mcp    (common menu parent) set this on the common parent of the link/menu.
    // c_m      set this on the menu element, 
    //          ensure that position:absolute and display:none and that the menu is a direct child of c_mcp;
    // The menu will auto-wire itself if the above rules are followed
    
    // docking (loc) uses the domutils.dodock function which is speced as such:
    // 0 : Bottom,Left
    // 1 : Bottom, Right
    // 2 : Top,Left
    // 3 : Top,Right
    // 4 : Left,Top
    // 5 : Left,Bottom
    // 6 : Right,Top
    // 7 : Right,Bottom
    
    ev = ev||event;
    var src = ev.target||ev.srcElement,
        ac = ["c_ml","c_mcp","c_m"],
        parentEl,sourceEl,menuEl,
        el = src;
        

    // Find/Ensure class="c_ml";
    if( (sourceEl = pn(el,ac[0])) && typeof sourceEl.menu === "undefined")
    {
        parentEl = pn(el,ac[1]) || sourceEl.parentNode;
        if( parentEl )
        {
            // this is for an IE6 fix where the li does not auto-size correct when a sub menu is present.
            if( navigator.appVersion.indexOf("MSIE 6")>-1 && parentEl.tagName == "LI" && $css.has(parentEl.parentNode,"c_m") )
            {
                parentEl.style.width = parentEl.offsetWidth+"px";
            }
            var children = parentEl.childNodes;
            var i = children.length;
            while(i-- && !menuEl)
            {
                menuEl = $css.has(children[i],ac[2])?children[i]:null;
            }
            makeBind();
        }
    }
    
    function makeBind()
    {
        var r = false;
        if( menuEl.binding )
        {
            menuEl.binding.toggleState();
        }
        else if( menuEl && sourceEl )
        {
            menuEl.binding = new $menu(menuEl,sourceEl,loc,offset,alt,nofocus,ev.type,posabs);
            menuEl.binding.toggleState();
            sourceEl.menu = menuEl.binding;
            r = true;
        }
        return r;
    }

    function pn(el,cn)
    {
        var f = $css.has(el,cn);
        var r = (f ? el : null);
        while(!r && (el = el.parentNode) && (typeof el != "undefined") )
        {   
            if( $css.has(el,cn))
            {
                r = el;
            }
        }
        return r;
    }
    
    return false;
}


$css =
{
    /// <summary>
    /// Returns a bool if the class Name exists on the element
    /// <summary>
    /// <param name="el">element to check class name on</param>
    /// <param name="className">Class name to check for</param>
    has: function(el, className) {
        var r = false;
        try {
            // Checks for the className as a word
            r = new RegExp("\\b" + className + "\\b", "i").test(el.className);
        }
        catch (ex) { }
        return r
    },

    /// <summary>
    /// Removes className from an element
    /// <summary>
    /// <param name="el">element to change class name on</param>
    /// <param name="className">Existing Class name to remove</param>
    remove: function(el, className) {
        $css.swap(el, className)
    },

    /// <summary>
    /// Swaps className for newClassName on an element
    /// <summary>
    /// <param name="el">element to change class name on</param>
    /// <param name="className">Existing Class name to remove</param>
    /// <param name="newClassName">Class Name to add</param>
    swap: function(el, className, newClassName) {
        newClassName = newClassName || '';

        if (el && el.className) {
            // First replace swaps class name
            // Second replace removes 2 spaces in a row for a single space
            el.className = el.className.replace(new RegExp("\\b" + className + "\\b", "i"), newClassName).replace(/^\s|\s(\s)|\s$/g, "$1");
        }
    },

    /// <summary>
    /// Adds className to an element
    /// <summary>
    /// <param name="el">element to change class name on</param>
    /// <param name="className">Class Name to add</param>
    add: function(el, className) {
        if (el) {
            if (el.className) {
                if (!$css.has(el, className)) {
                    el.className += " " + className;
                }
            }
            else {
                el.className = className;
            }
        }
    }
}


function $(s) {
    return (s == null || (typeof s == "object" && !(s instanceof String))) ? s : document.getElementById(s);
}

function $f() {
    // Rename to match framework.
    var w = $f.w = window,
        doc = $f.doc = document,
        ie = $f.ie = w.ActiveXObject ? 1 : 0, // opera returns "0" (intended)
        eventStack = [];

    // This will set the rtl value based on the document.classname 
    // We set the real value in the domutils.js because we don't want to take a dependency on domutils here for size reasons
    w.rtl = document.body.className.indexOf("rtl") > -1;

    if ("undefined" != typeof $Browser) {
        $Browser.isIE = function() { return ie; }
    }

    // TODO: Wrap addevent to send correct element browser agnostic
    $f.addEvent = function(obj, sEventType, func) {
        ie ? obj.attachEvent(sEventType, func)
           : obj.addEventListener(sEventType.substr(2), func, false);

        eventStack.push({ target: obj, event: sEventType, func: func });
    }

    $f.removAllEvents = function() {
        var o, i = eventStack.length;
        while (i--) {
            o = eventStack[i];
            removeEvent(o.target, o.event, o.func)
        }
    }

    $f.removeEvent = function(obj, sEventType, func) {
        sEventType = (!ie ? sEventType.substr(2) : sEventType);
        var o, i = eventStack.length;
        while (i--) {
            o = eventStack[i];

            if (o.target == obj && o.event == sEventType && o.func == func) {
                removeEvent(o.target, o.event, o.func);
                eventStack.splice(i, 1);
                break;
            }
        }
    }

    $f.cancelEvent = function(e) {
        e = e || window.event;
        e.cancelBubble = true;

        if (e.stopPropagation) {
            e.preventDefault();
            e.stopPropagation();
        }
        else {
            e.returnValue = false;
        }
        return false;
    }

    function removeEvent(obj, sEventType, func) {
        ie
         ? obj.detachEvent(sEventType, func)
         : obj.removeEventListener(sEventType, func, false);
    }

    $f.px = function(s) {
        return s + "px";
    }

}
$f();

$f.addEvent($f.w, "onunload", $f.removAllEvents);








// To read Browser Sense classes
// This is important for things like the header drop down menu where they need to change style
// based on browser like our CSS does.
// If your javascript is not doing visual things it should not use $B to figure out if the browser
// has the ability it should check for the function before calling it.
// Depends on css.js for $css.has()
// Depends on body tag having CSS ClassNames
new function() {
    // Only do this once.
    if ("undefined" != typeof $B) {
        return;
    }
    window['$B'] = {};

    var body = document.body,
        cssHas = $css.has;

    if (cssHas(body, 'IE')) {
        // One old technique :
        // ie = $f.ie = w.ActiveXObject ? 1 : 0, // opera returns "0" (intended)

        // old version technique:
        // this one has bugs due to some toolbars
        // ie6 = (navigator.appVersion.indexOf("MSIE 6")>-1)

        // old version technique: (from browser.js in gadgetframework
        // $Browser.version = parseFloat(_appVersion.substr(_appVersion.indexOf("MSIE") + 5, 3));

        // old technique from compat.js
        // var _isSafari = (navigator.userAgent.indexOf("WebKit")>=0);
        // var _isOpera = window.opera != null;
        // var _isMozilla = (navigator.userAgent.indexOf("Mozilla") >= 0) && (!_isOpera) && (!_isSafari);

        // BUGBUG: If no way to determine IE8 in IE7 mode vs IE8 vs IE7
        if (cssHas(body, 'IE_M8')) {
            $B.ie = 8;
        }
        else if (cssHas(body, 'IE_M7')) {
            $B.ie = 7;
        }
        else {
            // Treat 6 and below the same;
            $B.ie = 6;
        }
    }
    else if (cssHas(body, 'Firefox')) {
        if (cssHas(body, 'FF_M3')) {
            $B.ff = 3;
        }
        else {
            // Treat 2 and below as same;
            $B.ff = 2;
        }
    }
    else if (cssHas(body, 'Safari')) {
        // Treat 3 and below as same;
        $B.sf = 3;

        if (cssHas(body, 'SF_iPhone')) {
            $B.ip = 1;
        }
    }

    // one old technique
    // window.rtl = document.body.className.indexOf("rtl") > -1;

    // another old techinques
    // window.rtl = $f.getStyle(document.body, "direction") == "rtl";

    $B.rtl = cssHas(body, 'rtl');
}

// Requires baseutils.js

$f.dockIt = function(sourceElement, targetElement, dockLocation, offset, alt, posabs) {

    //
    // This is a mini dock function that deals with 8 positions
    // The dockLocation is the side of the targetElement that you would like to doc with.
    // The sourceElement is lined up using it's oposite side.
    // dockLocation: send 0 - 7 as follows
    // 0 : Bottom,Left
    // 1 : Bottom, Right
    // 2 : Top,Left
    // 3 : Top,Right
    // 4 : Left,Top
    // 5 : Left,Bottom
    // 6 : Right,Top
    // 7 : Right,Bottom
    //

    var dist = 0;

    alt = alt || false;

    dockLocation = typeof dockLocation == "undefined" ? 0 : dockLocation;
    offset = offset || { x: 0, y: 0 };

    if (typeof offset != "object") {
        dist = offset;
        offset = { x: 0, y: 0 };
    }

    var sourceLoc = $f.getLocation(sourceElement, alt),
        targetLoc = $f.getLocation(targetElement, alt);

    var r = { x: sourceLoc.bodyX + offset.x, y: sourceLoc.bodyY + offset.y },
        hz = (dockLocation % 2);

    if (posabs) {
        r.x = offset.x;
        r.y = offset.y + targetLoc.bottom;
    }
    else if (dockLocation >= 0) {
        if (dockLocation < 4) {
            r.x += hz ? (rtl ? targetLoc.left : (targetLoc.right - sourceLoc.width)) : (rtl ? (targetLoc.right - sourceLoc.width) : targetLoc.left);
            r.y += dockLocation < 2 ? (targetLoc.bottom + dist) : (targetLoc.top - sourceLoc.height - dist);
        }
        else {
            if (rtl) {
                if (dockLocation < 6)
                    dockLocation += 2;
                else
                    dockLocation -= 2;
            }
            r.x += dockLocation < 6 ? (targetLoc.left - sourceLoc.width - dist) : (targetLoc.right + dist);
            r.y += hz ? (targetLoc.bottom - sourceLoc.height) : targetLoc.top;
        }
    }

    sourceElement.style.left = r.x + "px";
    sourceElement.style.top = r.y + "px";

    return r;
}

$f.getLocation = function(el, alt) {
    //
    // Notes:
    // 
    var rel = false,
        gs = $f.getStyle,
        t = "offsetTop",
        l = "offsetLeft",
        p = "position",
        r = { x: el[l], y: el[t], top: 0, right: 0, bottom: 0, left: 0, bodyX: 0, bodyY: 0, width: el.offsetWidth, height: el.offsetHeight };


    while (el = el.offsetParent) {
        rel = gs(el, p) == "relative";

        if (alt != 2) {
            r.bodyX -= el[l];
            r.bodyY -= el[t];
        }
        if (rel) {
            var pl = toInt(gs(el, "padding-left"));
            var pt = toInt(gs(el, "padding-top"));
            r.x = (alt == 1) ? (r.x) : pl;
            r.y = (alt == 1) ? (r.y) : pt;
        }

        r.x += el[l];
        r.y += el[t];
    }

    function toInt(p_i) {
        p_i = parseInt(p_i);
        return (isNaN(p_i) ? 0 : p_i);
    }

    r.left = r.x
    r.top = r.y;
    r.right = r.x + r.width;
    r.bottom = r.y + r.height;

    return r;
}

$f.getStyle = function(el, style) {
    var r = "";
    if ($f.doc.defaultView && $f.doc.defaultView.getComputedStyle) {
        r = $f.doc.defaultView.getComputedStyle(el, "").getPropertyValue(style);
    }
    else if (el.currentStyle) {
        if (style.indexOf("-") >= 0) {
            var st = style.split("-");
            st[1] = st[1].substr(0, 1).toUpperCase() + st[1].substr(1);
            style = st.join("");
        }
        r = el.currentStyle[style];
    }
    return r;
}
// this will set the RTL value to the real RTL value.
window.rtl = $f.getStyle(document.body, "direction") == "rtl";

$f.isChildOf = function(elParent, elChild) {
    try {
        while (elChild && elChild !== elParent && elChild != document)
            elChild = elChild.parentNode;
        return elChild === elParent;
    } catch (e) { }
}
