/*jslint bitwise: true, browser: true, eqeqeq: true, nomen: true, undef: true, white: true */
/*extern Sys, BLACKBAUD, $get, $addHandler, arrScrollers, ActiveXObject, checkForNextPage */

//global
var arrXmlReqs = []; //array to hold all XMLHttpReq objects
var dsImages = [];
var unpackedScrollers = {};

function getScroller(contentId) {
    //each scroller spits out an entry into this associative array 
    //keyed on it's contentid - created in ScrollingDonorDisplay
    
    if (!unpackedScrollers[contentId])
    {
        if (arrScrollers) {
            var obj = arrScrollers[contentId];
            if (typeof(obj) !== 'undefined') {
                unpackedScrollers[contentId] = Sys.Serialization.JavaScriptSerializer.deserialize(obj);
            } else {
                BLACKBAUD.netcommunity.consoleLog('Internal error. Problem retrieving Scroller Object!');
            }   
        }
    }
    return unpackedScrollers[contentId];
}

//List of functions
function preLoadImages() {
    dsImages['playbuttonout'] = new Image();
    dsImages['playbuttonout'].src = ROOT_PATH + 'images/play_large_gray.gif';
    dsImages['playbuttonover'] = new Image();
    dsImages['playbuttonover'].src = ROOT_PATH + 'images/play_large_blue.gif';
    dsImages['pausebuttonout'] = new Image();
    dsImages['pausebuttonout'].src = ROOT_PATH + 'images/pause_large_gray.gif';
    dsImages['pausebuttonover'] = new Image();
    dsImages['pausebuttonover'].src = ROOT_PATH + 'images/pause_large_blue.gif';  
    dsImages['openhandcursor'] = new Image();
    dsImages['openhandcursor'].src = ROOT_PATH + 'images/hand-open.cur';
    dsImages['closehandcursor'] = new Image();
    dsImages['closehandcursor'].src = ROOT_PATH + 'images/hand-closed.cur';
    return true;
}

function playButtonOut(id) {
    var img = document.getElementById(id);
    if (img) {
        img.src = dsImages.playbuttonout.src;
    }
}

function playButtonOver(id) {
    var img = document.getElementById(id);
    if (img) {
        img.src = dsImages.playbuttonover.src;
    }
}

function buttonState(contentId) { //is scroller playing or paused?
    var scrollerObj = getScroller(contentId);
    if (scrollerObj) {
        var hidden = scrollerObj.HiddenId;
        var interval = document.getElementById(hidden);
        if (interval) {
            if (String(interval.value).length > 0) {
                return 1; //playing
            }
            else {
                return -1; //paused
            }
        }
    }
}

function buttonOut(id, contentId) {
    var scrollerObj = getScroller(contentId);
    if (scrollerObj) {
        var img = document.getElementById(id);
        var btnState = buttonState(contentId);
        if (Number(btnState) > 0) { //play
            if (img) {
                img.src = dsImages.pausebuttonout.src;
            }
        } 
        else {
            if (img) {
                img.src = dsImages.playbuttonout.src;
            }
        }    
    }
}

function buttonOver(id, contentId) {
    var scrollerObj = getScroller(contentId);
    if (scrollerObj) {
        var img = document.getElementById(id);
        var btnState = buttonState(contentId);
        if (Number(btnState) > 0) { //play
            if (img) {
                img.src = dsImages.pausebuttonover.src;
            }
        } 
        else {
            if (img) {
                img.src = dsImages.playbuttonover.src;
            }
        }   
    }
}

function openHand(id) {
    var td = document.getElementById(id);
    if (td) {
        td.style.cursor = "url(" + dsImages.openhandcursor.src + "), default";
    }
    return false;
}

function closeHand(id) {
    var td = document.getElementById(id);
    if (td) {
        td.style.cursor = "url(" + dsImages.closehandcursor.src + "), default";
    }
    return false;
}

function getCachedDonors(scrollerObj, pageNumber)
{
    return scrollerObj.cachedRecordSets[pageNumber % scrollerObj.cacheSize];
}

function CXMLReq(freed) { // this function instantiates XMLHttpReq objects
    this.freed = freed;
    this.xmlhttp = false; 
    
    if (window.ActiveXObject) {  //IE
        this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    else if (window.XMLHttpRequest) { //FireFox
        this.xmlhttp = new XMLHttpRequest();
    }
}

function setTimer(scrollerObj, veryFirstTime) {
    var recordcount;
    if (scrollerObj.DesignDisplay) {
        recordcount = 1;
    } else {
        recordcount = scrollerObj.RecordCount;
    }
     
    if (recordcount) {
        if (Number(recordcount) > 0) { 

            //if content was dragged, div Top has changed.

            if (veryFirstTime)
            {
                // Firefox is not very efficient at repositioning divs, need to limit the frame period
                var maxFirefoxSpeed = 25;
                if (navigator.userAgent.indexOf("Gecko") >= 0 && scrollerObj.PixelsPerSecond > maxFirefoxSpeed)
                {
                    scrollerObj.PixelsPerSecond = maxFirefoxSpeed;
                }
                scrollerObj.framePeriod = 1000 * scrollerObj.pixelsPerFrame / scrollerObj.PixelsPerSecond;
            }

            var hidden = scrollerObj.HiddenId;
            var interval = document.getElementById(hidden);
            if (interval) {
                if (String(interval.value).length > 0) {
                    return;  //scroller is already playing
                } else {
                    interval.value = setInterval(scrollerObj.draw, scrollerObj.framePeriod);              
                }
            }
        }
    } else {
        BLACKBAUD.netcommunity.consoleLog('record count not evaluated.'); 
    }             
}

function playScroller(scrollerObj) {
    if (scrollerObj) {
        setTimer(scrollerObj, false);
    }
}

function objHeight(obj) {
    return Sys.UI.DomElement.getBounds(obj).height;
} 

function mouseUp(e) {
    e = e || window.event;
    //if pause was clicked prior to drag, don't play scroller
    if (!this.scrollerObj.pauseClicked) { 
        playScroller(this.scrollerObj);
    }
    this.scrollerObj.divI[0].onmousemove = null;
    this.scrollerObj.divI[1].onmousemove = null;
    checkForNextPage(this.scrollerObj);
}

function pauseScroller(scrollerObj) {
    if (scrollerObj) {
        var hidden = scrollerObj.HiddenId;
        var interval = document.getElementById(hidden);
        if (interval) {
            clearInterval(interval.value);
            interval.value = '';
        }
    }
}

function mouseMove(e) {
    var newY;
    if (e) {
        newY = e.layerY;
    } else if (window.event) {
        newY = window.event.offsetY;
    }
    
    var styleY = (newY - this.startY);
    var str, t, n;
    
    var div = this.scrollerObj.divI[0];
    if (div.style.pixelTop) {
        div.style.pixelTop += styleY;
    } else {
        str = String(div.style.top);
        t = str.split("p");
        n = Number(t[0]);
        n += styleY;
        div.style.top = n + 'px';
    }  

    div = this.scrollerObj.divI[1];
    if (div.style.pixelTop) {
        div.style.pixelTop += styleY;
    } else {
        str = String(div.style.top);
        t = str.split("p");
        n = Number(t[0]);
        n += styleY;
        div.style.top = n + 'px';
    }
    return false;
}

function mouseDown(e) {
    if (e) {
        this.startY = e.layerY;
    } 
    else if (window.event) {
        e = window.event;
        this.startY = e.offsetY;
    }
    pauseScroller(this.scrollerObj);
    this.scrollerObj.divI[0].onmousemove = mouseMove;
    this.scrollerObj.divI[1].onmousemove = mouseMove;
    return false;
}

function mouseOut(e) {
    //Make Scroller play if user releases the hold outside of the Display
    if (!this.scrollerObj.pauseClicked) { 
        playScroller(this.scrollerObj);
    }
    //To release the "lock" mentioned in CR300474-051308
    //reset onmousemove event handler for inner div and reset hand cursor.
    if (this.divI) {
        this.divI.onmousemove = null;
    }
    if (!this.DesignDisplay) {
        this.style.cursor = 'url(' + dsImages.openhandcursor.src + ')';
    }  
}   

function addDragBehavior(contentId) {
    var scrollerObj = getScroller(contentId);
    var scrollerInnerDiv;
    if (scrollerObj) {
        scrollerInnerDiv = scrollerObj.divI[0];
        if (scrollerInnerDiv) {
            scrollerInnerDiv.scrollerObj = scrollerObj;
            scrollerInnerDiv.contentId = contentId;
            scrollerInnerDiv.onmouseup = mouseUp;
            scrollerInnerDiv.onmousedown = mouseDown;
        }
        scrollerInnerDiv = scrollerObj.divI[1];
        if (scrollerInnerDiv) {
            scrollerInnerDiv.scrollerObj = scrollerObj;
            scrollerInnerDiv.contentId = contentId;
            scrollerInnerDiv.onmouseup = mouseUp;
            scrollerInnerDiv.onmousedown = mouseDown;  
        }
        //ViM on 6/25/08 for CR300474-051308
        //Register event handler for parent table
        var tbl;
        tbl = scrollerObj.TableId;
        var scrollerTable = document.getElementById(tbl);
        if (scrollerTable) {
            scrollerTable.scrollerObj = scrollerObj;
            scrollerTable.contentId = contentId;
            scrollerTable.DesignDisplay = scrollerObj.DesignDisplay;
            scrollerTable.divI = scrollerObj.divI;
            scrollerTable.onmouseleave = mouseOut;
        }
    }        
}

function startScroll(scrollerObj) {
    var recordCount = scrollerObj.RecordCount;
    
    //basically don't change the height/ or do anything if no gifts have been found yet.
    if (recordCount) {
        if (Number(recordCount) > 0) { 
            //if all the above works then bring in the magic...
            //function definition in ScrollerDragEffect.js
            addDragBehavior(scrollerObj.ScrollerId); 
            
            if (scrollerObj.Direction === 1) { // 1 = ascending
                scrollerObj.divI[scrollerObj.leadingIndex].style.top = scrollerObj.Height + 'px';
            } else {
                scrollerObj.divI[scrollerObj.leadingIndex].style.top = -objHeight(scrollerObj.divI[0]) + 'px';
            }
            setTimer(scrollerObj, true);
        }
    } else {
        BLACKBAUD.netcommunity.consoleLog('record count not evaluated.');
    }
}

function handleStateChange(pos, scrollerObj) {
    if (typeof(arrXmlReqs[pos]) !== 'undefined' && arrXmlReqs[pos].freed === 0 && arrXmlReqs[pos].xmlhttp.readyState === 4) {
    
        var oResponse;
        var payloadHTML;
        var recordcount;
        
        if (arrXmlReqs[pos].xmlhttp.status === 200) {
            oResponse = arrXmlReqs[pos].xmlhttp.responseText;
            //some JS string manipulation
            var temp = [];
            temp = oResponse.split('|');
            if (temp) {
                var divId = temp[0];
                recordcount = temp[1];
                payloadHTML = temp[2];

                scrollerObj.RecordCount = parseInt(recordcount, 10);

                //the response needs to include the inner div id or the scroller object itself. Use a delimiter | to separate the 
                //id from its corresponding data
                var scrollerInnerDiv = document.getElementById(divId);
                if (scrollerInnerDiv) {
                    if (payloadHTML.length > 0) {
                        scrollerObj.pagesReceived++;
                        var elapsed = (new Date()).getTime() - scrollerObj.requestTime[divId];
                        getCachedDonors(scrollerObj, scrollerInnerDiv.pageNumber).payload = payloadHTML;
                        if (elapsed > scrollerObj.maxRequestElapsed)
                        {
                            scrollerObj.maxRequestElapsed = elapsed;
                            var pixelsElapsed = scrollerObj.PixelsPerSecond * elapsed / 1000;
                            scrollerObj.nextPageSize = Math.ceil((scrollerObj.Height + pixelsElapsed) / scrollerObj.pixelsPerRow);
                        }
                        if (scrollerObj.pagesReceived <= 2)
                        {
                            scrollerInnerDiv.style.top = scrollerObj.Height + 'px';
                            scrollerInnerDiv.innerHTML = payloadHTML;
                            if (scrollerObj.pagesReceived === 2) 
                            {
                                //startScroll needs the data to have been rendered.
                                setTimeout(function () {
                                    startScroll(scrollerObj);
                                }, 100);
                            }
                        } 
                        else
                        {
                            scrollerInnerDiv.innerHTML = payloadHTML;
                            if (scrollerObj.pauseClicked)
                            {
                                // Once the HTML renders, we may need to reposition
                                setTimeout(function () {
                                    checkForNextPage(scrollerObj);
                                }, 100);
                            }
                        }
                    }
                } else {
                    BLACKBAUD.netcommunity.consoleLog('could not find scroller ' + divId);
                }
            }
        }
        arrXmlReqs[pos].freed = 1;			 
    }
}

//function handles multiple AJAX calls 
function makeRequest(url, scrollerObj) {
    var pos = -1;
    for (var i = 0; i < arrXmlReqs.length; i++) {
        if (arrXmlReqs[i].freed === 1) {
            pos = i;
            break;
        }
    }
    if (pos === -1) {
        pos = arrXmlReqs.length;
        arrXmlReqs[pos] = new CXMLReq(1);
    }
    
    if (arrXmlReqs[pos].xmlhttp) { //valid XMLHttpReq object.
        arrXmlReqs[pos].freed = 0; //I'm not free. Don't bother me until I get back my response.
        
        arrXmlReqs[pos].xmlhttp.open("GET", url, true);
        arrXmlReqs[pos].xmlhttp.onreadystatechange = function () {
            handleStateChange(pos, scrollerObj);
        };
        
        if (window.ActiveXObject) {
            arrXmlReqs[pos].xmlhttp.send();
        }
	    else if (window.XMLHttpRequest) {
            arrXmlReqs[pos].xmlhttp.send(null);
        }
    }
}

function initRequest(scrollerObj, index) {
    var isPageElement;
    var frBase;
    var baseId;
    var currencySymbol;
    
    var divId = index === 0 ? scrollerObj.DivInnerId0 : scrollerObj.DivInnerId1;
    var div = scrollerObj.divI[index];
    
    scrollerObj.requestTime[divId] = (new Date()).getTime();
    
    scrollerObj.divI[index].innerHTML = scrollerObj.loadingMessage;
    
    frBase = scrollerObj.FundraiserBaseType;
    baseId = scrollerObj.FundraiserBaseId;
    // Pascal 20090202: CR311620-111408
    currencySymbol = encodeURIComponent(scrollerObj.CurrencySymbol);
    
    if (frBase === 'solicitor' || frBase === 'team') {
        isPageElement = true;
    } else {
        isPageElement = false;
    }
        
    var url = scrollerObj.PageURL;
    
    if (url) {
        var queryString;
        var qs1 = '?contentid=' + scrollerObj.ScrollerId + '&divid=' + divId + '&offset=' + div.recordOffset + '&pagesize=' + div.pageSize + '&csymbol=' + currencySymbol;
        
        if (isPageElement) {
            var qs2 = '&basetype=' + frBase + '&baseid=' + baseId;
            queryString = qs1 + qs2 + '&stamp=';
        } else {
            queryString = qs1 + '&stamp=';
        }
        
        url = url.concat(queryString);
        var timestamp = new Date().getTime();
        url = url.concat(timestamp);
        makeRequest(url, scrollerObj);
        
    } else {
        BLACKBAUD.netcommunity.consoleLog('Invalid URL. Cannot make AJAX call.');
    }
}

function getDonors(scrollerObj, divIndex)
{
    var div = scrollerObj.divI[divIndex];
    var cached = getCachedDonors(scrollerObj, div.pageNumber);
    if (cached)
    {
        BLACKBAUD.netcommunity.consoleLog("Loading page from cache: " + div.pageNumber);
        div.recordOffset = cached.recordOffset;
        div.pageSize = cached.pageSize;
        div.innerHTML = cached.payload;
    }
    else
    {
        BLACKBAUD.netcommunity.consoleLog("Loading page from server: " + div.pageNumber);
        BLACKBAUD.netcommunity.consoleLog("Page size: " + div.pageSize);
        scrollerObj.cachedRecordSets[div.pageNumber % scrollerObj.cacheSize] = {
            recordOffset : div.recordOffset,
            pageSize : div.pageSize
        };
        initRequest(scrollerObj, divIndex);
    }
}

function nextPage(innerHeight, scrollerObj, index)
{
    scrollerObj.pixelsPerRow = innerHeight[1 - scrollerObj.leadingIndex] / scrollerObj.nextPageSize;
    getDonors(scrollerObj, index);
    scrollerObj.leadingIndex = 1 - scrollerObj.leadingIndex;
}

function checkForNextPage(scrollerObj)
{
    var innerHeight = [objHeight(scrollerObj.divI[0]), objHeight(scrollerObj.divI[1])];
    getCachedDonors(scrollerObj, scrollerObj.divI[0].pageNumber).height = innerHeight[0];
    getCachedDonors(scrollerObj, scrollerObj.divI[1].pageNumber).height = innerHeight[1];
    
    var leadingDiv = scrollerObj.divI[scrollerObj.leadingIndex];
    var trailingDiv = scrollerObj.divI[1 - scrollerObj.leadingIndex];
    var leadingDivTop = parseInt(leadingDiv.style.top, 10);
    var trailingDivTop = parseInt(trailingDiv.style.top, 10);
    var recordCount = scrollerObj.RecordCount;
    
    if (scrollerObj.Direction === 1) // up
    {
        if (leadingDivTop < -innerHeight[scrollerObj.leadingIndex])
        {
            // natural flow
            leadingDiv.pageSize = scrollerObj.nextPageSize;
            leadingDiv.recordOffset = (trailingDiv.recordOffset + trailingDiv.pageSize) % recordCount;
            leadingDiv.pageNumber = trailingDiv.pageNumber + 1;
            nextPage(innerHeight, scrollerObj, scrollerObj.leadingIndex);
            leadingDivTop += innerHeight[1 - scrollerObj.leadingIndex];
        }
        else if (leadingDivTop > 0 && leadingDiv.pageNumber > 0)
        {
            // manually dragged in the opposite direction
            trailingDiv.pageNumber = leadingDiv.pageNumber - 1;
            nextPage(innerHeight, scrollerObj, 1 - scrollerObj.leadingIndex);
            innerHeight[scrollerObj.leadingIndex] = getCachedDonors(scrollerObj, trailingDiv.pageNumber).height;
            leadingDivTop -= innerHeight[scrollerObj.leadingIndex];
        }
        trailingDivTop = leadingDivTop + innerHeight[scrollerObj.leadingIndex];
    }
    else
    {
        if (leadingDivTop > scrollerObj.Height)
        {
            // natural flow
            leadingDiv.pageSize = scrollerObj.nextPageSize;
            leadingDiv.recordOffset = (trailingDiv.recordOffset + trailingDiv.pageSize) % recordCount;
            leadingDiv.pageNumber = trailingDiv.pageNumber + 1;
            nextPage(innerHeight, scrollerObj, scrollerObj.leadingIndex);
            leadingDivTop -= innerHeight[scrollerObj.leadingIndex];
        }
        else if (leadingDivTop + innerHeight[scrollerObj.leadingIndex] < scrollerObj.Height && leadingDiv.pageNumber > 0)
        {
            // manually dragged in the opposite direction
            trailingDiv.pageNumber = leadingDiv.pageNumber - 1;
            nextPage(innerHeight, scrollerObj, 1 - scrollerObj.leadingIndex);
            leadingDivTop += innerHeight[1 - scrollerObj.leadingIndex];
        }
        trailingDivTop = leadingDivTop - innerHeight[1 - scrollerObj.leadingIndex];
    }
    // The meanings of leadingDiv and trailingDiv are ambiguous now so don't use them here.
    scrollerObj.divI[scrollerObj.leadingIndex].style.top = leadingDivTop + 'px';
    scrollerObj.divI[1 - scrollerObj.leadingIndex].style.top = trailingDivTop + 'px';
}

function scrF(scrollerObj)
{
    var leadingDivTop = parseInt(scrollerObj.divI[scrollerObj.leadingIndex].style.top, 10);
    if (scrollerObj.Direction === 1) // up
    {
        scrollerObj.divI[scrollerObj.leadingIndex].style.top = leadingDivTop - scrollerObj.pixelsPerFrame + 'px';
    }
    else
    {
        scrollerObj.divI[scrollerObj.leadingIndex].style.top = leadingDivTop + scrollerObj.pixelsPerFrame + 'px';
    }
    checkForNextPage(scrollerObj);
}

function btnClicked(contentId) {
    var scrollerObj = getScroller(contentId);
    if (scrollerObj) {
        var btnId;
        var img;
        var btnState = buttonState(contentId);
        if (Number(btnState) > 0) { //if playing, then pause
            pauseScroller(scrollerObj);
            scrollerObj.BtnState = -1; //change btn state
            //change img to play
            btnId = scrollerObj.BtnId;
            //change it's source to play onmouseover
            img = document.getElementById(btnId);
            img.src = dsImages.playbuttonover.src;
            //change the alt, title
            img.alt = 'Play'; 
            img.title = 'Play'; 
            scrollerObj.pauseClicked = true;
        }
        else { //if paused, then play
            playScroller(scrollerObj);
            scrollerObj.BtnState = 1; //change btn state
            //change img to pause
            btnId = scrollerObj.BtnId;
            //change it's source to pauseonmouseover
            img = document.getElementById(btnId);
            img.src = dsImages.pausebuttonover.src;
            //change the alt, title
            img.alt = 'Pause'; 
            img.title = 'Pause'; 
            scrollerObj.pauseClicked = false;
        }
    }
}

function setScrollerProps(div, scrollerObj) {
    //Set the div's height, width, caption
    div.style.width = String(scrollerObj.Width) + 'px';
    div.style.height = String(scrollerObj.Height) + 'px';
    
    //find the inner div and set it's properties
    if (scrollerObj.divI[0] && scrollerObj.divI[1]) {
        scrollerObj.divI[0].style.width = scrollerObj.Width + 'px';
        scrollerObj.divI[1].style.width = scrollerObj.Width + 'px';
        //don't set the height of the inner div - it should take the height of it's contents.
        if (scrollerObj.DesignDisplay) {
            scrollerObj.divI[0].style.height = scrollerObj.Height + 'px';
            scrollerObj.divI[1].style.height = scrollerObj.Height + 'px';
        }
        scrollerObj.divI[0].style.textAlign = 'center';
        scrollerObj.divI[1].style.textAlign = 'center';
        //scrollerInnerDiv.innerHTML = '<p class="DonorPlayerLoadingMsg">loading...</p>';
        
        //find the parent table
        var tbl;
        tbl = scrollerObj.TableId;
        var scrollerTable = document.getElementById(tbl);
        if (scrollerTable) {
            scrollerTable.style.width = scrollerObj.Width + 'px';
            scrollerTable.style.height = scrollerObj.Height + 30 + 'px';
            if (!scrollerObj.DesignDisplay) {
                scrollerTable.style.cursor = 'url(' + dsImages.openhandcursor.src + '), default';
            }
        } else {
            BLACKBAUD.netcommunity.consoleLog('Cannot find table ' + String(tbl));
        }
    } else {
        BLACKBAUD.netcommunity.consoleLog('Cannot find scroller ' + String(scrollerObj.DivInnerId0));   
    }
    
    //find the btn and register its event handler
    var btnId;
    btnId = scrollerObj.BtnId;
    
    if (String(btnId).length > 0) { //only if button is shown
        var btn = document.getElementById(btnId);
        if (btn) {
            btn.onclick = function (e) {
                btnClicked(scrollerObj.ScrollerId);
            };
        }
    } 
    
    return true;  
}

function getInitialDatasets(scrollerObj) {
    //Now you're ready to get the data for this particular scroller. 
    //Make this an AJAX call 1.Other parts of the page continue to load. 2.So you can see "loading..." :-)
    var asyncCtlId, frIds;
    asyncCtlId = scrollerObj.ScrollerId;
    frIds = scrollerObj.Fundraisers;
    
    //if design display, don't make call. Just scroll design content
    if (scrollerObj.DesignDisplay) {
        startScroll(scrollerObj);
    } else {
        //Make the AJAX calls.
        getDonors(scrollerObj, 0);
        getDonors(scrollerObj, 1);
    }
}

function initScrollers(contentId) { //called onload
    var scrollerObj = getScroller(contentId);
    if (scrollerObj) {
        if (!scrollerObj.DesignDisplay) {
            preLoadImages(); 
            //find the scroller divs
            scrollerObj.divO = document.getElementById(scrollerObj.DivOuterId); 
            scrollerObj.divI = [document.getElementById(scrollerObj.DivInnerId0), document.getElementById(scrollerObj.DivInnerId1)];
            scrollerObj.loadingMessage = scrollerObj.divI[0].innerHTML;
            scrollerObj.leadingIndex = 0;
            scrollerObj.pagesReceived = 0;
            scrollerObj.pixelsPerFrame = 1;
            scrollerObj.draw = function () {
                scrF(scrollerObj);
            };
            scrollerObj.requestTime = {};
            scrollerObj.maxRequestElapsed = 0;
            scrollerObj.pixelsPerRow = 20; // initial guess used only for the first two pages of results
            var initialPageSize = Math.ceil(scrollerObj.Height / scrollerObj.pixelsPerRow);
            scrollerObj.divI[0].pageSize = initialPageSize;
            scrollerObj.divI[1].pageSize = initialPageSize;
            scrollerObj.divI[0].recordOffset = 0;
            scrollerObj.divI[1].recordOffset = initialPageSize;
            scrollerObj.divI[0].pageNumber = 0;
            scrollerObj.divI[1].pageNumber = 1;
            scrollerObj.cachedRecordSets = [];
            scrollerObj.PixelsPerSecond = parseInt(scrollerObj.PixelsPerSecond, 10);
            scrollerObj.Width = parseInt(scrollerObj.Width, 10);
            scrollerObj.Height = parseInt(scrollerObj.Height, 10);
            scrollerObj.cacheSize = 100;
            if (document.getElementById && document.createElement) {
                if (scrollerObj.divO) {
                    // setScrollerProps - sets the width, height of outer & inner divs
                    var propsSet = setScrollerProps(scrollerObj.divO, scrollerObj);
                    if (propsSet) {
                        getInitialDatasets(scrollerObj); 
                    } else {
                        BLACKBAUD.netcommunity.consoleLog('Cannot set scroller properties. AJAX call cannot be made.');
                    }
                } else {
                    BLACKBAUD.netcommunity.consoleLog('Cannot find scroller (outer)' + String(scrollerObj.DivOuterId));
                }
            } else {
                BLACKBAUD.netcommunity.consoleLog('Browser does not support DOM. Cannot load scrollers!');
            }
        }
    }   
}

function cursorRelease(e) {
    if (window.event) { //IE 
        this.style.cursor = "url(/BCMSPortal/images/hand-open.cur)";	
    }
}

function cursorDrag(e) {
    if (window.event) { //IE 
        this.style.cursor = "url(/BCMSPortal/images/hand-closed.cur)";	
    }
}

////////////////////////////////////////////
// End of script
if (typeof(Sys) !== 'undefined')
{
    Sys.Application.notifyScriptLoaded();
}
////////////////////////////////////////////
// Do not add any code below this
////////////////////////////////////////////
