
/*   
 *   
 *   TTTTTTTT   EEEEE    CCCC
 *      TT      E       C    C
 *      TT      EEE     C
 *      TT      E       C    
 *      TT      EEEEE    CCCCC    DIGITAL MEDIA HUB
 *   
 *   __ this code will self-construct in 2 seconds... __
 *   
 *   
*/


var trace = function( msg ) {
    try {
        console.log( msg );
    }
    catch ( e ) {
        alert( "TRACE DEBUG MESSAGE:\n\n" + msg );
    }
};

/*
 same as trace, but if no console is found
 it will write a textarea to the bottom of the page
*/
var debug = function( msg ) {
    var debugID = 'debugdebugdebugdebug';
    try {
        console.log( msg );
    }
    catch ( e ) {
        var t = document.getElementById( debugID );
        if ( t === null ) {
            // instanciate t
            var b = document.getElementsByTagName('body')[0];
            t = document.createElement('textarea');
            t.id = debugID;
            t.rows = 20;
            t.cols = 100;
            t.style.border = '1px #000 solid';
            t.value = '**** DEBUG CONSOLE (enable Firebug to use that instead) ****';
            b.appendChild( t );
        }
        t.value += "\n" + msg;
    }
};


var baseURL = window.location.href.split('/');
baseURL.pop();
baseURL = baseURL.join('/') + '/';

var TopPanelTypes = {
    LoginSignupForm:    '0',
    SearchResults:      '1'
};



/*
 * SETTINGS
 * various things that you can change here
 * quickly instead of digging through this
 * wild outback bush known as HUBKODE
 *
 */
var SETTINGS = {
    
    /*
     * Pause live updating while video is playing
     * trying this out to help reduce the memory leak
     * when everything is going at once
     *
     */
    PauseLiveUpdates: false,
    
    /*
     * Only allows one module to update at once,
     * (hopefully) reducing the load on AJAX calls
     *
     * ** NOTE: DO NOT SET THIS - it's controlled by the application! **
     *
     */
    SingleServingMode: false,
    
    
    /*
     * Autoplay
     * a quick way to set what page elements
     * automatically start on load
     * 
     */
    Autoplay: {
        VideoPlayer: true,
        VideoPlayerFirstLoad: false
    },
    
    /*
     * Intervals
     * automatic AJAX updating thingies need to
     * know when to run... everything's in milliseconds
     *
     */
    Intervals: {
        
        TwitterOfficial: {
            UpdateRSS: 25000,
            UpdateDisplay: 20000
        },
        
        LegislationTracker: {
            UpdateFeed: 16000
        },
        
        ActivityStream: {
            UpdateFeed: 15000
        },
        
        ActivityStreamDamageControl: {
            UpdateFeed: function() { return (SETTINGS.Intervals.ActivityStream - 1000); }
        },
        
        CalendarOfficial: {
            UpdateFeed: 300000, /* every 5 minutes */
            UpdateDisplay: 250000
        },
        
        ELife: {
            UpdateFeed: 30000
        },
        
        ConventionResources: {
            UpdateFeed: 120000 /* every 2min */
        },
        
        OfficialBlogs: {
            UpdateFeed: 31000
        },
        
        NewsCoverage: {
            UpdateFeed: 32000
        },
        
        FunFactsFAQ: {
            UpdateFeed: 33000
        }
        
    },
    
    /*
     * Policies
     * various rules to enforce and their coresponding conditionals
     * 
     */
    Policies: {
        
        Notify: {
            ForceLinksNewWindow: true,
            ForceLinksExclusions: [
                '#',
                'javascript:void()',
                'javascript:void(0)'
            ]
        },
        
        ActivityStream: {
            RandomizeFeeds: true
        },
        
        Calendar: {
            MinimumDisplayItems: 5,
            MaximumDisplayItems: 5,
            EnforceLimit:        false,
            EnforceTodayOnly:    false
        },
        
        VideoCPL: {
            MaximumThumbnailsAtOnce: 9999
        }
        
    },
    
    /*
     * VISUALS
     * visual and content related placeholders
     *
     */
    Visuals: {
        LoadingIconURL: 'images/ajax-loading.gif',
        TwitterOfficialLastIndex: -1,
        ModuleEasingType: 'easeOutCirc',
        VODCurrentOffset: 0,
        ChatVisible: false,
        BrandingSlideDownEasingEffect: 'easeInOutCirc'
    },
    
    Defaults: {
        ColumnWidth: '302',
        /* edit: removed the 'px' from the end, cuz jQuery adds 'px' @ the end automagically (and IE was dying) */
        ActivityStream: {
            Height: '511'
        },
        Calendar: {
            Height: '284'
        },
        FeaturedMultimedia: {
            Height: '203'
        },
        LegislationTracker: {
            Height: '220',
            SearchText: 'Search Legislation' /*SearchText: 'type here to search legislation'*/
        },
        ConventionResources: {
            Height: '268'
        }
    }
    
    /*
     keep track of whats currently in the top dropdown panel
     so we dont waste bandwith with ajax calls
    */
    /*ShowingInTopPanel: TopPanelTypes.LoginSignupForm*/
    
};




/*
 * VIDEOS
 * handles LIVE and VOD
 *
 */
var VIDEOS = {
    Live: [],
    VOD: [],
    CurrentLiveID: 0,
    CurrentLiveInfo: {},
    CurrentVODID: -1,
    CurrentVODInfo: {},
    ShareVideoID: {},
    ShareVideoInfo: {}
};



/*
 * GLOBAL FEEDS
 * stores the most recent scrub of various feeds
 * when new data arrives, it should be checked against this
 * and the new items merged, then added to the page
 * in their respective modules
 *
 * yeah right, that'll happen...
 *
 *
 * * note: these arrays must be in the form of {url:'', message:''}
 *
 */

var FEEDS = {
    
    /* official TEC posts (from ELO? where?) */
    Official: [],
    
    TwitterOfficial: [],
    
    TwitterUnofficial: [],
    
    /* images pulled from Flickr's REST API */
    Flickr: [],
    
    /* our official calendar (from where?) */
    Calendar: [],
    
    /* legislation, pulled from the current (RedDot-run) General Convention page */
    LegislativeTracker: [],
    
    /* ??? */
    ConventionResources: [],
    
    /* Episcopal Life */
    ELife: [],
    
    OfficialBlogs: [],
    
    NewsCoverage: [],
    
    FunFactsFAQ: []
    
};





/*
 * TIMERS
 * timer resources for each AJAX call that runs on an interval
 *
 */
var TIMERS = {
    ActivityStream: 0,
    LegislationTracker: 0,
    TwitterOfficialLoad: 0,
    TwitterOfficialDisplay: 0,
    Flickr: 0,
    CalendarOfficialLoad: 0,
    CalendarOfficialDisplay: 0,
    ELifeLoad: 0,
    ConventionResources: 0,
    OfficialBlogs: 0,
    NewsCoverage: 0,
    FunFactsFAQ: 0,
    LegislationTrackerSearch: 0
};


/*
 * UPDATERS
 * these are the actual functions to be called when
 * the AJAX timer(s) kick in... this abstracts them
 * so they can be called independantly also
 *
 * * note: activity stream caps @ 80chars
 *
 */
var UPDATE = {
    /*
     * these prevent an ajax auto-update from doubling up!
     */
    InProgress: {
        TwitterOfficial:    false,
        TwitterUnofficial:  false,
        Calendar:           false,
        LegislationTracker: false,
        ActivityStream:     false,
        ELife:              false,
        OfficialBlogs:      false,
        NewsCoverage:       false,
        FunFactsFAQ:        false
    },
    TwitterOfficialLoad: function(){},
    TwitterOfficialDisplay: function(){},
    TwitterUnofficialLoad: function(){},
    CalendarLoad: function(){},
    CalendarDisplay: function(){},
    ELifeLoad: function(){},
    ConventionResourcesLoad: function(){},
    OfficialBlogsLoad: function(){},
    NewsCoverageLoad: function(){},
    FunFactsFAQLoad: function(){},
    LegislationTrackerLoad: function(){}
};



/*
 * ACTIONS
 * functions that don't necessarily go in an AJAX updater
 * try to keep them grouped nicely pls thx
 *
 */
var ACTIONS = {
    
    Branding: {
        Show: function(){},
        Hide: function(){},
        ToggleVisible: function(){}
    },
    
    VIDEO: {
        ShowVOD: function(){},
        ShowVODAll: function(){},
        AttachThumbnailHandlers: function(){},
        PlayVideo: function(){},
        GetVideoInfo: function(id){},
        PlaySharedVideo: function(title){}
    },
    
    FEEDS: {
        /* el grande cocaina sniff */
        ActivityStreamReload: function(){}
    },
    
    CHAT: {
        Show: function(){},
        Hide: function(){},
        ToggleVisibility: function(){}
    },
    
    MODULES: {
        Toggle: function(){}
    },
    
    SEARCH: {
        Legislation: function(key){}
    }
    
};






/*
 * for the Calendar
 *
 */
var EventType = {
    None:       'eventNone',
    Live:       'eventLive',
    LiveSP:     'eventLiveSP',
    VOD:        'eventOnDemand',
    VODSP:      'eventOnDemandSP'
};




/* use jQuery to handle the DOM-ready event */
$(function() {
    
    //$('div.module').corners("6px");
    SETTINGS.WaitYourTurn = false; // allow modules to update, but play nice with eachother
    
    /* minimize baby */ /* note: i put that comment there so i can search for "minimize" DONT REMOVE IT. */
    /* basic collapse/expand functionality for modules */
    $('div.module div.moduleHeader a.moduleToggle').click( function(e) {
        e.preventDefault();
        e.stopPropagation();
        ACTIONS.MODULES.Toggle( $(this).parent().parent() );
    });
    
    $('div.module div.moduleHeader a.moduleExpand').click( function(e) {
        e.preventDefault();
        e.stopPropagation();
        if ( $(this).parent().parent().hasClass('expanded') ) {
            ACTIONS.MODULES.Restore();
            // finally, reapply the jScrollPane
            //$(currentModule).jScrollPane({reinitialiseOnImageLoad:true});
            $(this).parent().parent().removeClass('expanded'); //** this has to come after Restore
        }
        else {
            ACTIONS.MODULES.Expose( $(this).parent().parent().attr('id') );
            // finally, reapply the jScrollPane
            //$(currentModule).jScrollPane({reinitialiseOnImageLoad:true});
            $(this).parent().parent().addClass('expanded'); //** must come last!!
        }
    });
    
    /* sign up and login links */
    $('div#branding div#brandingHandle div#userLinks a#logIn').click( function() {
        showLoginSignUp();
    });
    $('div#branding div#brandingHandle div#userLinks a#signUp').click( function() {
        showLoginSignUp();
    });
    /*
     @fn.showLoginSignUp
     drops down the hidden top area and shows the login | sign up form
    */
    var showLoginSignUp = function() {
        // todo: this
    };
    
    
    $('div#present div#videoPlayer a#flowplayer').click( function(e) {
        if ( SETTINGS.Autoplay.VideoPlayerFirstLoad === false ) {
            e.preventDefault();
            e.stopPropagation();
            $('#flowplayer').empty();
            ACTIONS.VIDEO.PlayVideo( $(this).attr('href'), false );
            SETTINGS.Autoplay.VideoPlayerFirstLoad = true;
        }
    });
    
    
    /*
     * handler for LIVE
     *
     */
    $('div#videoInformation div#TECLive a#videoCPLShowLive').click( function(e) {
        e.preventDefault();
        e.stopPropagation();
        $(this).addClass("active");
        $('div#videoInformation div#TECLive a#videoCPLShowVOD').removeClass("active");
        ACTIONS.VIDEO.ShowLive();
    });
    
    
    /*
     * handler for VOD
     *
     */
    $('div#videoInformation div#TECLive a#videoCPLShowVOD').click( function(e) {
        e.preventDefault();
        e.stopPropagation();
        $(this).addClass("active");
        $('div#videoInformation div#TECLive a#videoCPLShowLive').removeClass("active");
        SETTINGS.Visuals.VODCurrentOffset = 0;
        ACTIONS.VIDEO.ShowVOD();
    });
    
    
    /* IE PINGG FIXX */
    $('body').supersleight();
    
    
    
    // rotate of official (top right) twitter feed
    $('div#notify p').fadeOut(200, function() {
        $(this).html(
            '<p>Follow us on Twitter <a href="http://twitter.com/gcmediahub09" target="_blank">@gchub09</a></p>'
        );
    }).fadeIn(200);
    
    /**********************************
    ************ DISABLED *************
    **********************************/
    /*TIMERS.TwitterOfficialLoad = window.setInterval( function() {
        UPDATE.TwitterOfficialLoad();
    }, SETTINGS.Intervals.TwitterOfficial.UpdateRSS );
    
    TIMERS.TwitterOfficialDisplay = window.setInterval( function() {
        UPDATE.TwitterOfficialDisplay();
    }, SETTINGS.Intervals.TwitterOfficial.UpdateDisplay );*/
    
    UPDATE.TwitterOfficialLoad(true);
    UPDATE.TwitterOfficialDisplay();
    
    
    
    
    // actually display the tweets
    //var _m_twitterOfficial_lastIndex = -1;
    
    /*
     * on mouseover, pause the rotation of the official tweets
     *
     */
    $('div#header div#notify').mouseenter( function() {
        window.clearInterval( TIMERS.TwitterOfficialDisplay );
    }).mouseleave( function() {
        /**********************************
        ************ DISABLED *************
        **********************************/
        /*TIMERS.TwitterOfficialDisplay = window.setInterval( function() {
            UPDATE.TwitterOfficialDisplay();
        }, SETTINGS.Intervals.TwitterOfficial.UpdateDisplay );*/
    });
    
    
    // pause activity stream on mouse over
    $('div#activityStream.module').mouseenter( function() {
        window.clearInterval( TIMERS.ActivityStream );
    }).mouseleave( function() {
        /**********************************
        ************ DISABLED *************
        **********************************/
        /*TIMERS.ActivityStream = window.setInterval( function() {
            // unofficial twitter
            UPDATE.TwitterUnofficialLoad();
            // elife
            UPDATE.ELifeLoad();
            // official blogs
            UPDATE.OfficialBlogsLoad();
        }, SETTINGS.Intervals.ActivityStream.UpdateFeed );*/
    });
    
    
    
    // make sure the reg/signin form is loaded, otherwise load it
    $('a#logIn, a#signUp').click(function(e) {
        e.preventDefault();
        e.stopPropagation();
        //ACTIONS.Branding.ToggleVisible();
        ACTIONS.Branding.Show();
        // load the form, if not already
        //if ( SETTINGS.ShowingInTopPanel != TopPanelTypes.LoginSignupForm ) {
            // show the loading indicator
            $('div#branding div#brandingInner').empty().html(
                '<img src="' + SETTINGS.Visuals.LoadingIconURL + '" />'
            );
            $.get( 'inc/login_form.inc.php', {}, function(formHTML) {
                $('div#branding div#brandingInner').empty().html( formHTML );
                // TODO: set up any js form handlers here, since all attached
                // events get cleared with new content
                // re-initialize the facebook nonsense button
                $('div#branding div#brandingInner').ready(function(){
                    FB.init();
                });
            }, 'html' );
        //}
    });
    
    
    $('div#stage div#search form#searchFormBasic input[name="q"]').keypress( function(k) {
        // intercept Enter key
        if ( k.which == 13 ) {
            k.preventDefault();
            k.stopPropagation();
            ACTIONS.Branding.Show();
            $('div#branding div#brandingInner')
                .empty()
                .html( '<img src="' + SETTINGS.Visuals.LoadingIconURL + '" />' );
            //trace('loading search results for "' + $(this).val() + '"');
            $.get( 'inc/search.php', {q: $(this).val()}, function(data) {
                $('div#branding div#brandingInner').empty().html( data );
                $('div#branding div#brandingInner').ready(function(){
                    $('div#branding').focus();
                });
            }, 'html' );
        }
    }).focus( function() {
        if ( $(this).val() == 'search' ) {
            $(this).val('');
        }
    }).blur( function() {
        if ( $(this).val() === '' ) {
            $(this).val('search');
        }
    });
    
    
    $('div#branding').blur( function() {
        ACTIONS.Branding.Hide();
    });
    $('div#header, div#present').click( function() {
        ACTIONS.Branding.Hide();
    });
    $('div#brandingHandle').click( function() {
        ACTIONS.Branding.ToggleVisible();
    });
    
    
    
    $('#sb_msg').hide();
    // slide toggle the chat
    $('span#tecChatToggle').click( function() {
        ACTIONS.CHAT.ToggleVisibility();
    });
    $('#tecChatLogo').click( function() {
        ACTIONS.CHAT.ToggleVisibility();
    });

    // deal with focussing the chat message entry box
    $('input#tecChatMessage')
        .focus( function() {
            $(this).css('color', '#fefefe');
        })
        .blur( function() {
            $(this).css('color', '#4D7FC9');
        });
    
    
    
    // IE tweak to initialize chat... ugh
    if ( $.browser.msie ) {
        ACTIONS.CHAT.Hide();
    }
    
    
    // legislation tracker auto updates
    UPDATE.LegislationTrackerLoad = function() {
        if ( SETTINGS.PauseLiveUpdates ) { return; }
        if ( UPDATE.InProgress.LegislationTracker ) {
            return false;
        }
        else {
            UPDATE.InProgress.LegislationTracker = true;
        }
        $.get( 'import/legislative_tracker_live.import.php', {}, function(data) {
            $('div#legislationTracker.module ul.moduleContent').empty().html( data );
            retooltipLegacyTracker();
            ACTIONS.SEARCH.Legislation();
        });
        UPDATE.InProgress.LegislationTracker = false;
    };
    /**********************************
    ************ DISABLED *************
    **********************************/
    /*TIMERS.LegislationTracker = window.setInterval( function() {
        UPDATE.LegislationTrackerLoad();
    }, SETTINGS.Intervals.LegislationTracker.UpdateFeed ); // 10 sec*/
    
    
    
    /*
     *
     * keeps track of the "activity stream"
     *
     */
    /**********************************
    ************ DISABLED *************
    **********************************/
    /*TIMERS.ActivityStream = window.setInterval( function() {
        
        // unofficial twitter bs
        UPDATE.TwitterUnofficialLoad();
        
        // elife
        UPDATE.ELifeLoad();
        
        // official blogs
        UPDATE.OfficialBlogsLoad();
        
    }, SETTINGS.Intervals.ActivityStream.UpdateFeed );*/
    
    
    
    ACTIONS.VIDEO.AttachThumbnailHandlers();
    
    // kick ActivityStream in first thing
    /*UPDATE.CNNLoad();*/
    //UPDATE.TwitterUnofficialLoad();
    window.setTimeout(function(){
        UPDATE.OfficialBlogsLoad();
    }, 2000 );
    //UPDATE.ELifeLoad();
    //UPDATE.ConventionResourcesLoad();
    UPDATE.NewsCoverageLoad();
    window.setTimeout( function() {
        UPDATE.FunFactsFAQLoad();
    }, 4000 );
    //UPDATE.CalendarLoad();
   /* window.setTimeout( function() {
        UPDATE.LegislationTrackerLoad();
    }, 4000 );
    window.setTimeout( function() {
        retooltipLegacyTracker();
    }, 5000 );*/
    
    window.setTimeout( function() {
        SETTINGS.PauseLiveUpdates = true;
    }, 6000 );
    
    

    /*
     * convention resources module
     */
    /**********************************
    ************ DISABLED *************
    **********************************/
    /*TIMERS.ConventionResources = window.setInterval( function() {
        UPDATE.ConventionResourcesLoad();
    }, SETTINGS.Intervals.ConventionResources.UpdateFeed );*/
    
    
    
    /*
     * news coverage module
     */
    /**********************************
    ************ DISABLED *************
    **********************************/
    /*TIMERS.NewsCoverage = window.setInterval( function() {
        UPDATE.NewsCoverageLoad();
    }, SETTINGS.Intervals.NewsCoverage.UpdateFeed );*/
    
    
    
    /*
     * handle drag & drop functionality for modules
     * ala iGoogle
     * 
    */
    var placeholderHeight = 50;
    $('.column').sortable({
        connectWith: '.column',
        /* resize the placeholder to be the same size as the actual
         * content widget, for an accurate preview */
        over: function() {
            $('.ui-sortable-placeholder').height(g_height);
        },
        handle: $('.moduleHeader')
    });
    
    $('div.module')
        .mousedown(function() {
            /* grab a height value for our sortable over event */
            g_height = $(this).height();
        })
        .addClass(
            'ui-widget ' +
            'ui-widget-content ui-helper-clearfix ' +
            'ui-corner-all'
        ).end();
        
        $('.moduleHeader').css('cursor', 'pointer');
        
        // make the handle into a handle by disallowing text selections
        $('div.module div.moduleHeader').disableSelection();
    
    
    
    /*
     * make each module have a custom scroll bar
     *
     */
    $('.moduleContent, #shouts').jScrollPane({
        reinitialiseOnImageLoad: true
    });
    
    /*
     * Legislation Tracker intelligent inline search
     * or at least that's what I'm calling it.
     *
     */
    /*$('div#legislationTracker.module div.moduleLegend input#legislationSearch').keypress( function(key){
        if ( key.which == 13 ) {
            key.preventDefault();
            key.stopPropagation();
            
    });*/
    $('div#legislationTracker.module div.moduleLegend input#legislationSearch')
        .focus( function() {
            var curVal = $(this).val();
            if ( curVal.toString().toLowerCase() == SETTINGS.Defaults.LegislationTracker.SearchText.toLowerCase() ) {
                $(this).val( '' );
            }
        })
        .blur( function() {
            if ( $(this).val() === '' ) {
                $(this).val( SETTINGS.Defaults.LegislationTracker.SearchText );
            }
        })
        .keyup( function(key) {
            $('div#legislationTracker.module div.moduleLegend img#legislationTrackerSearchLoading').show(100);
            window.clearTimeout( TIMERS.LegislationTrackerSearch );
            /**********************************
            ************ DISABLED *************
            **********************************/
            /*TIMERS.LegislationTrackerSearch = window.setTimeout( function() {
                $('div#legislationTracker.module div.moduleLegend img#legislationTrackerSearchLoading').hide(100);
                ACTIONS.SEARCH.Legislation();
            }, 1000 ); // wait 1 seconds*/
        }).keypress( function(key) {
            if ( key.which == 13 ) {
                key.preventDefault();
                key.stopPropagation();
                return false;
            }
        });
    
    
    /* preload the legislation tracker search loading indicator */
    try {
        var legislativeTrackerSearchLoading = new Image();
        legislativeTrackerSearchLoading.src = 'images/leg_search_loading.gif';
    } catch (e) {}
    
    
    
    /*$('#shouts').find('a').click( function() {
        window.open( $(this).attr('href') );
    });*/
   
    /* embed url junk */
    var embedStage  = $('div#embedStage');
    var embedBox    = $('textarea#embedBox');
    var embedLink   = $('input#embedLink');
    var closeButton = $('div.closeButton');
    
    $(embedStage).hide();
    $(embedBox).click(function(){ 
        $(this).select();
    });
    
    $(embedLink).click(function(){
        $(this).select();
    });

    $(closeButton).click(function(){
        try {
            $f().play();
        } catch (e) {}
    });
    
    delete embedStage;
    delete embedBox;
    delete embedLink;
    delete closeButton;
    
}); // end jQuery dom ready wrapper




// leg track -> tooltips
var retooltipLegacyTracker = function() {
    $('div#legislationTracker.module ul.moduleContent li').each( function() {
        /*
            here's the official way to do this via the plugin's website,
            but since we might eventually put more info in the title attribute,
            we're doing it manually for now to have more control
            *      *       *       *       *       *       *       *       *
            ** Replacing title tooltips **
            Replacing the regular old title tooltips of your document is a peice of cake. Simply call the qtip() method with no content option and it uses the title attribute of the target element by default! Like so:
            $('a[title]').qtip({ style: { name: 'cream', tip: true } })
            
         */
        // since we're using JS, strip the title and show our special tooltips
        var title = eval('(' + $(this).attr('title') + ')');
        $(this).attr('title', '');
        $(this).qtip({
            content: {
                // Set the text to an image HTML string with the correct src URL to the loading image you want to use
                text: '<b>Status:</b> ' + title.status + (
                            (title.viewOriginal.length && (title.viewOriginal != '#')) ?
                            ('<br /><a href="' + title.viewOriginal + '" target="_blank" onclick="sbFromURL(this);return false;">View Original</a>') : ''
                        ) + (
                            (title.viewCurrent.length && (title.viewCurrent != '#')) ?
                            (' | <a href="' + title.viewCurrent + '" target="_blank" onclick="sbFromURL(this);return false;">View Current</a>') : ''
                        )
            },
            position: {
                corner: {
                   target: 'topRight', // Position the tooltip above the link
                   tooltip: 'center'
                },
                adjust: {
                   screen: false // Keep the tooltip on-screen at all times
                }
            },
            show: { 
                when: 'mouseenter', 
                solo: true // Only show one tooltip at a time
            },
            //hide: 'mouseleave',
            hide: {
                delay: 300,
                fixed: true/*,
                when {
                    target: $('.qtip'),
                    event: 'inactive'
                }*/
            },
            style: {
                tip: true, // Apply a speech bubble tip to the tooltip at the designated tooltip corner
                border: {
                   width: 0,
                   radius: 4
                },
                name: 'cream', // Use the default light style
                width: 200 // Set the tooltip width
            }
        });
    });
}; // end function retooltipLegacyTracker()





/*
 link is an anchor DOM object, not a url!
*/
var sbFromURL = function( link ) {
    
    $('.qtip').hide(200);
    
    $.get( link.href, {}, function(data) {
        Shadowbox.open({
            player:     'html',
            title:      $(link).text(),
            /*content:    '<div id="sbFromURL"><img src="images/loading_inverted.gif" ' +
                        'style="position:relative;"' +
                        + ' /></div>',*/
            //content:    '<div id="sbFromURL"><img class="sbFromURLLoading" src="images/loading_inverted.gif" /></div>',
            content: '<div id="sbFromURL">' + data + '</div>',
            width: 800,
            height: 600,
            animate: false, /* why the hell isn't this working!? */
            onFinish: function(o) {
                //alert('finished... loading');
                //$.get( link.href, {}, function(data) { $('div#sbFromURL') } );
                //$('div#sbFromURL').load( link.href );
            }
        });
    });
    
}; // end function sbFromURL



var sbIframeFromURL = function( link ) {
    
    $('.qtip').hide(20);
    
    Shadowbox.open({
        player:     'iframe',
        title:      '', /*$(link).text(),*/
        /*content:    '<div id="sbFromURL"><img src="images/loading_inverted.gif" ' +
                    'style="position:relative;"' +
                    + ' /></div>',*/
        //content:    '<div id="sbFromURL"><img class="sbFromURLLoading" src="images/loading_inverted.gif" /></div>',
        //content: '<div id="sbIframeFromURL">' + unescape(link) + '</div>',
        content: unescape( link ),
        width: 800,
        height: 600,
        animate: false, /* why the hell isn't this working!? */
        onFinish: function(o) {
            //alert('finished... loading');
            //$.get( link.href, {}, function(data) { $('div#sbFromURL') } );
            //$('div#sbFromURL').load( link.href );
        }
    });
    
}; // end function sbIframeFromURL




/*
 * note to any developers:
 * if you haven't seen this guy's site yet, check it out!!
 * he ported a lot of PHP functions over to JS... very cool
 *
 */
var in_array = function( needle, haystack, argStrict ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: vlado houba
    // *     example 1: in_array('van', ['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: true
    // *     example 2: in_array('vlado', {0: 'Kevin', vlado: 'van', 1: 'Zonneveld'});
    // *     returns 2: false
    // *     example 3: in_array(1, ['1', '2', '3']);
    // *     returns 3: true
    // *     example 3: in_array(1, ['1', '2', '3'], false);
    // *     returns 3: true
    // *     example 4: in_array(1, ['1', '2', '3'], true);
    // *     returns 4: false
    var key = '',
    strict = !!argStrict;
    if (strict) {
        for (key in haystack) {
            if (haystack[key] === needle) {
                return true;
            }
        }
    }
    else {
        for (key in haystack) {
            if (haystack[key] == needle) {
                return true;
            }
        }
    }
    return false;
};







function array_merge() {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Nate
    // -    depends on: is_int
    // %          note: Relies on is_int because !isNaN accepts floats     
    // *     example 1: arr1 = {"color": "red", 0: 2, 1: 4}
    // *     example 1: arr2 = {0: "a", 1: "b", "color": "green", "shape": "trapezoid", 2: 4}
    // *     example 1: array_merge(arr1, arr2)
    // *     returns 1: {"color": "green", 0: 2, 1: 4, 2: "a", 3: "b", "shape": "trapezoid", 4: 4}
    // *     example 2: arr1 = []
    // *     example 2: arr2 = {1: "data"}
    // *     example 2: array_merge(arr1, arr2)
    // *     returns 2: {1: "data"}
    
    var args = Array.prototype.slice.call(arguments);
    var retObj = {}, k, j = 0, i = 0;
    var retArr;
    
    for (i=0, retArr=true; i < args.length; i++) {
        if (!(args[i] instanceof Array)) {
            retArr=false;
            break;
        }
    }
    
    if (retArr) {
        return args;
    }
    var ct = 0;
    
    for (i=0, ct=0; i < args.length; i++) {
        if (args[i] instanceof Array) {
            for (j=0; j < args[i].length; j++) {
                retObj[ct++] = args[i][j];
            }
        } else {
            for (k in args[i]) {
                if (this.is_int(k)) {
                    retObj[ct++] = args[i][k];
                } else {
                    retObj[k] = args[i][k];
                }
            }
        }
    }
    
    return retObj;
}
