/// <reference path="../../ScriptReference/jquery-1.7.1-vsdoc.js" />
/// <reference path="../../Scripts/jquery.enableTouch.js"/>
/// <reference path="../../Scripts/Mediasite.Core.js"/>
/// <reference path="../../Scripts/Mediasite.Geometry.js"/>
/// <reference path="../../Scripts/Mediasite.Player.Core.js"/>
/// <reference path="../../Scripts/Mediasite.Player.Localization.js"/>
/// <reference path="../../Scripts/SlideNav.js"/>
/// <reference path="../../Scripts/SlideInspector.js"/>
/// <reference path="../../Scripts/SpriteAnimation.js"/>

Mediasite.Player.NewStandardView = function (playerContext) {
    var self = this;
    //UpdateMediaInfo: function (mediaInfo) { },
    //UpdateMediaState: function (state) { },
    //UpdateMediaVolume: function (volume) { },
    //UpdatePlaybackRate: function (rateInfo) { },
    //UpdateOptions: function (options) { },
    //UpdateSlideBrowserView: function (view) { },      
    //InactivityExceeded: function () { },
    //SendQuestionComplete: function (success, message) { },
    //SendEmailComplete: function (success, message) { },
    //ToggleSlideText: function () { },
    //ToggleSlideBrowser: function () { },

    var selectors = {
        titleArea: '#titleArea',
        contentArea: '#contentArea',
        slideBox: '.stage-slideBox',
        slideInspector: '#inspector',
        slidePreview: '#slidePreview',
        videoBox: '.stage-videoBox',
        videoThumbContainer: '#videoThumbContainer',
        contentFramer: '.contentFramer',
        positionSlider: '#positionSlider',
        positionSliderHandle: '#positionSlider .ui-slider-handle',
        currentPosition: '#currentPosition',
        livePosition: '#live-position-text',
        duration: '#duration',
        controlBar: '#control-bar',
        controlsMiddle: '#controls-middle',
        controlsLeft: '#controls-left',
        controlsRight: '#controls-right',
        controlBarButtons: '#control-bar button',
        playPauseButton: '#playPauseButton',
        playStopButton: '#playStopButton',
        skipBackButton: '#skipBackButton',
        mediasiteSwirlButton: '#mediasite-swirl a',
        layoutButtons: '.stage-layoutControls button',
        pipButton: '.stage-pipButton',
        sideBySideButton: '.stage-sideBySideButton',
        fullFrameButton: '.stage-fullFrameButton',
        captionButton: '#captionButton',
        searchButton: '#searchButton',
        fidelityIndicator: '#fidelityIndicator',
        volumeButton: '#volumeButton',
        pollsButton: '#pollsButton',
        askButton: '#askButton',
        emailButton: '#emailButton',
        linksButton: '#linksButton',
        chaptersButton: '#chaptersButton',
        swapButton: '.stage-swapButton',
        infoPanel: '#infoPanel',
        captionPanel: '#captionPanel',
        searchPanel: '#searchPanel',
        askPanel: '#askPanel',
        emailPanel: '#emailPanel',
        linksPanel: '#linksPanel',
        chaptersPanel: '#chaptersPanel',
        infoButton: '#infoButton',
        presentationTitle: '#presentationTitle',
        closeDetailPanelButton: '#detailPanels .closePanelButton',
        closeInteractivityPanelButton: '#interactivityPanels .closePanelButton',
        helpButton: '#helpButton',
        mediaStateText: '.mediaState p',
        mediaStateDiv: '#mediaState',
        mediaStateStandalone: '#mediaStateStandalone',
        speedButton: '#playSpeedButton',
        buttonDivider: '.buttonDivider',
        broadcastingIndicator: '#broadcasting-indicator',
        volume: '#volumeButton',
        muteWrapper: '#ui-playervolume-mute-wrapper',
        unmuteWrapper: '#ui-playervolume-unmute-wrapper',
        volumeSlider: '#ui-playervolume-slider',
        panelStylesheet: 'link[rel="stylesheet"][href*="Panel"]',

        infoPanelCloseButton: "#infoPanel .closePanelButton",
        searchPanelCloseButton: "#searchPanel .closePanelButton",
        askPanelCloseButton: "#askPanel .closePanelButton",
        emailPanelCloseButton: "#emailPanel .closePanelButton",
        linksPanelCloseButton: "#linksPanel .closePanelButton",
        chaptersPanelCloseButton: "#chaptersPanel .closePanelButton"
    };

    var classes = {
        popup: 'popupPanel'
    };

    var detailPanels = {
        None: 'None',
        Info: 'Info',
        Caption: 'Caption',
        Search: 'Search'
    };

    var interactivityPanels = {
        None: 'None',
        Polls: 'Polls',
        Ask: 'Ask',
        Email: 'Email',
        Links: 'Links'
    };

    var _presentation;
    var slideStream;
    var _slidePartitions;
    var _currentSlide;
    var _currentPosition;
    var _mediaState;
    var pollsWindow;
    var stage, slideNav, slideInspector, slidePreview, slidePreviewAnimation, broadcastingIndicator;
    var mediaDuration = 0;
    var sliderMaxValue = 10000;
    var positionChanging;
    var _currentDetailPanel = detailPanels.None;
    var _currentInteractivityPanel = interactivityPanels.None;
    var isCCHidden = true;
    var fadeSpeed = 'normal';
    var helpWindow;
    var _defaultAspect = 4 / 3;
    var _isIOS = Mediasite.BrowserDetect.IOS();
    var _isAndroid = Mediasite.BrowserDetect.Android();
    var _usePopupPanels = !!_isAndroid;  // Put interactivity panels in a new window
    var _currentPopupWindow = null;
    var _livePresentationHasEnded = false;
    var _mediaInfo = {};
    var _audioOnly = false;
    var _mediaEnded = false;
    var streamViewHandlers = [];
    var captionPanel;

    var _events = new Mediasite.Player.DisableableEventBundle();
    var _eventNames = Mediasite.Player.ViewEvent;
    var _layoutFeature = new Mediasite.Player.FeatureAccess();
    _layoutFeature.item = {
        HeaderArea: 'HeaderArea',
        ViewDateTime: 'ViewDateTime',
        FidelityIndicator: 'FidelityIndicator',
        SofoBranding: 'SofoBranding',
        MainControls: 'MainControls',
        SlideNavigation: 'SlideNavigation'
    };

    var _muteUnmuteButtonClicked = false;
    var _panelFocusResetter = null;

    // jump navigation helper used when navigating with the bracket/shift-bracket/ctrl-bracket keyboard commands
    var _jumpNavigationHelper = new Mediasite.Player.Navigation.JumpNavigationHelper();

    function setupPanelFocusResetter() {

        // This collection is used by PanelFocusResetter to associate a panel, the button that opened it, and the panels close button.  
        // PanelFocusResetter can use this information to know if a focused element is within one of the panels when they are being 
        // closed in order to determine how focus should be reset.

        var panelButtonAndElements = [
            {
                panelButton: $(selectors.infoButton),
                panelElement: $(selectors.infoPanel),
                panelCloseButton: $(selectors.infoPanelCloseButton)
            },
            {
                panelButton: $(selectors.searchButton),
                panelElement: $(selectors.searchPanel),
                panelCloseButton: $(selectors.searchPanelCloseButton)
            },
            {
                panelButton: $(selectors.askButton),
                panelElement: $(selectors.askPanel),
                panelCloseButton: $(selectors.askPanelCloseButton)
            },
            {
                panelButton: $(selectors.emailButton),
                panelElement: $(selectors.emailPanel),
                panelCloseButton: $(selectors.emailPanelCloseButton)
            },
            {
                panelButton: $(selectors.chaptersButton),
                panelElement: $(selectors.chaptersPanel),
                panelCloseButton: $(selectors.chaptersPanelCloseButton)
            },
            {
                panelButton: $(selectors.linksButton),
                panelElement: $(selectors.linksPanel),
                panelCloseButton: $(selectors.linksPanelCloseButton)
            }
        ];

        _panelFocusResetter = new Mediasite.Player.PanelFocusResetter(panelButtonAndElements);
    }

    function setupDisabledFeatures() {
        _events.disableCommonViewEvents(playerContext.PlayerLayoutOptions, playerContext.CurrentPresentation, _mediaInfo);

        _layoutFeature.disable(_layoutFeature.item.ViewDateTime, playerContext.PlayerLayoutOptions.ShowDateTime === false);
        _layoutFeature.disable(_layoutFeature.item.FidelityIndicator, playerContext.PlayerLayoutOptions.AllowFidelityIndicator === false);
        _layoutFeature.disable(_layoutFeature.item.HeaderArea, playerContext.PlayerLayoutOptions.ShowHeaderArea === false);
        _layoutFeature.disable(_layoutFeature.item.SofoBranding, playerContext.PlayerLayoutOptions.EnableSofoBranding === false);
        _layoutFeature.disable(_layoutFeature.item.MainControls, playerContext.PlayerLayoutOptions.ShowMainControls === false);
        _layoutFeature.disable(_layoutFeature.item.SlideNavigation, playerContext.PlayerLayoutOptions.AllowScrubbing === false || playerContext.PlayerLayoutOptions.ShowSlideNavigation === false);
    }

    this.AddEventHandler = function (eventName, handler) {
        _events.addHandler(eventName, handler);
    };

    _carouselSizes = {
        Small: 'Small',
        Medium: 'Medium',
        Large: 'Large'
    };

    // #region Player options
    // Default Values for Player Options
    setOptionDefault('SlideAspect', '4:3');
    setOptionDefault('VideoAspect', '4:3');
    setOptionDefault('SideBySideSecondarySize', Mediasite.Player.StageSideBySideSecondarySize.Medium);
    setOptionDefault('PipSize', Mediasite.Player.StagePipSize.Standard);
    setOptionDefault('SlideCarouselSize', _carouselSizes.Medium);
    setOptionDefault('HideDateTime', false);

    function setOptionDefault(optionKey, defaultValue) {
        var value = playerContext.PlayerLayoutOptions[optionKey];
        if (typeof value === 'undefined' || typeof value === 'null') {
            playerContext.PlayerLayoutOptions[optionKey] = defaultValue;
        }
    }

    // #endregion

    function getAspectRatio(aspectString) {
        var components = aspectString.split(':');
        if (components.length === 2) {
            return parseInt(components[0], 10) / parseInt(components[1], 10);
        }

        return _defaultAspect; // parse error
    }

    function setInitialStageLayout() {
        setStageLayoutType(getStageLayoutTypeForInitialLayoutOption(playerContext.PlayerLayoutOptions.FullInitialLayout));
    }

    this.SlideStreamType = Mediasite.ContentStreamType.Slide;

    this.DismissPanels = function () {
        if ((_currentInteractivityPanel != interactivityPanels.None) || (_currentDetailPanel != detailPanels.None)) {

            var detailPanelClosingType = null;
            var interactivityPanelClosingType = null;

            // Determine what the panelClosingType is for detailPanel and interactivityPanel.  These will tell 
            // PanelFocusResetter how to figure out what element should be focused when a panel or panels are closed

            if ((_currentInteractivityPanel != interactivityPanels.None) && (_currentDetailPanel != detailPanels.None)) {

                // If both panels are closing, we only need invoke PanelFocusResetter once with the type AllClosed
                detailPanelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.AllClosed;

            } else if (_currentInteractivityPanel != interactivityPanels.None) {
                interactivityPanelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.OneClosedNoneStillOpen;
            } else if (_currentDetailPanel != detailPanels.None) {
                detailPanelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.OneClosedNoneStillOpen;
            }

            // Now call the appropriate functions to close the appropriate panels
            // no need to pass in a 'clickType'

            if (_currentInteractivityPanel != interactivityPanels.None) {
                setCurrentInteractivityPanel(interactivityPanels.None, interactivityPanelClosingType, Mediasite.Player.PanelFocusResetter.ClickType.KeyPress);
            }
            if (_currentDetailPanel != detailPanels.None) {
                setCurrentDetailPanel(detailPanels.None, detailPanelClosingType, Mediasite.Player.PanelFocusResetter.ClickType.KeyPress);
            }
        }
    };

    this.LoadLayout = function () {

        jQuery.fx.interval = _isIOS ? 50 : jQuery.fx.interval; // the default 13ms is way too quick for some devices.

        updateBodyClasses();

        stage = new Mediasite.Player.StageControl(selectors.contentArea, selectors.slideBox, selectors.videoBox, selectors.slidePreview, undefined, playerContext.PlayerLayoutOptions);
        stage.setSlideAspect(getAspectRatio(playerContext.PlayerLayoutOptions.SlideAspect));
        stage.setVideoAspect(getAspectRatio(playerContext.PlayerLayoutOptions.VideoAspect));
        stage.setPrimaryContentElement(playerContext.PlayerLayoutOptions.PrimaryContent);
        stage.setVideoSide(playerContext.PlayerLayoutOptions.VideoPosition);

        if (!_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) {
            slideNav = new Mediasite.Player.SlideNav($('#slide-navigator'), function (number, width, height) {
                if (!_presentation) {
                    return null;
                }

                var aspect = (height > 0) ? width / height : 4 / 3;

                return slideStream.SlideUrlProvider.GetCacheFriendlySlideUrl(number, height, aspect);
            });
            slideNav.getElement().bind({
                'seek': function (e, data) { _events.fire(_eventNames.PositionChanged, data.position); },
                'beginPreview': slideNav_beginPreview,
                'endPreview': slideNav_endPreview
            });
            slideNav.getElement().enableTouch();
        }

        slideInspector = new Mediasite.Player.SlideInspector($(selectors.slideInspector));

        if (!_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) {
            slidePreview = new Mediasite.Player.SlidePreviewControl($(selectors.slidePreview));
            slidePreview.setSlideAspect(getAspectRatio(playerContext.PlayerLayoutOptions.SlideAspect));
            slidePreview.getElement().bind('slidePreviewInitiated', slidePreview_slidePreviewInitiated);

            slidePreviewAnimation = new Mediasite.Player.SlidePreviewAnimation($('body'));
        }

        broadcastingIndicator = new Mediasite.SpriteAnimation($(selectors.broadcastingIndicator), { spriteWidth: 32, totalFrames: 5, frameDuration: 750 });

        // #region Hide panels
        $(selectors.infoPanel).hide();
        $(selectors.searchPanel).hide();
        $(selectors.askPanel).hide();
        $(selectors.emailPanel).hide();
        $(selectors.linksPanel).hide();
        $(selectors.chaptersPanel).hide();
        // #endregion

        var makeFramePart = function (cssClass) {
            return $('<div />').addClass(cssClass);
        };

        // Add borders to slide and video areas.
        $(selectors.contentFramer).append(makeFramePart('left')).append(makeFramePart('top')).append(makeFramePart('right')).append(makeFramePart('bottom'));


        // When stage size changes, inform children
        $(selectors.contentArea).bind('stageresize', function (evt) {
            evt.stopPropagation();

            $(selectors.slideInspector).trigger('containerresize');
        });

        setupDisabledFeatures();
        setupControls();

        setBroadcastingIndicatorTooltip(Mediasite.Player.Localization.LiveIndicator.WaitingTooltip);

        if (playerContext.GlobalOptions.IsLayoutPreview) { // but for presentation playback, wait until media element is loaded
            setInitialStageLayout(); // must happen after setupControls() call so that stage layout buttons exist.
        }

        // Set full screen banner
        if (playerContext.PlayerLayoutOptions.Images && playerContext.PlayerLayoutOptions.Images.FullScreenBanner) {
            var titleArea = $(selectors.titleArea);
            titleArea.css({
                "background-image": "url('" + playerContext.PlayerLayoutOptions.Images.FullScreenBanner.ImageFilename + "')"
            });
            if (playerContext.PlayerLayoutOptions.Images.FullScreenBanner.ImageUrl != "") {
                imageAnchor = $(document.createElement('a'));
                imageAnchor.attr("href", playerContext.PlayerLayoutOptions.Images.FullScreenBanner.ImageUrl);
                imageAnchor.attr("title", playerContext.PlayerLayoutOptions.Images.FullScreenBanner.ImageUrl);
                imageAnchor.attr("target", "_blank");
                imageAnchor.hover( // TODO: refactor into CSS file
                  function () {
                      titleArea.css('filter', 'alpha(opacity=100)');
                      titleArea.css('opacity', '1.0');
                  },
                  function () {
                      titleArea.css('filter', 'alpha(opacity=80)');
                      titleArea.css('opacity', '0.8');
                  }
                );
                imageAnchor.css({
                    "display": "block",
                    "width": playerContext.PlayerLayoutOptions.Images.FullScreenBanner.Width,
                    "height": playerContext.PlayerLayoutOptions.Images.FullScreenBanner.Height,
                    "margin": "0 auto"
                });
                imageAnchor.appendTo(titleArea);
            }
        } else {
            $(selectors.titleArea).css('visibility', 'hidden'); // TODO: remove opacity from #titleArea in CSS, only set opacity on #titleArea a; add themed background color to #titleArea A
        }

        if (playerContext.PlayerLayoutOptions.Images && playerContext.PlayerLayoutOptions.Images.VideoThumb) {
            var img = $('<img />').attr({
                'src': playerContext.PlayerLayoutOptions.Images.VideoThumb.ImageFilename,
                'alt': '' // TODO: Better alt text?
            });
            $(selectors.videoThumbContainer).empty().append(img);
        }

        if (playerContext.PlayerLayoutOptions.Images && playerContext.PlayerLayoutOptions.Images.DefaultSlide) {
            showOptionImageAsSlide(playerContext.PlayerLayoutOptions.Images.DefaultSlide);
        }

        updateLayout();
        $(window).bind('resize', updateLayout);
        if (_usePopupPanels) {
            $(window).bind('beforeunload', clearInteractivityPopupWindow);
        }

    };

    this.GetStreamViewHandler = function (streamViewHandlerOptions) {

        if (streamViewHandlers.length == 2) return undefined;

        var streamViewHandler = undefined;
        if (streamViewHandlerOptions.DisplayContent == Mediasite.ContentType.Video) {
            streamViewHandler = new Mediasite.Player.StreamViewHandler(
            {
                MediaContainer: $('#mediaElementArea'),
                UpdateCurrentSlide: function () { },
                AddNewSlide: function () { }
            });
            streamViewHandlers.push(streamViewHandler);
        }

        if (streamViewHandlerOptions.DisplayContent == Mediasite.ContentType.Slide) {
            this.SlideStreamType = streamViewHandlerOptions.StreamType;
            streamViewHandler = new Mediasite.Player.StreamViewHandler(
            {
                MediaContainer: $(selectors.slideInspector),
                UpdateCurrentSlide: self.UpdateCurrentSlide,
                AddNewSlide: self.AddNewSlide
            });
            streamViewHandlers.push(streamViewHandler);
        }

        return streamViewHandler;
    };

    this.ShowErrorMessage = function (message, details) {

        if (playerContext.GlobalOptions.ErrorPage && playerContext.GlobalOptions.ErrorPage.length > 0) {
            var errorPage = playerContext.GlobalOptions.ErrorPage;
            window.location = errorPage;
        }
        else {
            $('#MessageDisplay').messagedisplay(
                {
                    title: message,
                    message: details,
                    width: '400px',
                    modal: false,
                    allowClose: false,
                    dialogClass: 'errorAlertContainer'
                });
        }
    };

    this.UpdateSlideStream = function (stream) {
        slideStream = stream;
    }

    this.UpdatePresentationData = function (modelPresentation) {
        _presentation = modelPresentation;

        slideStream = _presentation.GetStream(this.SlideStreamType);

        if (!_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation) && slideStream) {
            slidePreview.setSlideUrlProvider(slideStream.SlideUrlProvider);
        }

        updateControls();
        updateLayoutButtonStates();
        updateBodyClasses();
        updateLayout();

        $(selectors.infoPanel).playerinfopanel({ presentation: _presentation, onChapterChanged: onChapterChanged, defaultPresenterImageSrc: playerContext.PlayerLayoutOptions.Images.DefaultPresenterImage ? playerContext.PlayerLayoutOptions.Images.DefaultPresenterImage.ImageFilename : '', hideDateTime: _layoutFeature.isDisabled(_layoutFeature.item.ViewDateTime), privacyPolicyUrl: playerContext.GlobalOptions.PrivacyPolicyUrl });
        $(selectors.searchPanel).playersearchpanel({ presentation: _presentation, disableCaptionDisplay: _presentation.DisableCaptionDisplay, onSearch: onSearch, onCaptionClick: onCaptionClick });
        captionPanel = new Mediasite.Player.CaptionPanel($(selectors.captionPanel));
        $(selectors.chaptersPanel).playerchapterspanel({ chapters: _presentation.Chapters, onChapterChanged: onChapterChanged });
        $(selectors.linksPanel).playerlinkspanel({ links: _presentation.Links });

        fixSlideTitles();

        if (!_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation) && hasSlides()) {
            _slidePartitions = new Mediasite.Player.SlidePartitions(slideStream.Slides);
            _slidePartitions.bind('currentpagechanged', slidePartitions_currentpagechanged);
            slideNav.setSlides(_slidePartitions.getCurrentPageItems());
        }

        //Determine if slides should be hidden based on the content or feature       
        if (!playerContext.GlobalOptions.IsLayoutPreview && !_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) {
            _layoutFeature.disable(_layoutFeature.item.SlideNavigation, !hasSlides());
        }

        if (playerContext.PlayerLayoutOptions.Images && playerContext.PlayerLayoutOptions.Images.FullScreenBanner) {
            $(selectors.titleArea).attr({
                "alt": _presentation.Title,
                "title": _presentation.Title
            });
        }

        if (playerContext.PlayerLayoutOptions.Images) {

            if (_presentation.PlayStatus === Mediasite.Player.PresentationStatus.ScheduledForLive ||
            _presentation.PlayStatus === Mediasite.Player.PresentationStatus.OpenForLive) {

                showOptionImageAsSlide(playerContext.PlayerLayoutOptions.Images.WaitingForPresentationSlide);
            }
        }

        $(document).bind("keyup", function (event) {
            var viewEvent = Mediasite.Player.ViewEvent.fromKeyEvent(event);
            if (viewEvent) {
                event.preventDefault();

                var eventData = {};

                if (viewEvent == Mediasite.Player.ViewEvent.NextSlide) {
                    nextSlide();
                    return;
                }

                if (viewEvent == Mediasite.Player.ViewEvent.PreviousSlide) {
                    previousSlide();
                    return;
                }

                if (_jumpNavigationHelper.isJumpViewEvent(viewEvent)) {
                    if (!playerContext.CurrentPresentation.IsLivePresentation()) {
                        var newPosition = _jumpNavigationHelper.getJumpTime(viewEvent, _currentPosition, playerContext.CurrentPresentation.Duration, playerContext.CurrentPresentation.Chapters);
                        _events.fire(Mediasite.Player.ViewEvent.PositionChanged, newPosition);
                        _currentPosition = newPosition;
                    }
                    return;
                }

                _events.fire(viewEvent, eventData);
            }
        });

        //Once the presentation data has been loaded we can provide some fake data
        //to get the player stage to display according to the layout options.
        //When the media is actually loaded UpdateMediaInfo will be called again
        //to tweak the display based on further information from the media itself - MSL
        var fakeMediaInfo = { AudioOnly: false, Duration: 0 };
        this.UpdateMediaInfo(fakeMediaInfo);
        this.UpdateMediaState(Mediasite.Player.MediaState.Waiting);
        showVideoThumb();
    };

    this.UpdateCurrentSlide = function (slide) {

        if (!hasSlides()) return;

        _currentSlide = slide;

        if (slide.Number < 1) {
            if (playerContext.PlayerLayoutOptions.Images && playerContext.PlayerLayoutOptions.Images.DefaultSlide) {
                showOptionImageAsSlide(playerContext.PlayerLayoutOptions.Images.DefaultSlide);
            }
            return;
        }

        var slideImage = new Mediasite.Player.SlideImage(slide.Number, slideStream.SlideUrlProvider);
        var tooltip = (slide.Text != "") ? slide.Text : Mediasite.Player.Localization.Common.Slide + " " + slide.Number;

        showSlide(slideImage, '', tooltip);
    };

    function nextSlide() {
        if (_currentSlide) {
            if (_currentSlide.Number == slideStream.Slides.length) return;
            var slideTime = slideStream.Slides[_currentSlide.Number].Time;
            _events.fire(Mediasite.Player.ViewEvent.PositionChanged, slideTime);
        }
    }

    function previousSlide() {
        if (_currentSlide) {
            if (_currentSlide.Number - 2 < 0) return;
            var slideTime = slideStream.Slides[_currentSlide.Number - 2].Time;
            _events.fire(Mediasite.Player.ViewEvent.PositionChanged, slideTime);
        }
    }

    this.UpdatePosition = function (position) {
        if (!positionChanging) {
            updatePositionText(position);
            _currentPosition = position;

            setMediaDuration(position);

            if (getMediaDuration() > 0) {
                $(selectors.positionSlider).slider('option', 'value', position / getMediaDuration() * sliderMaxValue);
            }
        }

        if (getMediaDuration() > 0 && !_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) {
            slideNav.setNormalizedPosition(position / getMediaDuration());
        }

        if (isOnDemand() && (getMediaDuration() > 0) && (_currentPosition >= getMediaDuration())) {
            ShowPresentationEndedState();
        }

        if (_audioOnly && !hasSlides() && _mediaEnded && position > 0) {
            if (playerContext.PlayerLayoutOptions.Images && playerContext.PlayerLayoutOptions.Images.DefaultSlide) {
                showOptionImageAsSlide(playerContext.PlayerLayoutOptions.Images.DefaultSlide);
            }
            _mediaEnded = false;
        }
    };

    function ShowPresentationEndedState() {
        setBroadcastingIndicatorTooltip(Mediasite.Player.Localization.LiveIndicator.EndedTooltip);
        showOptionImageAsSlide(playerContext.PlayerLayoutOptions.Images.PresentationEndedSlide);

        if (_presentation.PlayStatus != Mediasite.Player.PresentationStatus.OnDemand) {
            _livePresentationHasEnded = true;
        }

        _mediaEnded = true;
    }

    function isOnDemand() {
        return _presentation.PlayStatus === Mediasite.Player.PresentationStatus.OnDemand;
    }

    this.UpdateMediaInfo = function (mediaInfo) {
        _mediaInfo = mediaInfo;
        _audioOnly = mediaInfo.AudioOnly;
        setInitialStageLayout(); // now that media element has initialized, it's safe to hide it (if applicable)
        var showLayoutButtons = true;

        setMediaDuration(mediaInfo.Duration);
        if (!_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) {
            slideNav.setDuration(getMediaDuration());
        }
        var durationString = getDisplayFromDuration(getMediaDuration(), true);
        $(selectors.duration).text(durationString);
        if (mediaInfo.AudioOnly) {
            stage.setPrimaryContentElement(Mediasite.Player.StageContentElement.Slide);
            setStageLayoutType(Mediasite.Player.StageLayoutType.PrimaryOnly);
            showLayoutButtons = false;
        }

        if ((!mediaInfo.AudioOnly && !hasSlides() && isOnDemand())
           || (!mediaInfo.AudioOnly && !hasSlides() && !isOnDemand())) {
            stage.setPrimaryContentElement(Mediasite.Player.StageContentElement.Video);
            setStageLayoutType(Mediasite.Player.StageLayoutType.PrimaryOnly);

            showLayoutButtons = false;
        }

        if (mediaInfo.CanChangeSpeed && maySetSpeed()) {
            $(selectors.speedButton).show();
        } else {
            $(selectors.speedButton).hide();
        }

        $(selectors.layoutButtons).toggle(showLayoutButtons);


        updateLayout();
    };

    this.UpdateMediaState = function (state) {
        hideVideoThumb();

        var mediaStateText = (state === Mediasite.Player.MediaState.Undefined) ? '' : Mediasite.Player.MediaState.GetDisplayName(state);
        $(selectors.mediaStateText).text(mediaStateText);

        var $mediaState = isVideoBoxShowing() ? $(selectors.mediaStateDiv) : $(selectors.mediaStateStandalone);
        if (state === Mediasite.Player.MediaState.Playing || state === Mediasite.Player.MediaState.Undefined) {
            $mediaState.stop(true, true).fadeOut(fadeSpeed);
        } else {
            $mediaState.stop(true, true).fadeIn(fadeSpeed);
        }

        $(selectors.playPauseButton).attr('disabled', false);
        $(selectors.playStopButton).attr('disabled', false);

        switch (state) {
            case Mediasite.Player.MediaState.Playing:
                togglePlayButton(false);
                break;
            case Mediasite.Player.MediaState.Paused:
            case Mediasite.Player.MediaState.Stopped:
            case Mediasite.Player.MediaState.MediaEnded:
                togglePlayButton(true);
                break;
            default:
                break;
        }

        if (state === Mediasite.Player.MediaState.MediaEnded && isOnDemand()) {
            // We can't trust MediaEnded during a live broadcast.
            ShowPresentationEndedState();
        }

        _mediaState = state;
        updateBroadcastingIndicator();
    };

    this.ShowHelp = function () {
        if (!helpWindow || helpWindow.closed) {
            var sep = playerContext.GlobalOptions.AppRoot.length > 0 ? "/" : "";
            var url = playerContext.GlobalOptions.AppRoot + sep + "Help/Mediasite/OverviewFullVersion.htm";
            helpWindow = Mediasite.Player.CreatePopup(url, "Help", 800, 600, true, true);
        }
    };

    this.ShowPolls = function () {
        if (!_presentation.PollingEnabled) {
            return;
        }

        if (!pollsWindow || pollsWindow.closed) {
            pollsWindow = Mediasite.Player.CreatePopup(_presentation.PollingLocation, "Polls", 600, 450, true, true);
        }
    };

    this.UpdateUserEmailAddress = function (emailAddress) {
        if (!_presentation.ForumEnabled) {
            return;
        }

        toggleInteractivityPanel(interactivityPanels.Ask);

        if (_currentDetailPanel !== interactivityPanels.Ask) {
            var javascriptResize = _currentPopupWindow ? false : true;
            $(selectors.askPanel).playeraskpanel({ presentation: _presentation, currentPosition: _currentPosition, labelMargin: 50, message: { cols: 30, rows: 8 }, dismissFunction: dismissInteractivityPanel, onSendQuestion: onSendQuestion, javascriptResize: javascriptResize });
            $(selectors.askPanel).playeraskpanel('updateUserEmailAddress', emailAddress);
        }
    };

    this.SendQuestionComplete = function (success, message) {
        //we do not want to hide the panel if successful. dialog should close it out when clicking OK
        //        if (success) {
        //            toggleInteractivityPanel(interactivityPanels.None);
        //        }
        $(selectors.askPanel).playeraskpanel('sendQuestionComplete', success, message);
    };

    this.UpdateEmailInvite = function (emailData) {
        if (!_presentation.SharingEnabled) {
            return;
        }
        //emailData.UseServerForSMTP = true; ///////////////////////////////////////////////////////////remove me!
        if (emailData.UseServerForSMTP) {
            toggleInteractivityPanel(interactivityPanels.Email);
        }

        var $invitePanel = $(selectors.emailPanel);

        var javascriptResize = _currentPopupWindow ? false : true;
        $invitePanel.playerinvitepanel({ presentation: _presentation, currentPosition: _currentPosition, labelMargin: 50, message: { cols: 30, rows: 12 }, url: window.location.href, dismissFunction: dismissInteractivityPanel, onSendEmail: onSendEmail, javascriptResize: javascriptResize });
        $invitePanel.playerinvitepanel('updateEmailInvite', emailData);
    };

    this.SendEmailComplete = function (success, message) {
        $(selectors.emailPanel).playerinvitepanel('sendInviteComplete', success, message);
    };

    this.ShowLinks = function () {

        if (_presentation.Links.length > 0) {
            toggleInteractivityPanel(interactivityPanels.Links);
            $(".ui-playerlinkspanel-list a").first().focus();
        }
    };

    this.ShowChapters = function () {

        if (_presentation.Chapters.length > 0) {
            toggleInteractivityPanel(interactivityPanels.Chapters);
            $(".ui-playerchapterspanel-chapteritem").first().focus();
        }
    };

    this.ShowInfo = function () {
        var showing = _currentDetailPanel !== detailPanels.Info;
        toggleDetailPanel(detailPanels.Info);

        if (showing) {
            $(selectors.infoPanel).playerinfopanel('updateLayout');
        }
    };

    this.ToggleCaptionDisplay = function () {
        if (!_presentation.HasCaptions || _presentation.DisableCaptionDisplay) {
            return;
        }

        var $ccButton = $(selectors.captionButton);
        if (isCCHidden) {
            captionPanel.show();
            $ccButton.attr({ title: Mediasite.Player.Localization.Buttons.HideCaptioning });
            isCCHidden = false;
        }
        else {
            captionPanel.hide();
            $ccButton.attr({ title: Mediasite.Player.Localization.Buttons.ShowCaptioning });
            isCCHidden = true;
        }
    };

    this.ToggleSearch = function () {
        if (!maySearch()) {
            return;
        }

        var showing = _currentDetailPanel !== detailPanels.Search;

        toggleDetailPanel(detailPanels.Search);
        if (showing) {
            $(selectors.searchPanel).playersearchpanel('updateLayout');
        }
    };


    this.DisplaySearchResults = function (searchTerm, results) {
        var $captionPanel = $(selectors.searchPanel);
        $captionPanel.playersearchpanel('displayResults', searchTerm, results);
    };

    this.DisplaySearchError = function () {
        var $captionPanel = $(selectors.searchPanel);
        $captionPanel.playersearchpanel('displayError');
    };

    this.UpdateCurrentCaption = function (caption) {
        
    };

    this.UpdateCurrentCaptions = function (captions) {
        captionPanel.setCaptions(captions);
    };

    this.LiveStatusChange = function (status) {
        //alert(status);
        switch (status) {
            case Mediasite.Player.PresentationStatus.Live:
                setBroadcastingIndicatorTooltip(Mediasite.Player.Localization.LiveIndicator.LiveTooltip);
                if (!_currentSlide || _currentSlide.Number < 1) {
                    showOptionImageAsSlide(playerContext.PlayerLayoutOptions.Images.DefaultSlide);
                }
                break;
            case Mediasite.Player.PresentationStatus.LivePaused:
                setBroadcastingIndicatorTooltip(Mediasite.Player.Localization.LiveIndicator.PausedTooltip);
                break;
            case Mediasite.Player.PresentationStatus.LiveEnded:
                ShowPresentationEndedState();
                break;
            default:
                break;
        }
    };

    this.AddNewSlide = function (slide) {
        if (_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation) || !hasSlides())
            return;
        // TODO: Hide default slide

        setMediaDuration(slide.Time);

        if (slide.Text == "" && slide.Number > 0) {
            slide.Text = Mediasite.Player.Localization.NewStandardPlayer.DefaultSlideTitleFormat.replaceholders(slide.Number);
        }

        this.UpdateCurrentSlide(slide);

        _slidePartitions = new Mediasite.Player.SlidePartitions(slideStream.Slides);
        _slidePartitions.bind('currentpagechanged', slidePartitions_currentpagechanged);
        slideNav.setSlides(_slidePartitions.getCurrentPageItems());

        slideNav.setDuration(slide.Time); // Let's be clever and pin the last slide at 100% duration.
        slideNav.setNormalizedPosition(1.0);
    };



    function setBroadcastingIndicatorTooltip(text) {
        $(selectors.broadcastingIndicator).attr('title', text);
    }

    function getGreatestSlideTime() {
        if (!hasSlides()) {
            return 0;
        }

        return slideStream.Slides[slideStream.Slides.length - 1].Time;
    }

    function getMediaDuration() {
        return mediaDuration;
    }
    function setMediaDuration(position) {
        if (position == Infinity) {
            // infinity is worthless as a duration. 
            // Use the greatest slide time instead.
            position = getGreatestSlideTime();
        }

        // The duration should never shrink during playback.
        // During live, we need to continuously extend the duration to 
        // include the current position and slide times.
        mediaDuration = Math.max(mediaDuration, position);

        if (slideNav) {
            slideNav.setDuration(mediaDuration);
        }

        // The duration displayed in the info panel is a different beast.
        // For a live presentation, the true duration can significantly 
        // exceed the duration delivered by the manifest. If the media 
        // duration grows beyond the configured presentation duration, 
        // show the greater one.
        $(selectors.infoPanel).playerinfopanel('updateDuration', Math.max(_presentation.Duration, mediaDuration));
    }

    function fixSlideTitles() {

        if (!hasSlides()) return;

        var i;


        for (i = 0; i < slideStream.Slides.length; i++) {
            var slide = slideStream.Slides[i];
            if (slide.Text == "") {
                slide.Text = Mediasite.Player.Localization.NewStandardPlayer.DefaultSlideTitleFormat.replaceholders(i + 1);
            }
        }
    }

    this.UpdatePlaybackRate = function (rateInfo) {
        $(selectors.speedButton).playerspeed("setPlaybackRate", rateInfo.Current);
    }

    function getStageLayoutTypeForInitialLayoutOption(optionValue) {
        var slt = Mediasite.Player.StageLayoutType;

        switch (optionValue) {
            case 'SlideOnly':
                return slt.PrimaryOnly;
            case 'PictureInPicture':
                return slt.PictureInPicture;
            default:
                return slt.SideBySide;
        }
    }

    function showSlide(slideImage, link, tooltip) {
        if (_livePresentationHasEnded) {
            return;
        }

        slideInspector.setSlideImage(slideImage);
        slideInspector.setSlideToolTip(tooltip);

        // In some browsers (ahem... Chrome), the fact that the contentFramer box 
        // is above the slideInspector box can hide the slideInspector's tooltip. 
        // If the tooltip applied to the slideBox which wraps them both, the 
        // tooltip shows up when hovering over the zoom in/out buttons. 
        // So... apply the tooltip to the contentFramer box.
        $('.contentFramer', $(selectors.slideBox)).attr('title', tooltip);

        // TODO: slideInspector.setSlideLinkUrl(link);
    }

    function showOptionImageAsSlide(optionImage) {
        if (!optionImage) {
            optionImage = { ImageFilename: '', ImageUrl: '' };
        }

        showSlide(new Mediasite.Player.SpecialSlideImage(optionImage.ImageFilename), optionImage.ImageUrl, Mediasite.Player.Localization.CurrentSlide.SlideImage);
    }

    function updateBroadcastingIndicator() {
        if (!_mediaState || !_presentation || !_presentation.PlayStatus) {
            return;
        }

        if (_mediaState === Mediasite.Player.MediaState.Playing) {
            broadcastingIndicator.Start();
        } else {
            broadcastingIndicator.Stop();
            broadcastingIndicator.Reset();
        }
    }

    function getPanelSelector(panel) {
        switch (panel) {
            case detailPanels.Info:
                return selectors.infoPanel;
            case detailPanels.Caption:
                //return selectors.cap;
            case detailPanels.Search:
                return selectors.searchPanel;
            case interactivityPanels.Ask:
                return selectors.askPanel;
            case interactivityPanels.Email:
                return selectors.emailPanel;
            case interactivityPanels.Links:
                return selectors.linksPanel;
            case interactivityPanels.Chapters:
                return selectors.chaptersPanel;
        }
    }

    function getPanelButtonSelector(panel) {
        switch (panel) {
            case detailPanels.Info:
                return selectors.infoButton;
            case detailPanels.Caption:
                //return selectors.cap;
            case detailPanels.Search:
                return selectors.searchButton;
            case interactivityPanels.Ask:
                return selectors.askButton;
            case interactivityPanels.Email:
                return selectors.emailButton;
            case interactivityPanels.Links:
                return selectors.linksButton;
            case interactivityPanels.Chapters:
                return selectors.chaptersButton;
        }
    }

    function fadePanel(panelSelector, show) {
        if (show) {
            $(panelSelector).stop(true, true).fadeIn(fadeSpeed, function () {
                if (panelSelector && !_isIOS) {
                    // Focus on first form element found
                    $('input, textarea', panelSelector).first().focus();
                }
            });
        } else {
            $(panelSelector).stop(true, true).fadeOut(fadeSpeed);
        }
    }

    function toggleControls() {

    }

    //increase slider toucharea for smoother seeking
    function increaseSliderToucharea() {
        var touchAreaInHandle = $(document.createElement('div'));
        touchAreaInHandle.addClass('ui-slider-handle-toucharea');
        touchAreaInHandle.appendTo($('a.ui-slider-handle'));
    }

    function onCaptionClick(position) {
        _currentPosition = position;
        _events.fire(_eventNames.PositionChanged, position);
        $(selectors.mediaStateDiv).hide();
    }

    function onChapterChanged(position) {
        _events.fire(_eventNames.PositionChanged, position);
    }

    function onPlaybackRateFaster(doLoop) {
        _events.fire(_eventNames.PlaybackRateFaster, doLoop);
    }

    function onVolumeChanged(volume) {
        _events.fire(_eventNames.VolumeChanged, volume);
    }

    function onMuteClicked() {
        _muteUnmuteButtonClicked = true;
        _events.fire(_eventNames.Mute);
    }

    function onSearch(searchTerm) {
        _events.fire(_eventNames.Search, searchTerm);
    }

    function onSendQuestion(question) {
        _events.fire(_eventNames.UpdateAskQuestionEmailAddress, { 'EmailAddress': question.SubmitterEmail });
        _events.fire(_eventNames.SendQuestion, question);
    }

    function onSendEmail(email) {
        _events.fire(_eventNames.SendEmail, email);
    }

    function togglePlayButton(showPlay) {
        // interpret checked to mean 'is playing'.
        $(selectors.playPauseButton)
		.imageButton('setIsChecked', !showPlay);
        $(selectors.playStopButton)
		.imageButton('setIsChecked', !showPlay);
    }

    function isVideoBoxShowing() {
        var isShowing = false;

        if ($(selectors.videoBox).is(":visible") && $(selectors.videoBox).css('opacity') > 0.001) {
            isShowing = true;
        }
        return isShowing;
    }

    function setStageLayoutType(layoutType) {
        stage.setLayoutType(layoutType);
        updateLayoutButtonStates();
        setMediaStateIndicator();
    }

    function setMediaStateIndicator() {
        var showingMediaState = $(selectors.mediaStateDiv).add(selectors.mediaStateStandalone).is(":visible");

        if (showingMediaState) {
            var $mediaStateShow = $(selectors.mediaStateStandalone);
            var $mediaStateHide = $(selectors.mediaStateDiv);
            if (isVideoBoxShowing()) {
                var temp = $mediaStateShow;
                $mediaStateShow = $mediaStateHide;
                $mediaStateHide = temp;
            }

            $mediaStateShow.show();
            $mediaStateHide.hide();
        }
    }

    function updateLayoutButtonStates() {
        var layoutType = stage.getLayoutType();

        $(selectors.pipButton).imageButton('setIsChecked', layoutType === Mediasite.Player.StageLayoutType.PictureInPicture);
        $(selectors.sideBySideButton).imageButton('setIsChecked', layoutType === Mediasite.Player.StageLayoutType.SideBySide);
        $(selectors.fullFrameButton).imageButton('setIsChecked', layoutType === Mediasite.Player.StageLayoutType.PrimaryOnly);
    }

    function hasSlides() {
        if (!_presentation || !slideStream) return false;

        return slideStream.HasSlides();
    }

    function maySearch() {
        return !_events.isDisabled(_eventNames.Search) && _presentation.HasSearchableText;
    }

    function maySetSpeed() {
        return !_events.isDisabled(_eventNames.PlaybackRateChanged) && (_presentation.PlayStatus == Mediasite.Player.PresentationStatus.OnDemand);
    }

    function maySetVolume() {
        return !_events.isDisabled(_eventNames.VolumeChanged);
    }


    function mayDisplayMediaFidelity() {
        return !_layoutFeature.isDisabled(_layoutFeature.item.FidelityIndicator);
    }

    function setupControls() {
        setupPanelFocusResetter();

        // #region Mediasite branding button
        var $mediasiteBrandingImage = $(selectors.mediasiteSwirlButton);
        if (!_layoutFeature.isDisabled(_layoutFeature.item.SofoBranding)) {
            $mediasiteBrandingImage.imageButton();
        } else {
            $mediasiteBrandingImage.hide();
        }
        // #endregion


        // #region Panel buttons

        // Track click and enter-keypress separately - we want to know how the 'click' event was triggered for
        // determining how to set focus after a panel was closed.  
        // ON click, we want to know what the last focused element is.  On enter, we only care which panels close button was clicked.

        $(selectors.closeDetailPanelButton)
		    .imageButton({ spriteOffset: 32, normalTitle: Mediasite.Player.Localization.Buttons.Close })
		    .mouseup(function (e) {
		        if (e.which == 1) {
		            toggleDetailPanel(detailPanels.None, Mediasite.Player.PanelFocusResetter.ClickType.MouseClick);
		        }
		    })
            .keyup(function (e) {
                if (e.which == 13 || e.which == 32) {
                    toggleDetailPanel(detailPanels.None, Mediasite.Player.PanelFocusResetter.ClickType.KeyPress);
                }
            });

        $(selectors.closeInteractivityPanelButton)
		    .imageButton({ spriteOffset: 32, normalTitle: Mediasite.Player.Localization.Buttons.Close })
		    .mouseup(function (e) {
		        if (e.which == 1) {
		            toggleInteractivityPanel(interactivityPanels.None, Mediasite.Player.PanelFocusResetter.ClickType.MouseClick);
		        }
		    })
            .keyup(function (e) {
                if (e.which == 13 || e.which == 32) {
                    toggleInteractivityPanel(detailPanels.None, Mediasite.Player.PanelFocusResetter.ClickType.KeyPress);
                }
            });

        // #region

        // #region Controls area (hide)
        if (_layoutFeature.isDisabled(_layoutFeature.item.MainControls)) {
            $(selectors.controlBar).hide();
        }
        // #endregion

        // #region Play/Pause/Stop buttons (enable/disable/hide)
        var $playPause = $(selectors.playPauseButton);
        var $playStop = $(selectors.playStopButton);
        if (!_events.isDisabled(_eventNames.TogglePlayPause)) {
            $playPause
                .prop('disabled', false)
		        .imageButton({ isCheckButton: true, checkedPosition: '0 -381px', normalTitle: Mediasite.Player.Localization.Buttons.Play, checkedTitle: Mediasite.Player.Localization.Buttons.Pause })
		        .click(function () {
		            _events.fire(_eventNames.TogglePlayPause);
		        })
                .attr('disabled', true);

            $playStop
                .prop('disabled', false)
                .imageButton({ isCheckButton: true, checkedPosition: '0 -681px', normalTitle: Mediasite.Player.Localization.Buttons.Play, checkedTitle: Mediasite.Player.Localization.Buttons.Stop })
		        .click(function () {
		            _events.fire(_eventNames.TogglePlayPause);
		        })
                .attr('disabled', true);
        } else {
            $playPause.hide();
            $playStop.hide();
        }
        // #endregion

        // #region Skipback button (enable/disable/hide)
        var $skipback = $(selectors.skipBackButton);
        if (!_events.isDisabled(_eventNames.SkipBack)) {
            $skipback
                .prop('disabled', false)
		        .attr({ title: Mediasite.Player.Localization.Buttons.Skipback })
		        .imageButton()
		        .click(function () {
		            _events.fire(_eventNames.SkipBack);
		        });
        } else {
            $skipback.hide();
        }
        // #endregion

        // #region Layout switchers (enable/disable/hide)
        if (!_events.isDisabled(_eventNames.LayoutChanged)) {
            $(selectors.pipButton)
		    .attr({ title: Mediasite.Player.Localization.NewStandardPlayer.PipLayout })
		    .imageButton({ isCheckButton: true, checkedPosition: '-144px -413px' })
		    .click(function () {
		        setStageLayoutType(Mediasite.Player.StageLayoutType.PictureInPicture);
		    });
            $(selectors.sideBySideButton)
		    .attr({ title: Mediasite.Player.Localization.NewStandardPlayer.SideBySideLayout })
		    .imageButton({ isCheckButton: true, checkedPosition: '-144px -577px' })
		    .click(function () {
		        setStageLayoutType(Mediasite.Player.StageLayoutType.SideBySide);
		    });
            $(selectors.fullFrameButton)
		    .attr({ title: Mediasite.Player.Localization.NewStandardPlayer.FullFrameLayout })
		    .imageButton({ isCheckButton: true, checkedPosition: '-144px -645px' })
		    .click(function () {
		        setStageLayoutType(Mediasite.Player.StageLayoutType.PrimaryOnly);
		    });

            $(selectors.swapButton)
		        .attr({ title: Mediasite.Player.Localization.NewStandardPlayer.SwapMediaElements })
		        .imageButton()
		        .click(function () {
		            stage.setFlipLayout(stage.getFlipLayout() ^ 1);
		            setMediaStateIndicator();
		        });
        }

        // #endregion

        // #region Info button (enable/disable/hide)
        $info = $(selectors.infoButton);
        if (!_events.isDisabled(_eventNames.ShowInfo)) {
            $info
            .prop('disabled', false)
		    .attr({ title: Mediasite.Player.Localization.Buttons.Info })
		    .imageButton({ isCheckButton: true, checkedPosition: '-128px -285px' })
		    .click(function () {
		        _events.fire(_eventNames.ShowInfo);
		    });
        } else {
            $info.hide();
        }
        // #endregion

        // #region Closed caption control (enable/disable/hide)
        var $caption = $(selectors.captionButton);
        if (!_events.isDisabled(_eventNames.ToggleCaptions)) {
            $caption
                .imageButton({
                    isCheckButton: true,
                    checkedPosition: '-128px -32px',
                    normalTitle: Mediasite.Player.Localization.Buttons.ShowCaptioning,
                    checkedTitle: Mediasite.Player.Localization.Buttons.HideCaptioning
                })
		        .click(function () { _events.fire(_eventNames.ToggleCaptions); });
        } else {
            $caption.hide();
        }
        // #endregion

        // #region Text search control (enable/disable/hide)
        var $search = $(selectors.searchButton)
        if (!_events.isDisabled(_eventNames.ToggleSearch)) {
            $search
		        .imageButton({
		            isCheckButton: true,
		            checkedPosition: '-128px -513px',
		            normalTitle: Mediasite.Player.Localization.Buttons.ShowCaptionSearch,
		            checkedTitle: Mediasite.Player.Localization.Buttons.HideCaptionSearch
		        })
		        .click(function () { _events.fire(_eventNames.ToggleSearch); });
        } else {
            $search.hide();
        }
        // #endregion

        // #region Speed control (enable/disable/hide)
        var $speed = $(selectors.speedButton);
        if (!_events.isDisabled(_eventNames.PlaybackRateFaster)) {
            $speed.playerspeed({ onPlaybackRateFaster: onPlaybackRateFaster });
        } else {
            $speed.hide();
        }
        // #endregion

        // #region Volume control (enable/disable/hide)
        if (!_events.isDisabled(_eventNames.VolumeChanged)) {
            $(selectors.volumeButton).playervolume({ onVolumeChanged: onVolumeChanged, onMuteClicked: onMuteClicked });
        } else {
            $(selectors.volumeButton).hide();
        }
        // #endregion

        // #region Fidelity (quality) indicator (hide (enable later)/remove)
        if (mayDisplayMediaFidelity()) {
            $(selectors.fidelityIndicator).hide();
        } else {
            $(selectors.fidelityIndicator).remove();
        }
        // #endregion

        // #region Polls control (enable/disable/hide)
        var $polls = $(selectors.pollsButton);
        if (!_events.isDisabled(_eventNames.ShowPolls)) {
            $polls
                .prop('disabled', false)
		        .attr({ title: Mediasite.Player.Localization.Buttons.ShowPolls })
		        .imageButton()
		        .click(function () { _events.fire(_eventNames.ShowPolls); });
        } else {
            $polls.hide();
        }
        // #endregion

        // #region Ask a Question control (enable/disable/hide)
        var $ask = $(selectors.askButton);
        if (!_events.isDisabled(_eventNames.AskQuestion)) {
            $ask
                .prop('disabled', false)
                .attr({ title: Mediasite.Player.Localization.Buttons.Ask })
			    .imageButton()
                .click(function () { _events.fire(_eventNames.AskQuestion); });
        } else {
            $ask.hide();
        }
        // #endregion

        // #region Share presentation control (enable/disable/hide)
        var $email = $(selectors.emailButton);
        if (!_events.isDisabled(_eventNames.OpenEmail)) {
            $email
                .prop('disabled', false)
                .attr({ title: Mediasite.Player.Localization.Buttons.Email })
			    .imageButton()
                .click(function () { _events.fire(_eventNames.OpenEmail); });
        } else {
            $email.hide();
        }
        // #endregion

        // #region Link listing control (enable/disable/hide)
        var $links = $(selectors.linksButton);
        if (!_events.isDisabled(_eventNames.ShowLinks)) {
            $links
                .prop('disabled', false)
                .attr({ title: Mediasite.Player.Localization.Buttons.Links })
			    .imageButton()
                .click(function () { _events.fire(_eventNames.ShowLinks); });
        } else {
            $links.hide();
        }
        // #endregion

        // #region Chapter navigation control (enable/disable/hide)
        var $chapters = $(selectors.chaptersButton)
        if (!_events.isDisabled(_eventNames.ShowChapters)) {
            $chapters
                .prop('disabled', false)
                .attr({ title: Mediasite.Player.Localization.Buttons.Chapters })
			    .imageButton()
                .click(function () { _events.fire(_eventNames.ShowChapters); });
        } else {
            $chapters.hide();
        }
        // #endregion

        // #region Help control (enable/disable/hide)
        var $help = $(selectors.helpButton);
        if (!_events.isDisabled(_eventNames.ShowHelp)) {
            $help
                .prop('disabled', false)
		        .attr({ title: Mediasite.Player.Localization.Buttons.Help })
		        .imageButton()
		        .click(function () { _events.fire(_eventNames.ShowHelp); });
        } else {
            $help.hide();
        }
        // #endregion

        // #region Button dividers
        // This block belongs after all the other buttons have been toggled

        if ($(selectors.controlsRight).children(':visible').not(selectors.buttonDivider).length == 0) {
            // If all buttons are hidden, hide the button dividers
            $(selectors.buttonDivider).hide();
        } else {
            // At least one button is visible...
            $(selectors.buttonDivider).each(function (i, e) {
                var $buttonDivider = $(e);

                var $visibleItem = $buttonDivider.prevAll(':visible').last();
                if ($visibleItem.length == 0 || $visibleItem.is(selectors.buttonDivider)) {
                    // If no buttons are visible preceding this divider, hide the divider
                    $buttonDivider.hide();
                    return;
                }


                var $visibleItem = $buttonDivider.nextAll(':visible').first();
                if ($visibleItem.length == 0 || $visibleItem.is(selectors.buttonDivider)) {
                    // If no buttons are visible following this divider, hide the divider
                    $buttonDivider.hide();
                    return;
                }
            });
        }

        // #endregion

        // #region Scrubber / position control  (enable/disable/hide)
        $(selectors.positionSlider).slider({
            disabled: _events.isDisabled(_eventNames.PositionChanged),
            range: 'min',
            min: 0,
            max: sliderMaxValue,
            step: 1,
            start: function (event, ui) {
                positionChanging = true;
            },
            slide: function (event, ui) {
                updatePositionText(getMediaDuration() * (ui.value / sliderMaxValue));
            },
            stop: function (event, ui) {
                positionChanging = false;
                _events.fire(_eventNames.PositionChanged, getMediaDuration() * (ui.value / sliderMaxValue));
            }
        }).enableTouch();
        $(selectors.positionSliderHandle).append('<div id="currentPosition">00:00:00</div>');
        $(selectors.positionSliderHandle).prop('tabindex', '-1');
        increaseSliderToucharea();
        // #endregion 

    }

    function updateControls() {
        if (!_presentation.HasCaptions) {
            $(selectors.captionButton).imageButton('disable');
        }

        if (_presentation.Chapters.length < 1) {
            $(selectors.chaptersButton).imageButton('disable');
        }

        if (!_presentation.PollingEnabled) {
            $(selectors.pollsButton).imageButton('disable');
        }

        if (!_presentation.ForumEnabled) {
            $(selectors.askButton).imageButton('disable');
        }

        if (!_presentation.SharingEnabled) {
            $(selectors.emailButton).imageButton('disable');
        }

        if (_presentation.Links.length < 1) {
            $(selectors.linksButton).imageButton('disable');
        }

        if (!maySearch()) {
            $(selectors.searchButton).hide();
        }

        if (!maySetSpeed()) {
            $(selectors.speedButton).hide();
        }

        if (!maySetVolume()) {
            $(selectors.volumeButton).hide();
        }

        // Fidelity indicator is hidden initially and shown when needed
    }

    this.UpdateMediaVolume = function (volume) {
        if (!maySetVolume()) return;

        if (!(volume > 0)) {
            //mute
            $(selectors.volume).playervolume("mute");
        }
        else {
            //unmute
            $(selectors.volume).playervolume("unmute", volume);
        }

        if (_muteUnmuteButtonClicked) {
            _muteUnmuteButtonClicked = false;

            if (!(volume > 0))
                $(selectors.unmuteWrapper + " button").focus();
            else
                $(selectors.muteWrapper + " button").focus();
        }
    }

    this.UpdateMediaFidelity = function (fidelityInfo) {
        if (!mayDisplayMediaFidelity()) return;

        if (!(fidelityInfo.tracks && fidelityInfo.tracks.length > 1)) return;

        var $fidelityIndicator = $(selectors.fidelityIndicator);
        if (!$fidelityIndicator.is(":visible")) {
            $fidelityIndicator.show().playerfidelity();
            updateLayout();
        }

        $fidelityIndicator.playerfidelity('update', fidelityInfo);
    }

    function togglePlayPause() {
        _events.fire(_eventNames.TogglePlayPause);
    }

    function removePx(pxString) {
        return pxString.replace('px', '');
    }

    function updateStageSize() {
        var stage = $(selectors.contentArea).first();
        stage.css('marginRight', '');
        stage.height(jQuery(window).height() - removePx(stage.css('marginTop')) - removePx(stage.css('marginBottom')));
        stage.width(jQuery(window).width() - removePx(stage.css('marginLeft')) - removePx(stage.css('marginRight')));

        stage.trigger('containerresize');
    }

    function updateLayout() {
        updateStageSize();

        $(selectors.controlsMiddle).css({
            'margin-left': $(selectors.controlsLeft).outerWidth() + 'px',
            'margin-right': ($(selectors.controlsRight).outerWidth() + 20) + 'px'  // extra space to allow for "current presentation position" (0:00:00) to overflow a little
        });
    }

    function getCurrentDetailPanel() {
        return _currentDetailPanel;
    }

    function setCurrentDetailPanel(value, panelClosingType, clickType) {
        var elementToFocus = null;

        if (value === detailPanels.Info && _events.isDisabled(_eventNames.ShowInfo)) {
            return;
        }

        fadePanel(getPanelSelector(_currentDetailPanel), false);

        if (panelClosingType)
            elementToFocus = _panelFocusResetter.GetElementToResetFocusTo(panelClosingType, $(getPanelButtonSelector(_currentDetailPanel)), clickType);

        if (value !== _currentDetailPanel) {

            if (_currentDetailPanel == detailPanels.Info && value == detailPanels.None)
                infoButton.focus();

            _currentDetailPanel = value;

            fadePanel(getPanelSelector(_currentDetailPanel), true);

            $(selectors.infoButton).imageButton('setIsChecked', _currentDetailPanel === detailPanels.Info);
            $(selectors.searchButton).imageButton('setIsChecked', _currentDetailPanel === detailPanels.Search);
        }

        if (elementToFocus)
            elementToFocus.focus();
    }

    function toggleDetailPanel(panel, clickType) {

        var panelClosingType = null;

        // if we are closing a details panel we need to determine where focus should be set
        if (panel === _currentDetailPanel || panel === detailPanels.None) {
            if (_currentInteractivityPanel == interactivityPanels.None) {
                panelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.OneClosedNoneStillOpen;
            } else {
                panelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.OneClosedSomeStillOpen;
            }
        }

        if (panel === _currentDetailPanel) {
            setCurrentDetailPanel(detailPanels.None, panelClosingType, clickType);
        }
        else {
            setCurrentDetailPanel(panel, panelClosingType, clickType);
        }
    }

    function dismissInteractivityPanel() {
        toggleInteractivityPanel(interactivityPanels.None);
    }

    function clearInteractivityPopupWindow() {
        if (!_usePopupPanels) return;

        if (_currentPopupWindow && _currentPopupWindow.close) {
            _currentPopupWindow.close();
        }
        _currentPopupWindow = null;
    }

    function setCurrentInteractivityPanel(value, panelClosingType, clickType) {
        var elementToFocus = null;

        fadePanel(getPanelSelector(_currentInteractivityPanel), false);
        clearInteractivityPopupWindow();

        if (panelClosingType)
            elementToFocus = _panelFocusResetter.GetElementToResetFocusTo(panelClosingType, $(getPanelButtonSelector(_currentInteractivityPanel)), clickType);

        if (_usePopupPanels && (value == interactivityPanels.Ask || value == interactivityPanels.Email)) {
            if (value !== interactivityPanels.None) {
                _currentPopupWindow = window.open('', 'interactivity', 'width=500,height=500', true);

                if (!_currentPopupWindow) {
                    // Pop up window failed
                    alert(Mediasite.Player.Localization.Common.PopupsBlocked);
                    _usePopupPanels = false;
                    setCurrentInteractivityPanel(value);
                    return;
                }

                var selector = $('body', _currentPopupWindow.document);
                selector.addClass(classes.popup);
                $(selectors.panelStylesheet).clone().appendTo(selector);

                switch (value) {
                    case interactivityPanels.Ask:
                        selectors.askPanel = selector;
                        break;
                    case interactivityPanels.Email:
                        selectors.emailPanel = selector;
                        break;
                }
            }

            // Can't detect when popup closes:
            // * $(_currentPopupWindow).bind('beforeunload') attaches it to the main window
            // * polling is inefficient
            _currentInteractivityPanel = interactivityPanels.None;
        } else {

            if (value !== _currentInteractivityPanel) {
                _currentInteractivityPanel = value;

                fadePanel(getPanelSelector(_currentInteractivityPanel), true);
            }
        }

        if (elementToFocus)
            elementToFocus.focus();
    }

    function toggleInteractivityPanel(panel, clickType) {

        var panelClosingType = null;

        // if we are closing a details panel we need to determine where focus should be set
        if (panel === _currentInteractivityPanel || panel === interactivityPanels.None) {
            if (_currentDetailPanel == detailPanels.None) {
                panelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.OneClosedNoneStillOpen;
            } else {
                panelClosingType = Mediasite.Player.PanelFocusResetter.PanelClosingType.OneClosedSomeStillOpen;
            }
        }

        if (panel === _currentInteractivityPanel) {
            setCurrentInteractivityPanel(interactivityPanels.None, panelClosingType, clickType);
        } else {
            setCurrentInteractivityPanel(panel, panelClosingType, clickType);
        }
    }

    function getDisplayFromDuration(durationInMS, padHours) {
        if (durationInMS <= 1000) { // Android reports 1000ms when video is not yet loaded
            return "";
        }
        var whole = durationInMS;
        var hours = Math.floor(whole / 3600000);
        whole = whole - (hours * 3600000);
        if (hours < 10) {
            hours = "0" + hours;
        }
        var minutes = Math.floor(whole / 60000);
        whole = whole - (minutes * 60000);
        var seconds = Math.floor(whole / 1000);
        whole = whole - (seconds * 1000);
        if (minutes < 10) {
            minutes = "0" + minutes;
        }
        if (seconds < 10) {
            seconds = "0" + seconds;
        }
        if (hours === "00" && !padHours) {
            return (minutes + ":" + seconds);
        }
        return (hours + ":" + minutes + ":" + seconds);
    }

    function updatePositionText(position) {
        $(selectors.currentPosition).text(getDisplayFromDuration(position, true));
        $(selectors.livePosition).text(getDisplayFromDuration(position, true));
    }

    function updateBodyClasses() {
        var bod = $('body').removeClass();

        if (_presentation) {
            var playStatusClass = getBodyClassForPlayStatus(_presentation.PlayStatus);
            bod.addClass(playStatusClass);

            if (_presentation.PlayStatus === Mediasite.Player.PresentationStatus.ScheduledForLive ||
                _presentation.PlayStatus === Mediasite.Player.PresentationStatus.OpenForLive ||
                _presentation.PlayStatus === Mediasite.Player.PresentationStatus.Live ||
                _presentation.PlayStatus === Mediasite.Player.PresentationStatus.LivePaused ||
                _presentation.PlayStatus === Mediasite.Player.PresentationStatus.LiveEnded) {

                bod.addClass('isLively');
            }
        }

        if (_layoutFeature.isDisabled(_layoutFeature.item.HeaderArea)) {
            bod.addClass('noTitleArea');
        }

        if (_events.isDisabled(_eventNames.LayoutChanged)) {
            bod.addClass('noLayoutAdjustment');
        }

        if (_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) {
            bod.addClass('noSlideNavigation');
        } else {
            bod.addClass(getSlideCarouselSizeBodyClassName(playerContext.PlayerLayoutOptions.SlideCarouselSize));
        }

        if (_layoutFeature.isDisabled(_layoutFeature.item.MainControls)) {
            bod.addClass('noControlBar');
        }

        if (Mediasite.BrowserDetect.IOS()) {
            bod.addClass('is-ios');
        } else {
            bod.addClass('not-ios');
        }

        if (!(Mediasite.BrowserDetect.Android() || Mediasite.BrowserDetect.IOS())) {
            bod.addClass('styledScrollbars');
        }
    }

    function getBodyClassForPlayStatus(playStatus) {
        // WARNING: The class name returned is coupled to the string value of the playStatus member, 
        // an detail which could change. If this becomes an issue, expand this function to return 
        // explicit values to match those expected in CSS.
        return playStatus;
    }

    function getSlideCarouselSizeBodyClassName(size) {
        return 'slideCarouselSize-' + size;
    }

    function hideVideoThumb() {
        $(selectors.videoThumbContainer).css('display', 'none');
    }

    function showVideoThumb() {
        $(selectors.videoThumbContainer).css('display', '');
    }

    function slideNav_beginPreview(e) {
        if (_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) return;
        slidePreview.setPreviewSlide(slideNav.getPreviewSlide());
    }

    function slideNav_endPreview(e) {
        if (_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) return;
        slidePreview.setPreviewSlide(null);
    }

    function slidePreview_slidePreviewInitiated(e) {
        if (_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) return;
        var thumbArea = slideNav.getPreviewThumbArea();
        var previewArea = slidePreview.getPreviewArea();
        var src = slidePreview.getPreviewSrc();

        slidePreviewAnimation.animate(src, thumbArea, previewArea);
    }

    function slidePartitions_currentpagechanged(e) {
        if (_layoutFeature.isDisabled(_layoutFeature.item.SlideNavigation)) return;
        slideNav.setSlides(_slidePartitions.getCurrentPageItems());
    }
};
// -=====


// Stage
// +============

// StageControl
// +===========
Mediasite.Player.StageControl = function (panel, slideBox, videoBox, slidePreviewBox, layoutEngine, layoutOptions) {
    var _panel = $(panel);
    var _slideBox = $(slideBox);
    var _videoBox = $(videoBox);
    var _slidePreviewBox = $(slidePreviewBox);
    var _layoutType, _flipLayout;

    // layoutEngine is an optional parameter.
    var _layoutEngine = layoutEngine || new Mediasite.Player.StageLayoutEngine();
    _layoutEngine.layoutOptions = layoutOptions;

    $(window).bind('resize', function () {
        _panel.trigger('stageresize');
    });

    function applyRect(element, rect) {
        element.width(rect.width());
        element.height(rect.height());
        element.css('left', rect.left());
        element.css('top', rect.top());
    }

    function updateLayout() {
        if (_panel.width() <= 0 || _panel.height() <= 0) {
            return;
        }

        var layout = _layoutEngine.getLayout();

        applyRect(_slideBox, layout.primary());
        applyRect(_videoBox, layout.secondary());
        applyRect(_slidePreviewBox, layout.primary());

        // adjust z-indexes
        var slideBoxZIndex = 0;
        if (_layoutEngine.flipLayout()) {
            slideBoxZIndex = slideBoxZIndex ^ 2;
        }

        if (_layoutEngine.layoutType() === Mediasite.Player.StageLayoutType.PrimaryOnly) {
            slideBoxZIndex = slideBoxZIndex ^ 2;
        }

        _slideBox.css('zIndex', slideBoxZIndex);
        _videoBox.css('zIndex', slideBoxZIndex ^ 2);
        _slidePreviewBox.css('zIndex', 3);

        _slideBox.css('opacity', 0);

        _slideBox.css('margin-top', '0'); // See "Move the hidden slide area..." comment below.

        // adjust opacities
        if (_layoutEngine.layoutType() === Mediasite.Player.StageLayoutType.PrimaryOnly) {
            var slideBoxOpacity = 1;
            if (_layoutEngine.flipLayout()) {
                slideBoxOpacity = 0;
                // Move the hidden slide area off screen to prevent the user from clicking on 
                // the invisible slide zoom buttons when the slide aspect is wider than the 
                // video aspect, the video is primary, and the layout is PrimaryOnly. 
                // NOTE: Using display:none caused the slide image to change size on each reveal.
                // NOTE: This will be very broken if/when we add animations between stage layouts.
                _slideBox.css('margin-top', '9999px');
            }
            _slideBox.css('opacity', slideBoxOpacity);
            _videoBox.css('opacity', slideBoxOpacity ^ 1);

            //Live video will not start if video element is not visible
            if (_videoBox.css('opacity') == 0) {
                _videoBox.css('opacity', 0.001);
            }

        } else {
            _slideBox.css('opacity', '1');
            _videoBox.css('opacity', '1');
        }

        _panel.trigger('stageresize');
    }

    _panel.bind('containerresize', function (evt) {
        evt.stopPropagation();
        // The containerresize event should only be handled when triggered from above.
        // If this handler is called from an event propagating up, 
        // then a handler farther down the DOM tree should prevent propagation.

        _layoutEngine.boundingRect(Mediasite.Player.StageRect.fromElement(_panel));
        updateLayout();
    });

    updateLayout();

    this.getLayoutType = function () { return _layoutEngine.layoutType(); };
    this.setLayoutType = function (value) {
        _layoutEngine.layoutType(value);
        updateLayout();
    };
    this.getPrimaryContentElement = function () { return this.getFlipLayout() ? Mediasite.Player.StageContentElement.Video : Mediasite.Player.StageContentElement.Slide; };
    this.setPrimaryContentElement = function (value) {
        this.setFlipLayout(value === Mediasite.Player.StageContentElement.Video);
    };
    this.getFlipLayout = function () { return _layoutEngine.flipLayout(); };
    this.setFlipLayout = function (value) {
        _layoutEngine.flipLayout(value);
        updateLayout();
    };
    this.getVideoSide = function () { return _layoutEngine.secondarySide(); };
    this.setVideoSide = function (value) {
        var pos = value;
        if (_layoutEngine.flipLayout()) {
            pos = (pos === Mediasite.Player.RightOrLeft.Left) ? Mediasite.Player.RightOrLeft.Right : Mediasite.Player.RightOrLeft.Left;
        }

        _layoutEngine.secondarySide(pos);
        updateLayout();
    };
    this.getSlideAspect = function () { return _layoutEngine.primaryAspect(); };
    this.setSlideAspect = function (value) {
        _layoutEngine.primaryAspect(value);
        updateLayout();
    };
    this.getVideoAspect = function () { return _layoutEngine.secondaryAspect(); };
    this.setVideoAspect = function (value) {
        _layoutEngine.secondaryAspect(value);
        updateLayout();
    };
};
// -=====

// StageLayoutEngine
// +================
Mediasite.Player.StageLayoutEngine = function (layoutStrategyFactory) {

    var _layoutStrategyFactory = layoutStrategyFactory || Mediasite.Player.StageLayoutStrategy.forType;
    var _layoutType = Mediasite.Player.StageLayoutType.SideBySide;
    var _currentLayoutStrategy = null;
    var _boundingRect = new Mediasite.Player.StageRect(0, 0, 400, 300);
    var _primaryAspect = 4 / 3;
    var _secondaryAspect = 4 / 3;
    var _flipLayout = false;
    var _smallBoxSide = Mediasite.Player.RightOrLeft.Right;

    function updateCurrentLayoutStrategy() {
        _currentLayoutStrategy = _layoutStrategyFactory(_layoutType);
    }

    updateCurrentLayoutStrategy();

    this.layoutOptions = {};

    this.layoutType = function (value) {
        if (typeof value !== 'undefined') {
            _layoutType = value;
            updateCurrentLayoutStrategy();
        }
        return _layoutType;
    };

    this.boundingRect = function (value) {
        if (typeof value !== 'undefined') {
            _boundingRect = value;
        }
        return _boundingRect;
    };

    this.primaryAspect = function (value) {
        if (typeof value !== 'undefined') {
            _primaryAspect = value;
        }
        return _primaryAspect;
    };

    this.secondaryAspect = function (value) {
        if (typeof value !== 'undefined') {
            _secondaryAspect = value;
        }
        return _secondaryAspect;
    };

    this.flipLayout = function (value) {
        if (typeof value !== 'undefined') {
            _flipLayout = value;
        }
        return _flipLayout;
    };

    this.secondarySide = function (value) {
        if (typeof value !== 'undefined') {
            _smallBoxSide = value;
        }
        return _smallBoxSide;
    };

    this.getLayout = function () {
        var l;
        if (_flipLayout) {
            l = _currentLayoutStrategy.getLayout(_boundingRect, _secondaryAspect, _primaryAspect, this.layoutOptions);
            l = new Mediasite.Player.StageLayout(l.secondary(), l.primary());
        } else {
            l = _currentLayoutStrategy.getLayout(_boundingRect, _primaryAspect, _secondaryAspect, this.layoutOptions);
        }

        if (_smallBoxSide === Mediasite.Player.RightOrLeft.Left) {
            l = new Mediasite.Player.StageLayout(
			l.primary().flipHorizontal(_boundingRect.width(), _boundingRect.left()),
			l.secondary().flipHorizontal(_boundingRect.width(), _boundingRect.left()));
        }

        return l;
    };
};
// -=====

Mediasite.Player.RightOrLeft = {
    Right: 'Right',
    Left: 'Left'
};

Mediasite.Player.StageContentElement = {
    Video: 'Video',
    Slide: 'Slide'
};

Mediasite.Player.StageLayoutType = {
    SideBySide: 0,
    PictureInPicture: 1,
    PrimaryOnly: 2
};

Mediasite.Player.StagePipSize = {
    Standard: "Standard",
    Small: "Small"
};

Mediasite.Player.StageSideBySideSecondarySize = {
    Small: 'Small',
    Medium: 'Medium',
    Large: 'Large',
    EqualHeight: 'EqualHeight'
};


// StageLayout
// +==========
Mediasite.Player.StageLayout = function (primaryRect, secondaryRect) {
    var _primary = primaryRect;
    var _secondary = secondaryRect;

    this.primary = function () {
        return _primary;
    };
    this.secondary = function () {
        return _secondary;
    };
};

Mediasite.Player.StageLayout.getFittedRect = function (rect, aspect) {
    var boundingAspect = rect.width() / rect.height();

    var height = rect.height();
    var width = rect.width();
    var top = rect.top();
    var left = rect.left();


    if (boundingAspect > aspect) {
        // Bounding Rect has wider aspect.
        width = height * aspect;
        left = (rect.width() - width) / 2.0 + rect.left();
    }
    else {
        // Bounding Rect has taller aspect.
        height = width / aspect;
        top = (rect.height() - height) / 2.0 + rect.top();
    }

    return new Mediasite.Player.StageRect(left, top, width, height);
};

Mediasite.Player.StageLayout.SideBySide = function (boundingRect, primaryAspect, secondaryAspect, layoutOptions) {
    var margin = 16; // pixels to shave off all sides of bounding rect.
    var gutter = 16; // pixel width between content rects.
    var secondarySag = 16; // pixel distance the secondary rect's bottom will be below the primary rect.
    var secondaryTooShortThreshold = 120;

    if (boundingRect.width() <= 0) {
        throw { message: 'Parameter boundingRect must have a width greater than zero.' };
    }

    if (boundingRect.height() <= 0) {
        throw { message: 'Parameter boundingRect must have a height greater than zero.' };
    }


    // Determine the primary-to-secondary height and width ratios. 
    // Because the aspect ratios may differ, the height and width ratios 
    // may not be equal.
    var aspectQuotient = primaryAspect / secondaryAspect;
    var heightRatio = getSideBySideHeightRatio(layoutOptions.SideBySideSecondarySize);
    var widthRatio = heightRatio * aspectQuotient;


    // Define the legal content area as the boundingRect minus a small margin on each side.
    var legalContentArea = new Mediasite.Player.StageRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), boundingRect.height());
    legalContentArea = legalContentArea.contract(margin, margin);

    // The usable width for the two content rects is less than the entire content area 
    // because we leave a gap between them.
    var usableWidth = legalContentArea.width() - gutter;
    var usableHeight = legalContentArea.height();

    // Calculate the zone into which the secondary rect must be fit. 
    // Prevent the secondary rect's size from dropping below a thresholf, 
    // unless there's no choice. 
    var secondaryBaseWidthFraction = 1 / (widthRatio + 1);
    var secondaryBaseHeightFraction = 1 / heightRatio;

    var secondaryThresholdWidthFraction = (secondaryTooShortThreshold * secondaryAspect) / usableWidth;
    var secondaryThresholdHeightFraction = secondaryTooShortThreshold / usableHeight;

    var maxSecondaryWidthFraction = 1.0 / (1 + aspectQuotient);
    var maxSecondaryHeightFraction = 1.0;

    var secondaryWidthFraction = Math.min(maxSecondaryWidthFraction, Math.max(secondaryBaseWidthFraction, secondaryThresholdWidthFraction));
    var secondaryHeightFraction = Math.min(maxSecondaryHeightFraction, Math.max(secondaryBaseHeightFraction, secondaryThresholdHeightFraction));


    // The primary gets the remaining area.
    var primaryWidthFraction = 1.0 - secondaryWidthFraction;
    var primaryHeightFraction = 1.0;


    // Calculate rects that will just fit inside the allowed areas. 
    var primaryColumnWidth = usableWidth * primaryWidthFraction;
    var primaryColumnHeight = usableHeight * primaryHeightFraction;
    var primaryColumn = new Mediasite.Player.StageRect(legalContentArea.left(), legalContentArea.top(), primaryColumnWidth, primaryColumnHeight);
    var primaryRect = Mediasite.Player.StageLayout.getFittedRect(primaryColumn, primaryAspect);

    var secondaryColumnWidth = usableWidth * secondaryWidthFraction;
    var secondaryColumnLeft = legalContentArea.left() + primaryColumnWidth + gutter;
    var secondaryColumnHeight = usableHeight * secondaryHeightFraction;
    var secondaryColumn = new Mediasite.Player.StageRect(secondaryColumnLeft, legalContentArea.top(), secondaryColumnWidth, secondaryColumnHeight);
    var secondaryRect = Mediasite.Player.StageLayout.getFittedRect(secondaryColumn, secondaryAspect);

    if (heightRatio !== 1.0) {
        // This is not an Equivalent height content layout.

        // Place the secondary rect on the far right 
        // and center the primary in the remaining width.
        var greedyPrimaryAreaWidth = usableWidth - secondaryRect.width();
        var primaryLeftMargin = Math.max(0, Math.floor((greedyPrimaryAreaWidth - primaryRect.width()) / 2));
        var primaryLeft = legalContentArea.left() + primaryLeftMargin;
        var secondaryLeft = legalContentArea.right() - secondaryRect.width();

        // When the secondary is about half the height of the primary or shorter, 
        // let the secondary's bottom sag a little below the primary.
        var secondaryTop = primaryRect.bottom() - secondaryRect.height();
        if (secondaryRect.height() < primaryRect.height() * 0.51) {
            secondaryTop += secondarySag;
        }
    }

    // Return the final rects.
    primaryRect = primaryRect.copy({ left: primaryLeft });
    secondaryRect = secondaryRect.copy({ left: secondaryLeft, top: secondaryTop });

    return new Mediasite.Player.StageLayout(primaryRect, secondaryRect);
};

function getSideBySideHeightRatio(sideBySideSecondarySize) {
    switch (sideBySideSecondarySize) {
        case Mediasite.Player.StageSideBySideSecondarySize.EqualHeight:
            return 1 / 1.0;
        case Mediasite.Player.StageSideBySideSecondarySize.Large:
            return 1 / 0.5;
        case Mediasite.Player.StageSideBySideSecondarySize.Small:
            return 1 / 0.3;
        case Mediasite.Player.StageSideBySideSecondarySize.Medium:
        default:
            return 1 / 0.4;
    }
}

Mediasite.Player.StageLayout.PictureInPicture = function (boundingRect, primaryAspect, secondaryAspect, layoutOptions) {
    var margin = 8;
    var maxInnerItem = getPipFraction(layoutOptions.PipSize); // Maximum portion of the primary item covered by the secondary item.

    var primaryColumn = boundingRect.contract(margin * 2, margin * 2);
    var primaryRect = Mediasite.Player.StageLayout.getFittedRect(primaryColumn, primaryAspect);

    var secondaryColumnWidth = primaryRect.width() * maxInnerItem + margin * 2;
    var secondaryColumn = new Mediasite.Player.StageRect(primaryRect.right() - secondaryColumnWidth, boundingRect.top(), secondaryColumnWidth, boundingRect.height());
    var secondaryRect = Mediasite.Player.StageLayout.getFittedRect(secondaryColumn, secondaryAspect);

    // place the secondary item just below and just to the right of the primary item.
    secondaryRect = secondaryRect.copy({
        left: primaryRect.right() + margin * 2 - secondaryRect.width(),
        top: primaryRect.bottom() + margin * 2 - secondaryRect.height()
    });

    return new Mediasite.Player.StageLayout(primaryRect, secondaryRect);
};

function getPipFraction(pipSize) {
    if (pipSize === Mediasite.Player.StagePipSize.Small) {
        return 0.25;
    } else { // Standard (and undefined)
        return 0.35;  // Pre-6.1, was 0.4 but capped at 320px;
    }
}

Mediasite.Player.StageLayout.PrimaryOnly = function (boundingRect, primaryAspect, secondaryAspect) {
    var margin = 8;

    var column = boundingRect.contract(margin * 2, margin * 2.0);
    var primaryRect = Mediasite.Player.StageLayout.getFittedRect(column, primaryAspect);
    var secondaryRect = Mediasite.Player.StageLayout.getFittedRect(column, secondaryAspect);

    return new Mediasite.Player.StageLayout(primaryRect, secondaryRect);
};
// -=====

// StageLayoutStrategy
// +==================
Mediasite.Player.StageLayoutStrategy = function (getLayout) {
    this.getLayout = getLayout;
};

Mediasite.Player.StageLayoutStrategy.forType = function (layoutType) {
    if (layoutType === Mediasite.Player.StageLayoutType.PrimaryOnly) {
        return new Mediasite.Player.StageLayoutStrategy(Mediasite.Player.StageLayout.PrimaryOnly);
    } else if (layoutType === Mediasite.Player.StageLayoutType.PictureInPicture) {
        return new Mediasite.Player.StageLayoutStrategy(Mediasite.Player.StageLayout.PictureInPicture);
    } else {
        return new Mediasite.Player.StageLayoutStrategy(Mediasite.Player.StageLayout.SideBySide); // default (even if layoutType is junk).
    }
};
// -=====

// StageRect
// +========
Mediasite.Player.StageRect = function (left, top, width, height) {
    Mediasite.Geometry.Rect.apply(this, arguments);
}
jQuery.extend(Mediasite.Player.StageRect.prototype, {

    // this is the verb 'contract' which is the opposite of expand.
    contract: function (x, y) {
        x = x || 0;
        y = y || 0;

        var newWidth = this.width();
        var newHeight = this.height();
        var newLeft = this.left();
        var newTop = this.top();

        if (x * 2 < this.width() && y * 2 < this.height()) {
            newWidth -= x * 2;
            newHeight -= y * 2;
            newLeft += x;
            newTop += y;
        }

        return new Mediasite.Player.StageRect(newLeft, newTop, newWidth, newHeight);
    },

    copy: function (changeProps) {
        if (!changeProps) {
            return new Mediasite.Player.StageRect(this.left(), this.top(), this.width(), this.height());
        }

        var left = (typeof changeProps.left === 'undefined') ? this.left() : changeProps.left;
        var top = (typeof changeProps.top === 'undefined') ? this.top() : changeProps.top;
        var width = (typeof changeProps.width === 'undefined') ? this.width() : changeProps.width;
        var height = (typeof changeProps.height === 'undefined') ? this.height() : changeProps.height;

        return new Mediasite.Player.StageRect(left, top, width, height);
    },

    flipHorizontal: function (containerWidth, containerLeft) {
        var newLeft = (containerWidth + 2 * containerLeft) - this.right();

        return this.copy({ left: newLeft });
    }
});
Mediasite.Player.StageRect.fromElement = function (element) {
    if (!element) {
        return new Mediasite.Player.StageRect();
    }

    var position = element.position();
    return new Mediasite.Player.StageRect(position.left, position.top, element.width(), element.height());

};


// Module is invoked in places where a panel is being hidden:
// toggleDetailPanel
// toggleInteractivityPanel
// dismissPanels



/******************************************************************************************************************************
This function will register the player view so it can be used by the player engine
*******************************************************************************************************************************/
Mediasite.Player.Register(Mediasite.Player.PlayerType.NewStandardPlayer,
    {
        View: Mediasite.Player.NewStandardView,
        LoadFunction: function (callback) {
            var scripts = [
                "Javascript/Scripts/jquery.enableTouch.js",
                "Javascript/Scripts/3rdParty/jquery.mousewheel.js",
                "Javascript/Scripts/jquery.imageButton.js",
                "Javascript/Scripts/SpriteAnimation.js",
                "Javascript/Scripts/3rdParty/jquery.ba-resize.js",
                "Javascript/Scripts/jquery.iscroll.js",
                "Javascript/Scripts/jquery.ui.playerinfopanel.js",
                "Javascript/Scripts/jquery.ui.playerccsearchpanel.js",
                "Javascript/Scripts/jquery.ui.playercaptionpanel.js",
                "Javascript/Scripts/jquery.ui.playerchapterspanel.js",
                "Javascript/Scripts/jquery.ui.playeraskpanel.js",
                "Javascript/Scripts/jquery.ui.playerlinkspanel.js",
                "Javascript/Scripts/jquery.ui.playerinvitepanel.js",
                "Javascript/Scripts/jquery.ui.playerspeed.js",
                "Javascript/Scripts/jquery.ui.playervolume.js",
                "Javascript/Scripts/jquery.ui.playerfidelity.js",
                "Javascript/Scripts/SlideNav.js",
                "Javascript/Scripts/Mediasite.Player.PanelFocusResetter.js",
                "Javascript/Scripts/SlideInspector.js"
            ];

            var onScriptsLoaded = function () {

                if (Mediasite.BrowserDetect.IOS()) {
                    $("html").addClass("fixedViewport");
                }

                var size = 768, viewport;
                if (Mediasite.BrowserDetect.Android()) {
                    var initialScale = window.innerWidth / size;
                    viewport = "width=" + size + ",initial-scale=" + initialScale + ",maximum-scale=1.0";
                } else {
                    viewport = "width=" + size + ",maximum-scale=1.0";
                }

                if (viewport) {
                    $(document.head).find("meta[name=viewport]").remove();
                    var element = $("<meta name=viewport />").attr('content', viewport).appendTo(document.head);
                }

                // Mediasite.Logging.Log("Viewport: " + viewport);

                if (callback) {
                    callback();
                }
            };

            Mediasite.loadScripts(scripts, onScriptsLoaded);
        },
        MarkupUrl: 'Javascript/Players/NewStandardPlayer/NewStandardPlayer.html',
        MediaElementOptions:
            {
                backgroundElement: $('.contentBox')
            },
        StyleSheetFiles: [
                'NewStandardPlayer.css',
                'NewStandardPanels.css'
            ],
        ContentCapability: Mediasite.Player.ContentCapability.VideoAndSlides
    });
