﻿// A collection of scripts of use to content folks in putting together subject pages.
// Requires Prototype: <script type="text/javascript" src="/ClientSideScripts/prototype.js"></script>


String.prototype.trim = function() {
  return this.replace(/^\s+|\s+$/g, "");
}; /* from wikipedia (http://en.wikipedia.org/wiki/Trim_(programming)#JavaScript)

/*** utility methods to extend the element ***/
Prototype.Browser.IE6 = Prototype.Browser.IE && parseInt(navigator.userAgent.substring(navigator.userAgent.indexOf("MSIE")+5)) == 6;
Prototype.Browser.IE7 = /MSIE 7/i.test(navigator.userAgent);

check = function(element) {
        return ((typeof(element) != 'undefined') && (element != null));
        }
        
var myUtils = {
    getStyleValue: function(element, styleName) {
        if (window.getComputedStyle) { 
            return Number(element.getStyle(styleName).replace(/\D/g, ''));
        } else {
            return Number(element.currentStyle[styleName.camelize()].replace(/\D/g, '')); }
        },   
    getAllOffsets: function(element) {
        return { 
            'marginTop'    : element.getStyleValue('margin-top'),
            'marginRight'  : element.getStyleValue('margin-right'),
            'marginBottom' : element.getStyleValue('margin-bottom'),
            'marginLeft'   : element.getStyleValue('margin-left'),
            'paddingTop'   : element.getStyleValue('padding-top'),
            'paddingRight' : element.getStyleValue('padding-right'),
            'paddingBottom': element.getStyleValue('padding-bottom'),
            'paddingLeft'  : element.getStyleValue('padding-left'), 
            'borderTop'    : element.getStyleValue('border-top-width'),
            'borderRight'  : element.getStyleValue('border-right-width'),
            'borderBottom' : element.getStyleValue('border-bottom-width'),
            'borderLeft'   : element.getStyleValue('border-left-width')
            }
        }, 
    getHorizontalOffsets: function(element) {
        return { 
            'marginRight'  : element.getStyleValue('margin-right'),
            'marginLeft'   : element.getStyleValue('margin-left'),
            'paddingRight' : element.getStyleValue('padding-right'),
            'paddingLeft'  : element.getStyleValue('padding-left'), 
            'borderRight'  : element.getStyleValue('border-right-width'),
            'borderLeft'   : element.getStyleValue('border-left-width')
            }   
        },
    getVerticalOffsets: function(element) {
        return { 
            'marginTop'    : element.getStyleValue('margin-top', true),
            'marginBottom' : element.getStyleValue('margin-bottom', true),
            'paddingTop'   : element.getStyleValue('padding-top'),
            'paddingBottom': element.getStyleValue('padding-bottom'),
            'borderTop'    : element.getStyleValue('border-top-width'),
            'borderBottom' : element.getStyleValue('border-bottom-width')
            }    
        }, 
    setHeight: function(element, heightInPixels) {
        if (check(element)) { element.style.height = heightInPixels + 'px'; }
        },        
    setWidth: function(element, widthInPixels) {
        if (check(element)) { element.style.width = widthInPixels + 'px'; }
        },
    setTotalHeight: function(element, heightInPixels) {
        if (check(element)) {
            var vOff = element.getVerticalOffsets();
            //alert(Object.toJSON(vOff));
            var p = vOff.paddingTop + vOff.paddingBottom;
                m = vOff.marginTop + vOff.marginBottom;
                b = vOff.borderTop + vOff.borderBottom;
                
            //alert([p, m, b, p+m+b].join(', '));
            element.setHeight(heightInPixels - (p + m + b)); }
        },
    setTotalWidth: function(element, widthInPixels) {
        if (check(element)) {
            var p = element.getStyleValue('padding-left') + element.getStyleValue('padding-right'),
                m = element.getStyleValue('margin-left') + element.getStyleValue('margin-right'),
                b = element.getStyleValue('border-left-width') + element.getStyleValue('border-right-width');
            element.setWidth(widthInPixels - (p + m + b)); }
        }
}

Element.addMethods(myUtils);

/*** Drop Down Menu ***/
function OrvisDropDownMenu(triggerObj, menuObj, isOpen, hideDelay) {
// the trigger is the image, link, div, etc. that you mouse over to display the menu.
this.trigger = $(triggerObj);
// the menu is the div that contains all the menu options.
this.menu = $(menuObj);
// should the menu be open upon load, or closed? True for open, false for closed.
this.hideDelay = hideDelay || 0;
this.delay = null;

// if the menu div isn't valid, abort.
if (!this.menu) { return false; } 

// define the open and close functions.  We use the show() and hide() functions from Prototype.    
this.open = function() { 
    if (this.delay != null) { window.clearTimeout(this.delay); }
    this.menu.show(); 
    //this.detectPosition();
    };
this.close = function() { 
    if (this.hideDelay > 0) {
        this.delay = window.setTimeout("$('" + this.menu.id + "').hide()", this.hideDelay);
    } else { this.menu.hide(); }
    };

// if the menu should be open, open it.  Otherwise close it.  Nothing else needs to be
// specified in the HTML.
if (isOpen) { this.menu.show(); } else { this.menu.hide(); }

// set up the events.  On mouseover of either trigger or menu, open.  On mouseout of either, close.
Event.observe(this.menu, 'mouseover', this.open.bindAsEventListener(this));
Event.observe(this.menu, 'mouseout', this.close.bindAsEventListener(this));
if (this.trigger) { 
    Event.observe(this.trigger, 'mouseover', this.open.bindAsEventListener(this)); 
    Event.observe(this.trigger, 'mouseout', this.close.bindAsEventListener(this)); 
}

// this menu doesn't contain anything fancy like edge detection.  That can be added later on.
this.detectPosition = function() {
    var offset, dimensions, viewsize;
    viewsize = document.viewport.getDimensions();
    offset = this.menu.viewportOffset(); dimensions = this.menu.getDimensions();
    alert('offset:' + Object.toJSON(offset) + ' dimensions:' + Object.toJSON(dimensions));
    alert('viewport:' + Object.toJSON(viewsize));
    if (offset[0] < 0) {
        // too far left?
        alert('too far left');
        };
    if (offset[1] < 0) {
        // too high?
        alert('too far up');
        };
    if ((offset[0] + dimensions.width) > viewsize.width) {
        // too far right?
        alert('too far right');
        };
    if ((offset[1] + dimensions.height) > viewsize.height) {
        // too far down?
        alert('too far down');
        };
    };
}
;

/*
 to create a menu, define it in HTML and specify the names of the trigger element
 (often an image, or a link) and the container element of the menu.
*/
//new OrvisDropDownMenu('myMenu1ImgTrigger', 'myMenu1', blnShouldBeShowingOnLoad, intHideDelayInMilliseconds);
/*
Any fancy highlighting behavior is done in CSS. Suggested Styles for OrvisDropDownMenu:
.dropmenuparentdiv { background-color:white; position:relative; display:block; }
.dropmenudiv{ position:absolute; width: 150px; border:1px #527E38; border-bottom-width: 0; font:normal 11px Arial; line-height:13px; z-index:100; }
.dropmenudiv a{ width: 100%; display: block; text-indent: 3px; border-bottom: 1px solid black; border-top: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; padding: 1px 0; text-decoration: none; font-weight: bold; }
.dropmenudiv a:hover{ background-color: #E6E6CC; }
*/  


/*** Send to a Friend ***/
var EmailControl = function(inputRName, inputREmail, inputSName, inputSEmail, inputPMessage, pfName, pfURL, divDisplay, btnSubmit, btnCancel, btnTrigger) {
    this.rName = $(inputRName); this.rEmail = $(inputREmail);
    this.sName = $(inputSName); this.sEmail = $(inputSEmail);
    this.pMessage = $(inputPMessage);
    this.display = $(divDisplay);
    this.submit = $(btnSubmit);
    this.cancel_button = $(btnCancel);
    this.trigger = $(btnTrigger);
    this.pf_name = pfName; this.url = pfURL;

    this.toggle = function(e) { if (this.display) { 
            if (this.display.visible()) { this.display.hide(); } else { this.display.show(); }
            if (e) { e.stop(); }
        }};
    
    this.handleResponse = function(emailResponse) {
        emailResponse = eval('(' + emailResponse + ')');
        if (emailResponse.Status != "Success") {
            this.display.toggle();
        }
        alert(emailResponse.Message);
    }
    this.sendEmail = function() {
        this.toggle();
        var msg = { ToName:this.rName.value, ToEmail:this.rEmail.value,
                    FromName:this.sName.value, FromEmail:this.sEmail.value,
                    Message:this.pMessage.value, PFName:this.pf_name, URL:this.url + '&adv=1130' };
        //alert(Object.toJSON(msg));
        CallPageService('/ServicePages/EmailService.aspx', 'SendProductEmail', [msg], this.handleResponse.bindAsEventListener(this), FailedCallback, 'JSON');
    };
    
    if (this.trigger) {
        Event.observe(this.trigger, "click", this.toggle.bindAsEventListener(this));
        if (this.display) { this.display.hide(); }        
    }
    
    if (this.submit) {
        Event.observe(this.submit, "click", this.sendEmail.bindAsEventListener(this));
    }
    
    if (this.cancel_button) {
        Event.observe(this.cancel_button, "click", this.toggle.bindAsEventListener(this));
    }
    
} 

/**** Tabs ****/
function OrvisTab(triggerDiv, contentDiv, triggerClasses, contentClasses)
{
    this.tabset = null;
    this.trigger = $(triggerDiv);
    this.content = $(contentDiv);
    this.triggerClasses = this.contentClasses = null;
    if (typeof(triggerClasses) != "undefined") { this.triggerClasses = triggerClasses; }
    if (typeof(contentClasses) != "undefined") { this.contentClasses = contentClasses; }
    this.show = function() { 
        this.content.show(); 
        this.changeClass(this.trigger, this.triggerClasses.defaultClass, this.triggerClasses.chosenClass);
        this.changeClass(this.content, this.contentClasses.defaultClass, this.contentClasses.chosenClass);
        if (this.tabset != null) { this.tabset.hideAllBut(this); }
        this.content.fire("tab:show");
    };
    this.hide = function() { 
        this.content.hide(); 
        this.changeClass(this.trigger, this.triggerClasses.chosenClass, this.triggerClasses.defaultClass);
        this.changeClass(this.content, this.contentClasses.chosenClass, this.contentClasses.defaultClass);
        this.content.fire("tab:hide");
    };   
    this.changeClass = function(div, from, to) {
        if (d = $(div)) {
            if (from != null) { d.removeClassName(from); }
            if (to != null) { d.addClassName(to); }
    }};
    
    this.trigger.tabObj = this;
    this.content.tabObj = this;
    Event.observe(this.trigger, "click", this.show.bindAsEventListener(this));
};

function OrvisTabCSS(defaultClassName, chosenClassName, rowIdPrefix) {
    this.defaultClass = defaultClassName; // when the tab is not chosen, this class is applied.
    this.chosenClass = chosenClassName; // when the tab is chosen, this class is applied.
    this.rowId = rowIdPrefix; // if there are multiple rows, this class will be added.  class='rowClassName_0', rowClassName_1, etc.
};

function OrvisTabSet(arrayOfTabs, containerDiv) 
{
    // define class functions
    this.append = function(tab) {
        if (typeof(tab) != "undefined") {
            this.tabs.push(tab);
            tab.tabset = this;
        }};
    this.remove = function(tab) {
        tab.tabset = null;
        this.tabs = this.tabs.without(tab);
    };
    this.hideAllBut = function(tab) {
        this.tabs.without(tab).invoke('hide');
    };
    // define class properties
    this.containingBlock = $(containerDiv);
    this.tabs = $A(arrayOfTabs) || new Array();
    
    // initialize
    this.tabs.each(function(t) { t.tabset = this; }.bind(this));
    
    // some dynamic layout
    this.sizeTabs = function(fixed, rowheight, gutter, maxcols, outerBlock) {
        var cDim, rows, tabPosition;
        cDim = this.containingBlock.getDimensions(); rows = 0; tabPosition = { left: 0, top: 0 };
        if (fixed == true) // a fixed number of columns always show. Size accordingly.
        {
            var regularWidth = ((cDim.width / maxcols) - gutter), tabsInRow = 0, tabIndex = 0, numTabs = this.tabs.length;
            //alert(this.tabs.length);
            this.tabs.each(function(t) { // set the width and position of each tab.
                t.trigger.addClassName('tabTopPos');
                var offSets = t.trigger.getAllOffsets();
                    tabOffsets = offSets.paddingLeft + offSets.marginLeft + offSets.borderLeft + offSets.paddingRight + offSets.marginRight + offSets.borderRight,
                    tabWidth = regularWidth - tabOffsets; // get style dimensions          
                        
                //alert(['index: ', tabIndex, ' rows: ', rows, ' tabs in row: ', tabsInRow, ' width: ', tabWidth, ' gutter: ', gutter, ' left: ', tabPosition.left, ' top: ', tabPosition.top].join(''));
                if (tabPosition.top > 0) { tabPosition.left += gutter; } // if starting on row other than first, indent.
                t.trigger.style.width = tabWidth + 'px';
                t.trigger.style.position = 'absolute';
                t.trigger.style.left = tabPosition.left + 'px'; 
                t.trigger.style.top = tabPosition.top + 'px';
                t.trigger.addClassName([t.triggerClasses.rowId, rows].join('_'));
                t.trigger.id = (t.triggerClasses.rowId + '_' + rows);
                tabsInRow++; 
                tabIndex++;
                if (tabPosition.top <= 0) { tabPosition.left += gutter; }
                if (tabsInRow >= maxcols) { // if we've gotten to our max tabs in a row, add to the top and reset the left.
                    tabPosition.top += rowheight; tabPosition.left = 0; tabsInRow = 0; rows++; }
                else { // continue in same row.
                    tabPosition.left += regularWidth; 
                }
            });
        } else { // fit as many cols in as we can, of variable widths.
            this.tabs.each(function(t) { // set the width and position of each tab.
                t.trigger.addClassName('tabTopPos');
                var eWidth = Number(t.trigger.getWidth()),
                    offSets = t.trigger.getAllOffsets();
                    tabOffsets = offSets.paddingLeft + offSets.marginLeft + offSets.borderLeft + offSets.paddingRight + offSets.marginRight + offSets.borderRight,
                    tabWidth = eWidth - tabOffsets; // get existing dimensions.
                if (eWidth >= (cDim.width - (tabOffsets + gutter))) { 
                    // it's too big -- it's probably been auto-set by the browser.  Naughty browser!
                    t.trigger.style.width = '50px'; 
                    eWidth = Number(t.trigger.getWidth()); tabWidth = eWidth - tabOffsets;
                }
                if ((eWidth >= cDim.width) && (tabPosition.left == 0)) { // if tab is wider than container, reset tab width.
                    tabWidth = (cDim.width - tabOffsets); }

                if ((tabPosition.left + tabWidth + tabOffsets + gutter) > cDim.width) { // new row if we get too wide.
                    tabPosition.left = ((rows + 1) * gutter); tabPosition.top -= rowheight; rows++; }
                    
                //alert(['actual: ', eWidth, ' tab width: ', tabWidth, ' offsets: ', tabOffsets, ' added: ', eWidth + tabOffsets, ' subtracted: ', cDim.width - tabOffsets, ' gutter: ', gutter, ' left: ', tabPosition.left, ' top: ', tabPosition.top].join(''));
                t.trigger.style.width = tabWidth + 'px';
                t.trigger.style.position = 'absolute';
                t.trigger.style.left = tabPosition.left + 'px';
                t.trigger.style.top = tabPosition.top + 'px';
                t.trigger.addClassName([t.triggerClasses.rowId, rows].join('_'));
                t.trigger.id = (t.triggerClasses.rowId + '_' + rows);
                
                if ((tabPosition.left + tabWidth + tabOffsets + gutter) > cDim.width) { // new row if we get too wide.
                    tabPosition.left = ((rows + 1) * gutter); tabPosition.top -= rowheight; rows++;
                } else { // continue in same row
                    tabPosition.left += (tabWidth + tabOffsets + gutter);
                }

            });
        }
        if (check(outerBlock)) {
            outerBlock.style.marginTop = (outerBlock.getStyleValue('margin-top') + Math.abs(tabPosition.top)) + 'px';
        } else {
            this.containingBlock.style.marginTop = (this.containingBlock.getStyleValue('margin-top') + Math.abs(tabPosition.top)) + 'px';
        }
    }
};

// create a TabSet from a <dl></dl> HTML list in the page.  Degrades more gracefully.
// HTML MUST be in the form [list] [dt] [dd] [dt] [dd], alternating one dt with one dd.
// Still need to provide CSS class names.
function CreateOrvisTabSet(definitionList, triggerClasses, contentClasses) {
    if (dl = $(definitionList)) {
        dts = dl.select('dt.tabTop');
        dds = dl.select('dd.tabBody');
        // dt, dd pairs
        duples = dts.zip(dds);
        tabs = duples.collect(function(pair){ return new OrvisTab(pair[0], pair[1], triggerClasses, contentClasses); });
        return new OrvisTabSet(tabs, dl);   
    }
};


/************* Orvis AJAX Subject Tab *************/

OrvisTab.prototype.getSubject = function(subject_id) {
    var url = window.location.protocol + '//' + window.location.hostname + '/intro.aspx';
    var qs = window.location.search.toQueryParams();
    qs.newwindow = 'true';
    qs.subject = subject_id;

    new Ajax.Updater(this.content, url, { method: 'get', parameters: qs });    
};


/********** Slider / Filmstrip Presentation ************/

function OrvisFilmstrip(slidingDiv, upTrigger, rightTrigger, downTrigger, leftTrigger, verticalJump, horizontalJump) {

    if (slidingDiv == '') { return; }

    this.move = function(direction, howFar) {
        if (this.view == null) { 
            this.view = this.container.parentNode.getDimensions(); }
        if (this.extent == null) {
            this.extent = this.container.getDimensions(); }
        if (this.end == null) { 
            this.end = { 
            left: this.home.left + (0 - (this.extent.width - this.view.width)), 
            top: this.home.top + (0 - (this.extent.height - this.view.height))
            };
        }
        
        var current = this.container.positionedOffset();
        var doMove = { x: 0, y: 0, mode: 'relative' };
        switch(direction)
        {
            case 'up':
            doMove.x = 0;
            doMove.y = 0 - howFar;
            if (current.top + doMove.y < this.end.top) { 
                // don't shift too far "forward". If trying 
                // to move up (north) past our
                // end position, set it to end coords.
                doMove.x = current.left;
                doMove.y = this.end.top;
                doMove.mode = 'absolute';
            }
            break;
            
            case 'right':
            doMove.x = howFar;
            doMove.y = 0;
            if (current.left + doMove.x > this.home.left) { 
                // don't shift too far "back". If trying 
                // to move to the right (west) past our
                // initial position, set it to home coords.
                doMove.x = this.home.left;
                doMove.y = current.top;
                doMove.mode = 'absolute';
            }
            break;
            
            case 'down':
            doMove.x = 0;
            doMove.y = howFar;
            if (current.top + doMove.y > this.home.top) { 
                // don't shift too far "back". If trying 
                // to move down (south) past our
                // initial position, set it to home coords.
                doMove.x = current.left;
                doMove.y = this.home.top;
                doMove.mode = 'absolute';
            }
            break;
            
            case 'left':
            doMove.x = 0 - howFar;
            doMove.y = 0;
            if (current.left + doMove.x < this.end.left) { 
                // don't shift too far "forward". If trying 
                // to move left (east) past our
                // end position, set it to end coords.
                doMove.x = this.end.left;
                doMove.y = current.top;
                doMove.mode = 'absolute';
            }
            break;
            
            case 'home':
            doMove.x = this.home.left;
            doMove.y = this.home.top;
            doMove.mode = 'absolute';
            break;
            
            case 'end':
            doMove.x = this.end.left;
            doMove.y = this.end.top;
            doMove.mode = 'absolute';
        };
        new Effect.Move(this.container, doMove);
        this.container.fire(this.container.id + ":move", doMove);
    }

    this.container = $(slidingDiv); 
    if (!check(this.container)) { return; }
    
    this.home = this.container.positionedOffset();
    this.view = null; // must be set after load.
    this.extent = null; // must be set after load.
    this.end = null; // must be set after load.
    this.moveH = horizontalJump;  this.moveV = verticalJump;
    
    if (upTrigger != '') { this.north = $(upTrigger); }
    if (rightTrigger != '') { this.east = $(rightTrigger); }
    if (downTrigger != '') { this.south = $(downTrigger); }
    if (leftTrigger != '') { this.west = $(leftTrigger); }
    
    if (check(this.north)) { 
        Event.observe(this.north, "click", 
        function() { this.move('up', this.moveV); }.bindAsEventListener(this)); }
    if (check(this.east)) { 
        Event.observe(this.east, "click", 
        function() { this.move('right', this.moveH); }.bindAsEventListener(this)); }
    if (check(this.south)) { 
        Event.observe(this.south, "click", 
        function() { this.move('down', this.moveV); }.bindAsEventListener(this)); }
    if (check(this.west)) { 
        Event.observe(this.west, "click", 
        function() { this.move('left', this.moveH); }.bindAsEventListener(this)); }
    
    return this;
}

/*******************************************************/
/*** Sprites and Rollovers ***/

var OrvisSprite = function(element, baseCoords, rolloverCoords, eventToggles) {
     var e = $(element);
     if (!check(e)) { return; }
     e.move = function(coords) {
        this.style.left = coords.x + 'px';
        this.style.top = coords.y + 'px';
     }
     //baseCoords.mode = rolloverCoords.mode = 'absolute';
     e.spriteCoords = baseCoords;
     if (rolloverCoords != null) { 
         e.spriteRolloverCoords = rolloverCoords;
         if (e.spriteCoords.x != e.spriteRolloverCoords.x || e.spriteCoords.y != e.spriteRolloverCoords.y) {
            if (!check(eventToggles)) { eventToggles = { on: "mouseover", off: "mouseout" }; }
            Event.observe(e, eventToggles.on, function() { this.move(this.spriteRolloverCoords); }.bindAsEventListener(e));
            Event.observe(e, eventToggles.off, function() { this.move(this.spriteCoords); }.bindAsEventListener(e));
         }
    }
    e.move(e.spriteCoords);    
}

/*
coords: { x: 0, y: 0 }
eventToggles: { on: "mouseover", off: "mouseout" }
*/

/*******************************************************/
/*** Flash Object Generation ***/
/*
** P. Rutins January 2010
** movieElement: the HTML DOM object that is the flash player, or the name of it.
** usePrefs: true or false - should we read and write preferences from/to cookies? Volume only.
** onStartMovie: the name of the event that should be raised when a movie is started.
** onFinishMovie: the name of the event that should be raised when a movie has been played all the way through.
** onStopMovie: the name of the event that should be raised when a movie is stopped.
*/

var OrvisFlash = function(movieElement, usePrefs, onStartMovie, onFinishMovie, onStopMovie) {
    this.flashObj = $(movieElement);
    this.canPlay = function() { return (check(this.flashObj) && check(this.flashObj.playVideo)); };
    this.changePlayer = function(flashPlayerFile, flashVarList) {
        console.log('using reduced functionality.');
        try {
            // we fire stop and start events because if we're here, the player 
            // can't communicate via javascript.  Note that the finish event will never happen
            // unless we set the percent played to 100 manually so it ALWAYS happens.
            if (this.flashObj.movieName && this.flashObj.movieName != '') { this.fireStopEvent(this.flashObj.movieName + '_old_player'); }
            this.flashObj.LoadMovie(0, flashPlayerFile);
            this.setVariables(flashVarList);
            if (this.flashObj.movieName && this.flashObj.movieName != '') { this.fireStartEvent(this.flashObj.movieName + '_old_player'); }
            return true;
        } catch(e) { return false; /* couldn't get a handle on the flash player */ }
    };
    this.changeMovie = function(flashMovieName, flashVarList) { 
        // make sure we really have a flash movie object and can play something
        if (!this.canPlay()) { return false; }        
        var prevMovie = this.whatMovie();
        if (this.isPaused()) { this.playPause(); 
            if (prevMovie == flashMovieName) { return false; }
        } // if paused, start it again instead.
        // hook to check how much has played, 
        // then trigger event for coremetrics conversion event.
        // pass a function in on the constructor to do this.
        //this.fireStopEvent(prevMovie, null) -- the flash object now does this call.
        //this.fireStartEvent(flashMovieName); -- the flash object now does this call.
        this.flashObj.playVideo(flashMovieName);
        this.setVariables(flashVarList);
        // only set the volume, etc. if we're loading the first movie. Otherwise
        // use the current player's settings.  We'll save on page unload.
        if (usePrefs == true && prevMovie == null) { this.setPrefs(); }
    };
    this.setVariables = function(flashVarList) {
        $H(flashVarList).each(function(nv){
            if (check(eval('this.' + nv.key))) {
                eval('this.' + nv.key + '("' + nv.value + '")');
            }
        }, this.flashObj);
    };
    
    this.whatMovie = function() { if (check(this.flashObj.whatMovie)) { return this.flashObj.whatMovie(); }}
    
    this.toggleMuted = function() { if (check(this.flashObj.muteVideo)) { this.flashObj.muteVideo(); }};
    this.mute = function() { if (this.getVolume() > 0) { this.toggleMuted(); }};
    this.unmute = function() { if (this.getVolume() == 0) { this.toggleMuted(); }};
    this.getVolume = function() { return (check(this.flashObj.getVolume)) ? this.flashObj.getVolume() : 90; };
    this.setVolume = function(vol) { 
        if (vol > 0) { this.unmute(); } else { this.mute(); }
        if (check(this.flashObj.setTheVolume)) { this.flashObj.setTheVolume(vol); }
    };
    
    this.playPause = function() { if (this.flashObj.pauseResume) { this.flashObj.pauseResume(); }};
    this.isPaused = function() { return (check(this.flashObj.isPaused) ? this.flashObj.isPaused() : false); };
    this.percentPlayed = function() { 
        if (this.flashObj.percentagePlayed) { 
            return this.flashObj.percentagePlayed(); 
        } else { return 0; }
    }

    // fire events -- handlers can be assigned at any point.
    this.fireStopEvent = function(movieName, pctPlayed) {
        if (movieName == null) { movieName = this.whatMovie(); }
        if (pctPlayed == null) { pctPlayed = this.percentPlayed(); }        
        this.flashObj.fire("movie:stopped", {"movieName":movieName, "pctPlayed":pctPlayed, "nextEvent":onStopMovie}, true);
        if (pctPlayed > 90) { this.fireFinishEvent(movieName); }}
    this.fireStartEvent = function(movieName){
        if (movieName == null) { movieName = this.whatMovie(); }
        this.flashObj.fire("movie:started", {"movieName":movieName, "nextEvent":onStartMovie}, true);}
    this.fireFinishEvent = function(movieName){
        if (movieName == null) { movieName = this.whatMovie(); }
        this.flashObj.fire("movie:finished", {"movieName":movieName, "nextEvent":onFinishMovie}, true);}

    this.savePrefs = function() {
        // save mute value to cookie for session; use only volume, as it is 0 if muted.
        var vol = this.getVolume();
        document.cookie = "FP=vol=" + vol + ";expires=;path=/";
    };
    this.getPrefs = function() {
        var ca = $A(document.cookie.split(';'));
        // ["FP=mute=1,vol=90", ...] (except not storing mute key.)
        var fp; fp = ca.find(function(c){ return c.trim().startsWith('FP='); });
        // "FP=mute=1,show=1" -> "mute=1,vol=90"
        if (fp == null) { return; }
        fp = new String(fp).trim(); fp = fp.slice(3, fp.length);
        //alert(fp);
        // break it into key/value pairs
        var kv = fp.parseQuery(',');
        return kv;
    };
    this.setPrefs = function() {
        try {
            var prefs; prefs = this.getPrefs();
            if (check(prefs)) {
                this.setVolume(prefs.vol);
            }
        }
        catch(e) { alert(e.message); }
        return this.getVolume();
    };
    
    if (usePrefs == true) {
        Event.observe(window, "unload", function(){ this.savePrefs(); }.bindAsEventListener(this));
    }
};

/*******************************************************/
