/**
 *  Global Calls
 */
(function()
{
    /**
     *  Fix IE background image flicker
     *  http://www.mister-pixel.com/
     */
    try
    {
	    document.execCommand('BackgroundImageCache', false, true);
    }
    catch(e) {}
    
    /**
     *  Mouse Wheel Events
     *  Thanks http://andrewdupont.net/2007/11/07/pseudo-custom-events-in-prototype-16/
     *  Can only be accesesd via custom event:
     *      "mouse:wheel"
     */
    var wheel = function(event)
    {
        var realDelta;
        
        // normalize the delta
        if (event.wheelDelta) // IE & Opera
        {
            realDelta = event.wheelDelta / 120;
        }
        else if (event.detail) // W3C
        {
            realDelta = -event.detail / 3;
        }
        
        if (!realDelta) return;
        
        var customEvent = Event.element(event).fire('mouse:wheel', {delta: realDelta});
        if (customEvent.stopped) Event.stop(event);
    };
    
    document.observe('mousewheel', wheel).observe('DOMMouseScroll', wheel);
    
    /**
     *  Keyboard Events
     *  Can only be accesesd via custom event:
     *      "keyboard:type"   
     */
    var type = function(event)
    {
        var intendedAction;
        var reservedKeys = /[<>/?#=,]/;
        
        var keycode = event.which || event.keyCode;
	    var key = String.fromCharCode(keycode).toLowerCase();
	    
	    if((key == 'x') || (key == 'c') || (keycode == Event.KEY_ESC))
		{
			intendedAction = 'close';
		}
		else if (keycode == Event.KEY_RETURN)
		{
		    intendedAction = 'submit';
		}
		else if (reservedKeys.test(key))
		{
		    intendedAction = 'invalidate';
		}
		
        if (!intendedAction) return;
        
        var customEvent = Event.element(event).fire('keyboard:type', {action: intendedAction});
        if (customEvent.stopped) Event.stop(event);
    };
    
    document.observe('keypress', type);
})();

/**
 *  SunGard Initialization
 */
var SunGard = {
    init: function()
    {
        new SunGard.History();
        new SunGard.Tabs();
        new SunGard.SitewideFilter();
        new SunGard.Headers();
        new SunGard.ForeignLanguageSelector();
        new SunGard.Stage();
        new SunGard.Overlay();
        new SunGard.Carousel();
        new SunGard.RequestInfo();
        new SunGard.ExpandableSidebar();
        new SunGard.MediaLinks();
        new SunGard.Forms();
        new SunGard.ResetForm();
        new SunGard.UpdateWFFMForms();
    }
};

/**
 *  Headers (uses sIFR)
 */
  
SunGard.Headers = Class.create({
    // Constructor
    initialize: function()
    {
        if (typeof sIFR != 'function') return;
        
		sIFR.replaceElement('#logo-segment', named({sFlashSrc: rootPath + 'flash/common/avenir-55-roman.swf', sColor: '#FFFFFF', sWmode: 'transparent', sCase: 'upper'}));
	    sIFR.replaceElement('.corporate .home #content h1', named({sFlashSrc: rootPath + 'flash/common/avenir-45-book.swf', sColor: '#666666', sWmode: 'transparent'}));
	    sIFR.replaceElement('#content h1', named({sFlashSrc: rootPath + 'flash/common/avenir-65-medium.swf', sColor: '#3A3A3A', sWmode: 'transparent', sCase: 'upper', nPaddingBottom: '12'}));
    }
});

/**
 *  Foreign Language Selector (currently only for Campaign sites)
 */
SunGard.ForeignLanguageSelector = Class.create({
    _clientID: 'foreign-language',
    
    // Constructor
    initialize: function()
    {
        this.container = $(this._clientID);
        // only build if client hook exists
        if (this.container == null) return;
        
        // set up methods
        this.callWebServiceWithCallback(); // Non-JSONP web service call replaced by JSONP call
        //this.callWebService();
    },
    
    // Private Methods
    callWebService: function()
    {
        new Ajax.Request(rootPath + 'webservices/LanguageService.asmx/GetLanguages', {
            postBody: '{ID:\'' + currentItemID + '\'}',
            contentType: 'application/json; charset=utf-8',
            onSuccess: this.build.bind(this)
        });
    },
    
    callWebServiceWithCallback: function()
    {
        // JSONP call to get around cross domain issues (noticeable on M2L form pages)
        getJSON(rootPath + 'webservices/LanguageService.asmx/GetLanguages?ID=\'' + currentItemID + '\'&jsoncallback=?', this.build.bind(this));
    },
    
    build: function(response)
    {
        this.data = response.d;
        if (this.data == '') return; // no supported foreign languages, bounce out
        
        this.setProperties();
        if (this.numberOfLanguageOptions == 1) return; // don't display only one lang option
        this.buildCache();
        this.buildLanguageList();
        this[(this.numberOfLanguageOptions > 3 || this.suppressHeaderLanguageNames) ? 'buildDhtml' : 'buildInline']();
    },
    
    setProperties: function()
    {
        this.data = this.data.evalJSON();
        this.languages = this.data.Languages;
        this.numberOfLanguageOptions = this.languages.length;
        this.currentLanguage = this.data.CurrentLanguage;
        this.chooseLanguageText = this.data.ChooseLanguageText;
        this.suppressHeaderLanguageNames = this.data.HeaderLanguageNamesSuppressed;
    },
    
    buildCache: function()
    {
        this.wrapper = new Element('div', {id: 'language-selector'});
        this.list = new Element('ul').observe('click', this.onListClick.bind(this));
        this.listItemTemplate = new Template('<li#{style}><a href="##{code}">#{name}</a></li>');
        this.selectedListItemTemplate = new Template('<li#{style}>#{name}</li>');
    },
    
    buildLanguageList: function()
    {
        this.languages.each(function(language, i)
        {
            this.list.insert(this[(language.Code.toLowerCase() == this.currentLanguage) ? 'selectedListItemTemplate' : 'listItemTemplate'].evaluate({style: (i == 0) ? ' class="start"' : '', code: language.Code, name: language.Name}));
        }.bind(this));
    },
    
    buildInline: function()
    {
        this.wrapper.insert(this.list);
        this.container.insert({after: this.wrapper});
        this.container.setStyle({width: this.list.getWidth() + 'px'});
    },
    
    buildDhtml: function()
    {
        // bound function calls
        this.bOnDhtmlHover = this.onDhtmlHover.bindAsEventListener(this);
        // create elements
        this.dhtmlOpener = new Element('p').update('<a href="#">' + this.chooseLanguageText + '</a>');
        this.dhtmlBox = new Element('div', {id: 'language-options'});
        this.dhtmlBoxContentContainer = new Element('div');
        // attach events
        this.dhtmlOpener.observe('mouseover', this.bOnDhtmlHover).observe('mouseout', this.bOnDhtmlHover).observe('click', this.onDhtmlOpenerClick.bind(this));
        this.dhtmlBox.observe('mouseover', this.bOnDhtmlHover).observe('mouseout', this.bOnDhtmlHover);
        Event.observe(document.onresize ? document : window, 'resize', this.setDhtmlBoxProperties.bind(this));
        // insert
        this.dhtmlBoxContentContainer.insert(this.list);
        this.dhtmlBox.insert(this.dhtmlBoxContentContainer).hide();
        this.wrapper.insert(this.dhtmlOpener);
        this.container.insert({after: this.wrapper});
        this.container.up().insert({after: this.dhtmlBox}); // need to insert after 'header' b/c of IE layout issues with position relative ancestor that has set height
        this.setDhtmlBoxProperties();
    },
    
    setDhtmlBoxProperties: function()
    {
        var dhtmlOpenerDimensions = this.dhtmlOpener.getDimensions();
        var dhtmlOpenerPosition = this.dhtmlOpener.cumulativeOffset();
        var dhtmlBoxDimensions = this.dhtmlBox.getDimensions();
        var width = dhtmlOpenerDimensions.width + 'px';
        this.dhtmlBox.setStyle((dhtmlBoxDimensions.width < dhtmlOpenerDimensions.width) ? {left: dhtmlOpenerPosition.left - 1 + 'px', width: width} : {left: dhtmlOpenerPosition.left + dhtmlOpenerDimensions.width - dhtmlBoxDimensions.width - 1 + 'px'});
    },
    
    onListClick: function(event)
    {
        Event.stop(event); // stop default click event
        
        var element = Event.element(event); // get event element
        if (element.tagName != 'A') return; // make sure link was clicked
        $(element).blur(); // make sure link loses focus
        
        this.currentLanguage = element.hash.substr(1);
        this.redirect();
    },
    
    onDhtmlOpenerClick: function(event)
    {
        Event.stop(event); // stop default click event
    },
    
    onDhtmlHover: function(event)
    {
        this.dhtmlBox[(event.type == 'mouseover') ? 'show' : 'hide']();
    },
    
    redirect: function()
    {
        document.location = (this.currentLanguage == 'en') ? rootPath + micrositeHomePage.substr(1) : rootPath + this.currentLanguage.toLowerCase() + micrositeHomePage;
    }
});

/**
 *  Generic Search Filter
 */
SunGard.GenericSearchFilter = Class.create({
    // Constructor
    initialize: function()
    {
        // cache defaults
        this.defaultDisplayText = this.fld.readAttribute('value');
        this.value = '';
        
        // flag
        this.changed = false;
        
        // set up methods
        this.attachEvents();
    },
    
    // Private methods
    attachEvents: function()
    {
        this.fld.observe('focus', this.onFieldFocus.bind(this)).observe('blur', this.onFieldBlur.bind(this)).observe('keyboard:type', this.onFieldKeypress.bind(this));
    },
    
    onFieldFocus: function(event)
    {
        if (!this.changed) this.fld.clear();
        this.changed = true;
    },
    
    onFieldBlur: function(event)
    {
        if (this.fld.value != '') return;
        
        if (this.value == '')
        {
            this.fld.value = this.defaultDisplayText;
            this.changed = false;
        }
        else
        {
            if (this.keypressAction == null)
            {
                this.fld.value = this.value;
            }
        }
    },
    
    onFieldKeypress: function(event)
    {
        if (event.memo.action == 'submit')
        {
            // stop default form submit
            Event.stop(event);
            
            // set keypress flag
            this.keypressAction = true;
            
            // lose focus
            this.fld.blur();
            
            // get value and remove whitespace
            this.fld.value = this.fld.getValue().strip();
            
            // don't do anything if field is empty and has default copy
            if ((this.value == '' && this.fld.value == this.defaultDisplayText) || this.fld.value == this.value) return;
            
            // remove keypress flag
            this.keypressAction = null;
            
            this.runQuery();
        }
        else if (event.memo.action == 'invalidate')
        {
            // stop default form submit
            Event.stop(event);
            
            return;
        }
    },
    
    setValue: function(value)
    {
        this.fld.enable();
        if (value == '')
        {
            this.fld.value = this.defaultDisplayText;
            this.value = '';
            this.fld.blur();
            this.changed = false;
        }
        else
        {
            this.fld.value = value;
            this.value = value;
            this.changed = true;
        }
    },
    
    disable: function()
    {
        this.fld.disable();
        this.fld.value = 'Unavailable';
    }
});

/**
 *  Sitewide Search Filter (next to top nav, inherits from SunGard.GenericSearchFilter)
 */
SunGard.SitewideFilter = Class.create(SunGard.GenericSearchFilter, {
    // Constructor
    initialize: function($super)
    {
        // only run if search exists
        if ($('search') == null) return;
        
        // cache element
        this.fld = $$('#search input')[0];
        
        // call base class method
        $super();
    },
    
    // Public Methods
    runQuery: function()
    {
        // check current location
        if (String(window.location).toLowerCase().indexOf('searchresults.aspx') == -1)
        {
            // redirect to "search results" page
            window.location = rootPath + sitePath + 'searchresults.aspx#/q=' + this.fld.value.replace(/\s/g, '+') + '/';
        }
        else
        {
            // fire custom FX event
            document.fire('search:action');
            
            // fire custom event
            document.fire('criteria:selected', {group: 'Query', attribute: this.fld.value});
            
            // set query filter text
            $$('#query input')[0].value = this.fld.value;
            
            // clear text
            this.setValue('');
        }
    }
});

/**
 *  History (uses SWFAddress for deep linking and forward/backward functionality)
 *  Subscriptions:
 *      "SunGard.Tabs"
 */
SunGard.History = Class.create({
    _initialized: false,
    _subscribers: {},
    _delimiter: '/',
    
    // Constructor
    initialize: function()
    {
        document.observe('history:subscribe', this.attachEvents.bind(this));
    },
    
    // Private Methods
    attachEvents: function(event)
    {
        this._subscribers[event.memo.key] = {};
        this._subscribers[event.memo.key]['obj'] = event.memo.obj;
        this._subscribers[event.memo.key]['method'] = event.memo.method;
        
        // only add listeners once
        if (this._initialized) return;
        
        this._initialized = true;
        SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.onChange.bind(this)); // NOTE: also fired on initial load
        document.observe('history:add', this.add.bind(this));
    },
    
    onChange: function(event)
    {
        this.parseQueryString(event.path);
    },
    
    parseQueryString: function(qs)
    {
        var pairs = qs.toQueryParams([separator = this._delimiter]);
        
        $H(this._subscribers).each(function(subscriber)
        {
            var obj = subscriber.value['obj'];
            var method = subscriber.value['method'];
            
            if (qs == this._delimiter || qs == '' || qs == '#')
            {
                obj[method]('');
            }
            else
            {
                obj[method](pairs[subscriber.key]);
            }
        }.bind(this));
    },
    
    add: function(event)
    {
        SWFAddress.setValue(event.memo.key + '=' + event.memo.value);
    }
});

/**
 *  Tabs
 *  Subscribes:
 *      "history:subscribe" - register for history tracking
 */
SunGard.Tabs = Class.create({
    _activePrefix: 'active-',
    _tabPrefix: 'tab-',
    _key: 'tab',
    
    // Constructor
    initialize: function()
    {
        // only run if tabs exist on page
        if ($('tabs') == null || $$('#tabs #controls').length == 0) return;
        
        $$('#tabs div.tab').invoke('hide'); // hide all
        
        // cache elements
        this.controlContainer = $$('#tabs #controls ul')[0];
        
        // set up methods
        this.attachEvents();
    },
    
    // Private Methods
    attachEvents: function()
    {
        document.fire('history:subscribe', {key: this._key, obj: this, method: 'setActiveTab'}); // subscribe to UI History
        this.controlContainer.observe('click', this.onClick.bindAsEventListener(this)).observe('mouse:wheel', this.onWheeledOver.bindAsEventListener(this));
    },
    
    onClick: function(event)
    {
        // stop default click event
        Event.stop(event);
        
        // get event element
        var element = Event.element(event);
        // make sure link was clicked
        if (element.tagName != 'A') return;
        // make sure link loses focus
        $(element).blur();
        
        // set UI history
        document.fire('history:add', {key: this._key, value: element.hash.substr(1)});
    },
    
    onWheeledOver: function(event)
    {
        // stop default mouse wheel event
        Event.stop(event);
        
        var currentTab = this._tabPrefix + this.activeTab;
        
        // depending on mouse movement, next OR prev tab
        var tab = (event.memo.delta > 0) ? $(currentTab).next() : $(currentTab).previous();
        
        // do nothing if trying to advance last tab or go back from first (no circular functionality)
        if (tab == undefined) return;
        
        // set UI history
        document.fire('history:add', {key: this._key, value: tab.id.split(this._tabPrefix)[1]});
    },
    
    setActiveTab: function(tab)
    {
        $$('#tabs div.tab').invoke('hide'); // hide all
        $$('#tabs #controls ul li').invoke('removeClassName', 'active'); // remove 'active' label from all (used for print tab content)
        
        if (tab == '' || ($(tab) == null && this.activeTab == null)) // initial view AND tab area does not exist (previously set "tab" has not been set)
        {
            this.activeTab = $$('#tabs div.tab').first().id; // first tab is active
        }
        else if ($(tab)) // subsequent views => tab area exists
        {
            this.activeTab = tab; // "tabFromQuery" is active
        }
        else // subsequent views => tab area does not exist
        {
            this.activeTab = this.activeTab; // previously set "tab" is active
        }
        
        $(this.activeTab).show(); // show current
        this.controlContainer.id = this._activePrefix + this.activeTab; // set styles
        $(this._tabPrefix + this.activeTab).addClassName('active'); // add 'active' label to current (used for print tab content)
    }
});

/**
 *  MediaLinks
 *  Types:
 *      FlashVideo
 *      FlashAudio
 *  Subscriptions:
 *      "copy:reset" - unregister previous event handlers if they exist and look for more
 */
SunGard.MediaLinks = Class.create({
    _videoClassName: 'video',
    _audioClassName: 'audio',
    _modalCache: {}, // modal overlay cache
    _jsonpWebServiceMethods: ['GetVideoByID', 'GetAudioByID'], // web service methods that require JSONP calls
    
    // Constructor
    initialize: function()
    {
        // set up first since copy can change at any time and next test will fail if no links exist on initial load
        document.observe('copy:reset', this.reset.bind(this));
        
        this.mediaLinks = $$('a.' + this._videoClassName + ', a.' + this._audioClassName);
        if (this.mediaLinks.size() == 0) return;
        
        // set up methods
        this.attachEvents();
    },
    
    // Private Methods
    attachEvents: function()
    {
        // cache bound function calls
        this.bOnLinkClick = this.onLinkClick.bindAsEventListener(this);
        
        // hijack click event
        this.mediaLinks.invoke('observe', 'click', this.bOnLinkClick);
    },
    
    detachEvents: function()
    {
        // unregister event handler
        if (this.mediaLinks) this.mediaLinks.invoke('stopObserving', 'click', this.bOnLinkClick);
    },
    
    reset: function()
    {
        this.detachEvents();
        this.mediaLinks = $$('a.' + this._videoClassName + ', a.' + this._audioClassName);
        this.attachEvents();
    },
    
    onLinkClick: function(event)
    {
        // prevent browser default click
        Event.stop(event);
        
        // get event element
        var element = Event.element(event);
        
        // make sure to get link if IMG was clicked (ex: <a href...><img ... /> Some Text</a>)
        if (element.tagName == 'IMG')
        {
            element = Event.findElement(event, 'A');
        }
        // make sure link was clicked
        if (element.tagName != 'A') return;
        // make sure link loses focus
        $(element).blur();
        
        this.omnitureTagging(element);
        
        var classNames = $w(element.className);
        this.mediaType = classNames[0]; // get media type
        this.webServiceMethodName = classNames[1]; // get web service method name
        this.ID = element.hash.substr(1); // get GUID from HREF
        this[(this._modalCache[this.ID]) ? 'showModal' : 'callWebService'](); // if data already exists, use cached version
    },
    
    load: function(response)
    {
        var data = (response.responseJSON) ? response.responseJSON.d : response.d;
        data = data.evalJSON();
        data.id = this.ID;
        this._modalCache[this.ID] = new SunGard.ModalTemplate[(this.mediaType == this._videoClassName) ? 'FlashVideo' : 'FlashAudio'](data);
        this.showModal();
    },
    
    error: function(response)
    {
        alert('This video is currently unavailable.');
    },
    
    callWebService: function()
    {
        var isJSONPMethod = (this._jsonpWebServiceMethods.indexOf(this.webServiceMethodName) == -1) ? false : true;
        if (isJSONPMethod)
        {
            // JSONP call to get around cross domain issues (noticeable on M2L form pages)
            getJSON(rootPath + 'webservices/MediaService.asmx/' + this.webServiceMethodName + '?ID=\'' + this.ID + '\'&jsoncallback=?', this.load.bind(this));
            return;
        }
        new Ajax.Request(rootPath + 'webservices/MediaService.asmx/' + this.webServiceMethodName, {
            postBody: '{ID:\'' + this.ID + '\'}',
            contentType: 'application/json; charset=utf-8',
            onSuccess: this.load.bind(this),
            onFailure: this.error.bind(this)
        });
    },
    
    omnitureTagging: function(element)
    {
        var title = element.innerHTML.stripTags().strip(); // strip HTML and whitespace
        
        var s = s_gi(s_account);
        s.linkTrackVars = 'prop15,eVar15,events';
        s.linkTrackEvents = 'event5';
        s.prop15 = title;
        s.eVar15 = s.prop15;
        s.events = 'event5';
        s.tl(element, 'o', title);
    },
    
    showModal: function()
    {
        document.fire('modal:open', {id: this.ID});
    }
});

/**
 *  Carousel Sidebar
 */
SunGard.Carousel = Class.create({
    // Constructor
    initialize: function()
    {
        // only run if carousel exist on page
        if ($('carousel') == null) return;
        
        // cache elements
        this.carouselContainer = $('carousel');
        this.viewportContainer = $('viewport');
        this.controls = $$('#carousel #nav-carousel ul')[0];
        
        // cache bound function calls
        this.bStopAutomatedRotation = this.stopAutomatedRotation.bind(this);
        this.bStartAutomatedRotation = this.startAutomatedRotation.bind(this)
        
        // set defaults
        this.currentItem = 1;
        this.numberOfItems = $$('#carousel #viewport>li').length;
        this.carouselItem = $('item-' + this.currentItem);
        this.navItem = this.controls.select('li:first-of-type')[0]; // first item is default
        
        // set "+1" (last->first) item for auto rotation functionality
        this.plusOne = new Element('li', {id: 'item-' + (this.numberOfItems + 1)});
        this.plusOne.innerHTML = this.carouselItem.innerHTML;
        this.viewportContainer.insert(this.plusOne);
        
        // hide controls if only 1 carousel item
        if (this.controls.select('li').size() == 1)
        {
            this.controls.hide();
            return;
        }
        
        // set up methods
        this.setInterval();
        this.attachEvents();
        this.insertNavIndicator();
    },
    
    // Private Methods
    setInterval: function()
    {
        this.interval = carouselInterval * 1000; // need in milliseconds
    },
    
    attachEvents: function()
    {
        this.startAutomatedRotation();
        this.viewportContainer.observe('mouseenter', this.bStopAutomatedRotation).observe('mouseleave', this.bStartAutomatedRotation);
        this.controls.observe('click', this.onNavClick.bindAsEventListener(this));
    },
    
    insertNavIndicator: function()
    {
        var carouselContainerOffset = this.carouselContainer.cumulativeOffset();
        var controlsOffset = this.controls.cumulativeOffset();
        this.navTopPosition = controlsOffset.top - carouselContainerOffset.top + 3;
        
        this.indicator = new Element('div', {id: 'indicator'});
        this.indicator.setStyle({
            top: this.navTopPosition + 'px',
            left: this.navItem.cumulativeOffset().left - carouselContainerOffset.left - 3 + 'px'
        });
        
        // insert nav "indicator" into DOM
        this.carouselContainer.insert(this.indicator);
    },
    
    startAutomatedRotation: function()
    {
        this.rotation = setInterval(this.rotate.bind(this), this.interval);
    },
    
    stopAutomatedRotation: function()
    {
        clearInterval(this.rotation);
    },
    
    rotate: function()
    {
        if (this.currentItem <= this.numberOfItems) // account for "+1"
        {
            this.currentItem++;
        }
        else
        {
            this.currentItem = 1;
        }
        
        this.carouselItem = $('item-' + this.currentItem);
        this.navItem = this.controls.select('li')[((this.currentItem == this.numberOfItems + 1) ? 1 : this.currentItem) - 1]; // check for "+1" and account for 0 based array
        
        this.animate();
    },
    
    onNavClick: function(event)
    {
        // stop default click event
        Event.stop(event);
        
        var element = Event.element(event);
        
        // make sure link was clicked
        if (element.tagName != 'A') return;
        
        // make sure clicked link loses focus
        $(element).blur();
        
        // stop all automation functionality
        this.stopAutomatedRotation();
        this.viewportContainer.stopObserving('mouseenter', this.bStopAutomatedRotation).stopObserving('mouseleave', this.bStartAutomatedRotation);
        
        // stop any "in progress" effects
        if (this.itemEffect || this.indicatorEffect)
        {
            this.itemEffect.cancel();
            this.indicatorEffect.cancel();
        }
        
        // get/set items
        this.carouselItem = $(element.hash.substr(1));
        this.navItem = Event.findElement(event, 'LI');
        
        this.animate();
    },
    
    animate: function()
    {
        this.moveItem();
        this.moveNavIndicator();
    },
    
    moveItem: function()
    {
        var viewportContainerOffset = this.viewportContainer.cumulativeOffset();
        var itemOffset = this.carouselItem.cumulativeOffset();
        
        this.itemEffect = new Effect.Move(this.viewportContainer,
            {
                mode: 'absolute',
                duration: .6,
                x: viewportContainerOffset.left - itemOffset.left,
                y: viewportContainerOffset.top - itemOffset.top,
                afterFinish: function(effect){
                    if (this.currentItem == this.numberOfItems + 1)
                    {
                        this.currentItem = 1;
                        effect.element.setStyle({left: '0px'});
                    }
                }.bind(this)
            }
        ); 
    },
    
    moveNavIndicator: function()
    {
        this.indicatorEffect = new Effect.Fade(this.indicator, {
            duration: .3,
            afterFinish: function(effect){
                effect.element.setStyle({
                    top: this.navTopPosition + 'px',
                    left: this.navItem.cumulativeOffset().left - this.carouselContainer.cumulativeOffset().left - 3 + 'px'
                });
                
                new Effect.Appear(effect.element, {
                    duration: .3
                });
            }.bind(this)
        });
    }
});

/**
 *  Expandable (expand/collapse)
 *  Types:
 *      Sidebar
 *      Content areas
 */
SunGard.Expandable = Class.create({
    _expandedClassName: 'expanded',
    _collapsedClassName: 'collapsed',
    
    // Constructor
    initialize: function()
    {
        // set up methods
        this.buildUI();
    },
    
    // Private Methods
    buildUI: function()
    {
        // create expand/collapse all controls
        this.controls = new Element('ul', {className: 'controls-expandable'}).insert(
            new Element('li', {className: 'expand-all'}).insert(new Element('a', {href: '#expand'}).update('Expand All'))
        ).insert(
            new Element('li', {className: 'collapse-all'}).insert(new Element('a', {href: '#collapse'}).update('Collapse All'))
        ).observe('click', this.onControlsClick.bindAsEventListener(this));
        
        // insert expand/collapse all controls into DOM
        this.container.insert({before: this.controls});
    },
    
    onHeaderClick: function(group)
    {
        group[group.hasClassName(this._collapsedClassName) ? 'removeClassName' : 'addClassName'](this._collapsedClassName);
    },
    
    onControlsClick: function(event)
    {
        // stop default click event
        Event.stop(event);
        
        var element = Event.element(event);
        
        // make sure link was clicked
        if (element.tagName != 'A') return;
        
        // make sure clicked link loses focus
        $(element).blur();
        
        // get intended action (expand/collapse) from hash value
        var action = element.hash.substr(1);
        
        // expand/collapse all sidebar groups depending on "action"
        this.groups.invoke((action == 'expand') ? 'removeClassName' : 'addClassName', this._collapsedClassName);
    }
});

/**
 *  Expand/Collapse Sidebar group (inherits from SunGard.Expandable)
 */
SunGard.ExpandableSidebar = Class.create(SunGard.Expandable, {
    _autoExpandAllSites: ['publicsector'], // list of sites that want all sidebars expanded by default
    
    // Constructor
    initialize: function($super)
    {
        // only run if expand/collapse functionality exists on page
        if ($('expandable') == null) return;
        
        // cache elements
        this.container = $('expandable');
        this.groups = this.container.select('div.group');
        this.headers = this.container.select('div.group h4');
        
        if (this.groups.size() == 0) // double check that there are groups inside "expandable" sidebar
        {
            // remove DIV from DOM to avoid displaying expandable UI
            $('expandable').remove();
            return;
        }
        else if (this.groups.size() == 1) // if there is only one group, don't need expand/collapse functionality
        {
            $('sidebar').replaceChild(this.groups[0], this.container);
            return;
        }
        else
        {
            $super();
        }
    },
    
    // Private Methods
    buildUI: function($super)
    {
        var shouldAutoExpandAll = this._autoExpandAllSites.any(function(n) { return $$('body.'+n).length > 0; });
        
        this.groups.each(function(group, i)
        {
            // attach click event to headers
            this.headers[i].observe('click', this.onHeaderClick.bindAsEventListener(this));
        
            // leave first group or auto expand all sites expanded
            if (i == 0 || shouldAutoExpandAll) return;
            
            // collapse all sidebar groups
            group.addClassName(this._collapsedClassName);
        }.bind(this));
        
        $super();
    },
    
    onHeaderClick: function($super, event)
    {
        // stop default click event
        Event.stop(event);
        
        var element = Event.element(event);
        
        var associatedGroup = element.up('div.group');
        
        $super(associatedGroup);
    }
});

/**
 *  Stage
 */
SunGard.Stage = Class.create({
    // Constructor
    initialize: function()
    {
        this.buildCache();
        this.attachEvents();
    },
    
    // Private Methods
    buildCache: function()
    {
        this.body = $(document.body);
	    this.viewport = $(document.viewport);
	    this.page = $('header');
    },
    
    attachEvents: function()
    {
        Event.observe(document.onresize ? document : window, 'resize', this.resetDimensions.bind(this));
        document.observe('stage:getDimensions', this.getDimensions.bind(this));
    },
    
    setDimensions: function()
    {
        this.dimensions = {body: this.body.getDimensions(), viewport: this.viewport.getDimensions(), page: this.page.getDimensions()};
    },
    
    resetDimensions: function()
    {
        document.fire('stage:resized');
    },
    
    // Public Methods
    getDimensions: function(event)
    {
        this.setDimensions();
        event.memo.obj[event.memo.property] = this.dimensions;
    }
});

/**
 *  Overlay (used in conjunction with Modal windows to "grey" out background)
 */
SunGard.Overlay = Class.create({
    _overlayOpacity: 0.525,
    _duration: 0.5,
    
    // Constructor
    initialize: function()
    {
        this.build();
        this.buildCache();
        this.attachEvents();
    },
    
    // Private Methods
    build: function()
    {
        // create overlay DOM element
        this.overlay = new Element('div', {id: 'overlay', style: 'display: none'});
        // insert overlay into DOM
        $(document.body).insert(this.overlay);
    },
    
    buildCache: function()
    {
        this.bOnClick = this.onClick.bindAsEventListener(this);
        this.bOnStageResize = this.onStageResize.bind(this);
    },
    
    onClick: function(event)
	{
	    document.fire('overlay:hide'); // fire custom event
	},
	
	onStageResize: function()
    {
        this.setDimensions();
    },
    
    attachEvents: function()
    {
        document.observe('modal:show', this.setDimensions.bind(this)).observe('modal:show', this.show.bind(this)).observe('modal:hide', this.hide.bind(this)).observe('overlay:hide', this.hide.bind(this));
    },
	
	show: function()
	{
	    new Effect.Appear(this.overlay, {duration: this._duration, from: 0.0, to: this._overlayOpacity});
	    this.overlay.observe('click', this.bOnClick);
	    document.observe('stage:resized', this.bOnStageResize);
	    
	    // Getting modal div based on ID set in SunGard.ModalTemplate.M2L
	    var modalDiv = $('m2l');
	    if (modalDiv != null)
	    {
	        if (modalDiv.hasClassName('modal') == false)
	        {   // BUG, class is being added by Sitecore WFFM as "className='modal'"
	            modalDiv.addClassName('modal');
	        }
	    }
	},
	
	hide: function()
    { 
        this.overlay.stopObserving('click', this.bOnClick);
        document.stopObserving('stage:resized', this.bOnStageResize);
        new Effect.Fade(this.overlay, {duration: this._duration});
    },
    
    setDimensions: function()
    {
        // get stage dimensions
        document.fire('stage:getDimensions', {obj: this, property: 'dimensions'});
        // get modal bottom position
        document.fire('modal:getBottomPosition', {obj: this, property: 'modalBottomPosition'});
        
        var height = (this.dimensions.body.height > this.dimensions.viewport.height) ? this.dimensions.body.height : this.dimensions.viewport.height;
        if (this.modalBottomPosition > height) height = this.modalBottomPosition; // need to check height of background overlay since modal window can be longer than the body height
        
        this.overlay.setStyle({width: (this.dimensions.viewport.width < this.dimensions.page.width) ? this.dimensions.page.width + 'px' : '100%', height: height + 'px'});
    }
});

/**
 *  Modal Template
 */
SunGard.ModalTemplate = Class.create({
    _className: 'modal',
    _topMargin: 17,
    _leftMargin: 20,
    _maxWidth: 512, // hard-coded b/c of difficulties in getting width before element is inserted into DOM
    
    // Constructor
    initialize: function(data)
    {
        this.id = data.id;
        
        // set up methods
        this.buildCache();
        this.attachEvents();
        this.insert();
        this.setDimensions();
        this.buildAndInsertShim();
    },
    
    // Private Methods
    buildCache: function()
    {
        this.pageHead = $$('head')[0];
        
        this.cacheBoundFunctionCalls();
        this.cacheControls();
        
        this.container = new Element('div', {id: this.type, className: this._className}).insert(this.controls).insert(this.copy).hide();
    },
    
    cacheBoundFunctionCalls: function()
    {
        this.bOnKeyboardType = this.onKeyboardType.bindAsEventListener(this);
        this.bOnStageResize = this.onStageResize.bind(this);
        this.bGetModalBottomPosition = this.getModalBottomPosition.bind(this);
        this.bHide = this.hide.bind(this);
    },
    
    cacheControls: function()
    {
        this.close = new Element('li', {id: 'close'}).insert(new Element('a', {href: '#close'}).update('Close'));
        this.controlList = new Element('ul').observe('click', this.onControlsClick.bindAsEventListener(this));
        
        if (this.canPrint)
        {
            this.overlayPrintCssFile = new Element('link', {type: 'text/css', rel: 'stylesheet', media: 'print', href: rootPath + 'styles/common/print-overlay.css'});
            this.print = new Element('li', {id: 'print'}).insert(new Element('a', {href: '#print'}).update('Print'));
            this.controlList.insert(this.print).insert(this.close);
        }
        else
        {
            this.controlList.addClassName('close').insert(this.close);
        }
        
        this.controls = new Element('div', {id: 'controls'}).insert(this.controlList);
    },
    
    attachEvents: function()
    {
        document.observe('modal:open', this.show.bind(this));
    },
    
    insert: function()
    {
        $('footer').insert({before: this.container});
    },
    
    setDimensions: function()
    {
        this.containerDimensions = this.container.getDimensions();
    },
    
    buildAndInsertShim: function()
    {
        // IE needs iframe shim to cover "bleed-through" elements
        if (!Prototype.Browser.IE) return;
        
        this.iframeShim = new Element('iframe', {src: 'javascript:false;', id: 'shim', frameBorder: 0}).hide();
        this.iframeShim.setStyle(this.containerDimensions);
        
        $('footer').insert({before: this.iframeShim});
    },
    
    onControlsClick: function(event)
    {
        // stop default click event
        Event.stop(event);
        // get "click" element
        var element = Event.element(event);
        // make sure link was clicked
        if (element.tagName != 'A') return;
        // make sure clicked link loses focus
        $(element).blur();
        // ID determines course of action
        (Event.findElement(event, 'LI').id == 'print') ? window.print() : this.hide();
    },
    
    onKeyboardType: function(event)
	{
	    if (event.memo.action != 'close') return;
	    this.hide();
	},
    
    onStageResize: function()
    {
        this.setPosition();
    },
    
    show: function(event)
    {
        // only show this modal (check that IDs match)
        if (event && event.memo.id != this.id) return;
        // insert overlay print CSS reference
        if (this.canPrint) this.pageHead.insert(this.overlayPrintCssFile);
        // set position
        this.setPosition();
        // attach events
        document.observe('stage:resized', this.bOnStageResize).observe('keyboard:type', this.bOnKeyboardType).observe('overlay:hide', this.bHide).observe('modal:getBottomPosition', this.bGetModalBottomPosition);
        // custom event
        document.fire('modal:show');
        // show modal & shim
        this.container.show();
        if (this.iframeShim) this.iframeShim.show();
    },
    
    hide: function()
    {
        // remove overlay print CSS reference
        if (this.canPrint) this.overlayPrintCssFile.remove();
        // hide modal & shim
        this.container.hide();
        if (this.iframeShim) this.iframeShim.hide();
        // custom event
        document.fire('modal:hide');
        // dettach events
        document.stopObserving('stage:resized', this.bOnStageResize).stopObserving('keyboard:type', this.bOnKeyboardType).stopObserving('overlay:hide', this.bHide).stopObserving('modal:getBottomPosition', this.bGetModalBottomPosition);
    },
    
    setPosition: function()
    {
        // get stage dimensions
        document.fire('stage:getDimensions', {obj: this, property: 'dimensions'});
        
        this.getVerticalPosition();
        this.getHorizontalPosition();
        
        // set modal & shim position according to page size/position
        this.container.setStyle(Object.extend(this.containerHorizontalPosition, this.containerVerticalPosition));
        if (this.iframeShim) this.iframeShim.setStyle(Object.extend(this.containerHorizontalPosition, this.containerVerticalPosition));
    },
    
    getVerticalPosition: function()
    {
        this.defaultTopPosition = this.dimensions.page.height + this._topMargin;
        this.contentTopOffset = $('content').cumulativeScrollOffset().top;
        
        this.containerVerticalPosition = {top: ((this.contentTopOffset > this.defaultTopPosition) ? this.contentTopOffset + this._topMargin : this.defaultTopPosition) + 'px'};
        this.modalBottomPosition = parseInt(this.containerDimensions.height) + parseInt(this.containerVerticalPosition.top);
    },
    
    getHorizontalPosition: function()
    {
        this.containerHorizontalPosition = (this.dimensions.viewport.width < this.dimensions.page.width) ? {left: '0', marginLeft: this._leftMargin + 'px'} : {left: '50%', marginLeft: '-457px'};
    },
    
    // Public Methods
    getModalBottomPosition: function(event)
    {
        event.memo.obj[event.memo.property] = this.modalBottomPosition;
    }
});

/**
 *  Request Info/a Briefing links
 */
SunGard.RequestInfo = Class.create({
    _modalCache: {}, // modal overlay cache
    
    // Constructor
    initialize: function()
    {
        // only run if requests exist on page
        if ($$('#request-a-briefing a', 'a.request-info').length == 0) return;
        
        // set up methods
        this.buildCache();
        this.attachEvents();
    },
    
    // Private Methods
    buildCache: function()
    {
        this.requestLinks = $$('#request-a-briefing a', 'a.request-info');
    },
    
    attachEvents: function()
    {
        this.requestLinks.invoke('observe', 'click', this.onLinkClick.bindAsEventListener(this));
    },
    
    onLinkClick: function(event)
    {
        // stop default click event
        Event.stop(event);
        // get element
        var element = Event.element(event);
        // make sure clicked link loses focus
        $((element.tagName != 'A') ? Event.findElement(event, 'A') : element).blur();
        // get iframe src from HREF
        this.iframeSrc = element.href;
        this.iframeHeight = $w(element.className)[1];
        
        // create modal if it is not in cache
        if (this._modalCache[this.iframeSrc] == null) this.createModal();
        // show modal
        this.showModal();
    },
    
    createModal: function()
    {
        this._modalCache[this.iframeSrc] = new SunGard.ModalTemplate.M2L({id: this.iframeSrc, iframeSrc: this.iframeSrc, iframeHeight: this.iframeHeight});
    },
    
    showModal: function()
    {
        document.fire('modal:open', {id: this.iframeSrc});
    }
});

/**
 *  Market 2 Lead Modal Template opens a Market 2 Lead (M2L) form in an iframe
 *      inherits from ModalTemplate (located in sungard.js)
 *      opened via Request Information link
 */
SunGard.ModalTemplate.M2L = Class.create(SunGard.ModalTemplate, {
    _iframe: null,

    // Constructor
    initialize: function($super, data)
    {
        this.type = 'm2l';
        this.canPrint = true;
        
        this._iframe = new Element('iframe', {frameBorder: 0, src: data.iframeSrc, height: data.iframeHeight});
        this._iframe.observe('load', this.onIFrameLoad.bind(this._iframe)); 
        
        this.copy = new Element('div', {id: 'copy'}).insert(this._iframe);
        
        $super(data);
    },

    onIFrameLoad: function()
    {
        if (SunGard.iFrameHeight.height != null)
        {
            SunGard.iFrameHeight.height += 36; //add 36px to iframe height so toggled dropdowns don't introduce scrollbar
            $(this).setStyle( {height: SunGard.iFrameHeight.height + 'px'} ); 

        }
    }

});

SunGard.iFrameHeight = {
    height: null 
};

/**
 *  Media Type Icons
 *      internal (default)
 *      pdf
 *      external
 *      video
 *      audio
 */
SunGard.MediaTypeIcons = {
    internal: '',
    pdf: '<img alt="PDF file" src="' + rootPath + 'images/common/icons/pdf.gif" width="16" height="16" />',
    external: '<img alt="external link" src="' + rootPath + 'images/common/icons/external.gif" width="14" height="14" />',
    video: '<img alt="video file" src="' + rootPath + 'images/common/icons/video.gif" width="16" height="16" />',
    audio: '<img alt="audio file" src="' + rootPath + 'images/common/icons/audio.gif" width="16" height="16" />'
};

/**
 *  Base Non Flash Control
 */
SunGard.BaseNonFlashControl = '<div class="nonflash"><a href="http://get.adobe.com/flashplayer/"><img alt="Get Adobe&#0174; Flash&#0174; Player" src="' + rootPath + 'images/common/icons/get-flashplayer.gif" width="160" height="41" /></a> <p>It looks like you don&#8217;t have the latest version of the Adobe Flash Player. <em>To view this content, please <a href="http://get.adobe.com/flashplayer/">download the latest player</a>.</em></p></div>';

/**
 *  Flash Video Modal Template
 *      inherits from ModalTemplate (located in sungard.js)
 */
SunGard.ModalTemplate.FlashVideo = Class.create(SunGard.ModalTemplate, {
    // Constructor
    initialize: function($super, data)
    {
        this.type = 'media-link';
        this.canPrint = false;
        
        var header = new Element('h1').update(data.Title);
        this.summary = (data.Summary == '') ? '' : new Element('p').update(data.Summary);
        this.copy = new Element('div', {id: 'copy'}).insert(header).insert(this.summary);
        
        if (data.IsYouTubeVideo) // parse VideoUrl for YouTube ID
        {
            data.VideoUrl = data.VideoUrl.toQueryParams()['v'];
        }
        this.script = '<script type="text/javascript">var flashvars = {isyoutube: "' + data.IsYouTubeVideo + '", omnitureaccount: "' + s_account + '", imagePath: "' + data.PreviewImagePath + '", videoTitle: "' + s.pageName.replace('\'', '%27') + ':' + data.Title.replace('\'', '%27') + '", videoURL: "' + data.VideoUrl + '"}; var params = {menu: "false", quality: "best", scale: "showall", allowFullScreen: "false", allowScriptAccess: "always"}; var attributes = {}; swfobject.embedSWF("' + rootPath + 'flash/common/video-player.swf", "overlay-flash", "464", "261", "9.0.0", "' + rootPath + 'flash/common/express-install.swf", flashvars, params, attributes);</script>';
        this.video = new Element('div', {id: 'overlay-video'}).insert(new Element('div', {id: 'overlay-flash'}).update(SunGard.BaseNonFlashControl));
        
        $super(data);
    },
    
    show: function($super, event)
    {
        // only show this modal (check that IDs match)
        if (event.memo.id != this.id) return;
        
        this.video.insert(this.script);
        this.summary.insert({before: this.video});
        $super();
    },
    
    hide: function($super)
    {
        this.video.remove();
        $super();
    }
});

/**
 *  Flash Audio Modal Template
 *      inherits from ModalTemplate (located in sungard.js)
 */
SunGard.ModalTemplate.FlashAudio = Class.create(SunGard.ModalTemplate, {
    // Constructor
    initialize: function($super, data)
    {
        this.type = 'media-link';
        this.canPrint = false;
        
        var header = new Element('h1').update(data.Title);
        this.summary = (data.Summary == '') ? '' : new Element('p').update(data.Summary);
        this.copy = new Element('div', {id: 'copy'}).insert(header).insert(this.summary);
        
        this.script = '<script type="text/javascript">var flashvars = {audioPath: "' + data.Path + '"}; var params = {menu: "false", quality: "best", wmode: "transparent"}; var attributes = {}; swfobject.embedSWF("' + rootPath + 'flash/common/audio-player.swf", "overlay-flash", "412", "50", "8.0.0", "' + rootPath + 'flash/common/express-install.swf", flashvars, params, attributes);</script>';
        this.audio = new Element('div', {id: 'overlay-audio'}).insert(new Element('div', {id: 'overlay-flash'}).update(SunGard.BaseNonFlashControl));
        
        $super(data);
    },
    
    show: function($super, event)
    {
        // only show this modal (check that IDs match)
        if (event.memo.id != this.id) return;
        
        this.audio.insert(this.script);
        this.summary.insert({before: this.audio});
        $super();
    },
    
    hide: function($super)
    {
        this.audio.remove();
        $super();
    }
});

/**
 *  Forms
 */
SunGard.Forms = Class.create({
    initialize: function()
    {
        if($$('div.Country__c').length == 0) return;

        this.buildElements();
        this.attachEvents();
        this.showFieldsBasedOnCountry(this.countryDropDown);
    },

    buildElements: function()
    {
        this.countryDropDownContainer = $$('div.Country__c')[0];
        this.countryDropDown = $(this.countryDropDownContainer).select('select')[0];
        this.stateDropDown = $$('div.State__c')[0];
        this.provinceDropDown = $$('div.Province__StateOverride')[0];
    },
    
    showFieldsBasedOnCountry: function(target)
    {
        this.hideAll();

        if(target.value.toLowerCase()=='united states of america' || target.value.toLowerCase()=='united states')
        {
            if(this.stateDropDown != null) this.show($(this.stateDropDown));
        }
        if(target.value.toLowerCase()=='canada')
        {
            if(this.provinceDropDown != null) this.show($(this.provinceDropDown));
        }
    },

    attachEvents: function()
    {
        this.countryDropDown.observe('change', this.onChange.bind(this));
    },

    onChange: function(event)
    {
        var target = event.target;
        this.showFieldsBasedOnCountry(target);
    },

    show: function(element)
    {
        element.removeClassName('customHiddenClass');
        element.addClassName('scfDropListBorder');
    },

    hideAll: function()
    {
        if (this.provinceDropDown != null) $(this.provinceDropDown).addClassName('customHiddenClass').removeClassName('scfDropListBorder');
        if (this.stateDropDown != null) $(this.stateDropDown).addClassName('customHiddenClass').removeClassName('scfDropListBorder');
    }

});

/**
 *  Handles resetting form elements
 */
SunGard.ResetForm = Class.create({
    _savedValue: null,

    // Constructor
    initialize: function()
    {
        // only run if reset link exist on page
        this.resetLink = $('reset-wffm');
        if (this.resetLink == null) return;

        this.attachEvents();
    },
    
    // Private Methods
    attachEvents: function()
    {
        this.resetLink.observe('click', this.onClick.bindAsEventListener(this));
    },
    
    onClick: function(event)
    {
        Event.stop(event);
        this.clearForm();
    },

    // Clear ALL fields to be empty (not Form.reset, as that sets it back to the initial form values, which may have been set during page load)
    clearForm: function()
    {
        var form = $('mainform')

        // Clear value if not a hidden field
        var elements = Form.getElements('mainform'); 
        elements.each(function (element) { 
            if (element.type != 'hidden'  && element.type != 'submit')
            {
                if (element.type == 'radio')
                {
                    form.getInputs('radio', element.name)[0].checked = true;
                }
                else if (element.type == 'checkbox')
                {
                    element.checked = false;
                }
                else
                {
                    element.clear();
                }
            }
        });
    },
    resetForm: function()
    {
        Form.reset('mainform');
        $$('.customHiddenClass').each(function(item) {
            if (item.hasClassName('Lead_Contact_ID__c'))
            {
                $(item.select('input')[0]).setValue('');
            }
        });
    }

});

SunGard.UpdateWFFMForms = Class.create({
    // Constructor
    initialize: function()
    {        
        var modalBody = $('modal')
	    if (modalBody != null)
	    {
            try
            {   // Local site
                // Set form height
                parent.SunGard.iFrameHeight.height = document.body.scrollHeight;
            }
            catch(e)
            {   // External site accessing the form, leave height unchanged
                if (window.location.href.include('forms.sungard.com') == false)
                {   
                    // Background should be white
                    modalBody.setStyle({ backgroundColor: '#FFFFFF' });
                    
                    // Input fields should be wider (full width), so add a css class to allow width override
                    var formDiv = modalBody.select('.scfForm')[0];
                    if (formDiv != null)
                    {
                        if (formDiv.hasClassName('scfForm'))
                        {
                            formDiv.addClassName('scfFormExternalSite');
                        }
                    }
                }
            }
        }
    }
}); 

document.observe('dom:loaded', SunGard.init.bind(SunGard));
