Mediasite.Player.MediasitePlayer = function (options) {

    var presentationId = options.ResourceId;
    var serviceLocation = options.ServicePath;
    var parentElementId = options.PlayerContentId;
    var urlReferrer = options.UrlReferrer;
    var providerType = options.DataProviderType;
    var customHeader = options.CustomHeader;
    var loadingOverlay = new Mediasite.Player.Overlay();

    var playerView;
    var playerModel;
    var viewTracking;
    var stateReporting;
    var bookmarkStore;
    var search;
    var mediaPlayerModelOptions;
    var logger = Mediasite.Logging.LoggerFactory("Controller", { separator: "\n" });
    var playerState = { mediaState: undefined };
    var streamViewerManager;
    var mediaPlayerEventHandlers;
    var slideTrackerEventHandlers;
    var playbackSpeeds;
    var playerOptions;
    var playerStateManager = new Mediasite.Player.PlayerStateManager();
    var ariaMessageFactory;
    var playerContext;
    var playCover, playCoverStatusWatcher;

    if (Mediasite.GetQueryParam("loadLog", Mediasite.GetQueryParam.AsBool) == true) {
        Mediasite.LogViewer.Load();
    }

    var dataProvider = Mediasite.Player.DataProvider.GetProvider(providerType, presentationId, serviceLocation, parentElementId, urlReferrer, customHeader);
    dataProvider.LoadPlayerData(function (context) {
        playerContext = context;

        if (playerContext.Success) {

            //do iphone check
            if (Mediasite.Player.IosAppDetectionOptions) {
                var iosAppDetection = new IosAppDetection(Mediasite.Player.IosAppDetectionOptions);
                $(iosAppDetection).on('NotIosAppCandidate', beforeStartPlayerLoad);
                $(iosAppDetection).on('IosAppMessageClosed', beforeStartPlayerLoad);
                iosAppDetection.Run();
            } else {
                beforeStartPlayerLoad();
            }

            var playbackSpeeds = parsePlaybackSpeedsString(playerContext.GlobalOptions.PlaybackSpeeds);
            if (playbackSpeeds.length > 0) {
                Mediasite.MediaPlayer.ViewOptions.playbackRates = playbackSpeeds;
            }
        } else {
            setLoadingError(playerContext.error);
        }
    });

    function beforeStartPlayerLoad() {
        var convivaScripts = ["Javascript/Scripts/3rdParty/conviva-html5native-library.min.jsx", "Javascript/Scripts/ConvivaImplementation.js"];

        if (playerContext.GlobalOptions.EnableConviva) {
            Mediasite.loadScripts(convivaScripts, startPlayerLoad);
        } else {
            startPlayerLoad();
        }
    }


    function startPlayerLoad() {
        var pres = playerContext.CurrentPresentation;
        var i;

        playerContext.PlaybackOptions.AutoStart = true;

        playerContext.plugins = Mediasite.Player.doAllPluginDetection(playerContext);

        // Calculate media playback strategies for all video streams.
        calculatePlaybackStrategiesForStreams(pres.Streams, playerContext.plugins.available, pres.IsLivePresentation(), playerContext.GlobalOptions.FavorDeliverHLS);

        // Populate this old value so that some old code elsewhere functions.
        playerContext.GlobalOptions.PlayerContentPlugin = makePlayerContentPluginValue(pres.Streams);

        // Determine if we must fetch updated video source info when going live.
        playerContext.CurrentPresentation.mustRefreshVideoUrlsOnTransitionToLive = mustRefreshVideoUrlsOnTransitionToLive();

        // Verify that playback is possible with the available plugins and media.
        if (playerContext.GlobalOptions.PlayerContentPlugin.MediaPlayerType === Mediasite.Player.MediaPlayerType.Unknown) {
            Mediasite.Player.showZeroPlaybackStrategiesError(playerContext.plugins, playerContext.GlobalOptions.UseScreenReader);
            setLoadingError({ errorCode: 610, details: Mediasite.Player.Localization.ClientDetection.ErrorPageClientLoadError });
            return;
        }

        var playerOptionsPath = Mediasite.Player.AppPaths.PlayerView.format(playerContext.PlayerLayoutOptions.PlayerType);

        

        populateVideoElementPool(options.videoElementsForPool);

        Mediasite.loadScripts(playerOptionsPath, executeViewLoader);
    }

    function callDummyPlay(vidElement) {
        var promise = vidElement.play();
        if (promise) {
            promise.catch(function (error) { });
        }
    }

    function populateVideoElementPool(videoElements) {
        if (videoElements && videoElements.length && videoElements.length > 0) {
            for (i = 0; i < options.videoElementsForPool.length; i += 1) {
                Mediasite.Player.videoElementPool.addElement(options.videoElementsForPool[i]);
            }
        }
    }

    Mediasite.Player.videoElementPool = (function() {
        var elements = [];

        return {
            addElement: function (element) {
                elements.push(element);
            },
            getElement: function () {
                if (elements.length > 0) {
                    return elements.shift();
                } else {
                    return document.createElement("video");
                }
                
            },
            returnElement: function (element) {
                var i;

                for (i = 0; i < element.children; i += 1) {
                    element.removeChild(element.children[i]);
                }

                if (element.parentNode) {
                    vid.parentNode.removeChild(vid);
                }
                
                element.removeAttribute("style");
                element.removeAttribute("id");
                element.className = "";
                this.addElement(element);
            }
        };
    })();

    function getPresentationStatus(callback) {
        var successCallback = function (data) {
            callback({
                status: data.d.PlayStatus,
                liveStartUnixTime: data.d.LiveStartUnixTimeInMs
            });
        };
        var errorCallback = function () { callback({ status: null }); };
        var request = JSON.stringify({ 
            playbackTicket: playerContext.CurrentPresentation.PlaybackTicketId, 
            presentationId: playerContext.CurrentPresentation.PresentationId
        });

        dataProvider.GetLiveStatus(request, successCallback, errorCallback);
    }

    function isCurrentlyLive(playState) {
        return playState === Mediasite.Player.PresentationStatus.Live || playState === Mediasite.Player.PresentationStatus.LivePaused;
    }

    function isWaitingToBeginLive(playState) {
        return playState === Mediasite.Player.PresentationStatus.ScheduledForLive || playState === Mediasite.Player.PresentationStatus.OpenForLive;
    }

    function isPlayableState(playState) {
        return playState === Mediasite.Player.PresentationStatus.OnDemand || isCurrentlyLive();
    }

    function mustRefreshVideoUrlsOnTransitionToLive() {
        // This is a crude approach.
        return (playerContext.GlobalOptions.PlayerContentPlugin.MediaPlayerType === Mediasite.Player.MediaPlayerType.RampHLS);
    }

    function calculatePlaybackStrategiesForStreams(streams, availablePlugins, isLive, liveFavorHls) {
        var i, s, playbackStrategies;
        var calc = Mediasite.MediaPlayer.MediaPlayerSelectionEngine.create(isLive, liveFavorHls);
        for (i = 0; i < streams.length; i += 1) {
            s = streams[i];
            if (playerContext.GlobalOptions.IsLayoutPreview) {
                s.playbackStrategies = getLayoutPreviewPlaybackStrategies();
            } else {
                s.playbackStrategies = calc.calculateMediaPlayers(availablePlugins, s.VideoUrls);
            }
        }
    }

    function getLayoutPreviewPlaybackStrategies() {
        return [{
            pluginType: Mediasite.Player.MediaPlugins.HTML5,
            source: 'fake video source url'
        }];
    }

    function makePlayerContentPluginValue(streams) {
        var i;
        for (i = 0; i < streams.length; i += 1) {
            if (streams[i].playbackStrategies && streams[i].playbackStrategies.length > 0) {
                return {
                    MediaPlayerType: Mediasite.Player.MediaPlayerType.FromPluginType(streams[i].playbackStrategies[0].pluginType),
                    MimeType: streams[i].playbackStrategies[0].source.MimeType
                }
            }
        }

        // Didn't find anything, so return an dummy instance.
        return { MediaPlayerType: Mediasite.Player.MediaPlayerType.Unknown, MimeType: Mediasite.Player.MimeTypes.Unknown };
    }

    function setLoadingError(errorObject) {
        loadingOverlay.Hide();
        Mediasite.Player.APIBroker.playerNotInitialized(errorObject);
        Mediasite.Player.API.error = errorObject;
    }

    function executeViewLoader() {
        playerOptions = Mediasite.Player.Register.Players[playerContext.PlayerLayoutOptions.PlayerType];

        if (playerOptions) {
            if (!isPlayerCompatible()) {
                showIncompatiblePlayerError();
            } else {
                loadStyleSheets(onLoadStyleSheets);
            }
        }

        function onLoadStyleSheets() {
            $("#" + parentElementId).show(); // content can be revealed without FOUC now that stylesheets have been loaded
            playerOptions.LoadFunction(loadPlayer);
        }
    }

    function loadStyleSheets(successCallback) {
        var stylesheets = getStyleSheetPaths();
        Mediasite.Css.LoadStyleSheets(stylesheets, successCallback, errorCallback);


        function errorCallback(failedStylesheets) {
            loadingOverlay.Hide();

            logger.Error("Failed to load CSS files", failedStylesheets);

            Mediasite.Player.DisplayMessage({
                message: "Player CSS files failed to load.",
                isError: true,
                width: '500',
                buttons: []

            });
        }
    }

    function getStyleSheetPaths() {
        var filenames = playerOptions.StyleSheetFiles;
        var playerName = playerContext.PlayerLayoutOptions.PlayerType;
        var theme = playerContext.PlayerLayoutOptions.ThemeId;

        var paths = $.map(filenames, function (filename, index) {
            var main = Mediasite.Player.AppPaths.StyleSheet.format(playerName, filename, Mediasite.getVersionToken());
            var themed = theme && Mediasite.Player.AppPaths.ThemedStyleSheet.format(playerName, theme, filename, Mediasite.getVersionToken());

            var paths = [main];
            themed && paths.push(themed);
            return paths;
        });

        return paths;
    }

    function loadPlayer() {

        loadingOverlay.Hide();

        $.each(playerContext.CurrentPresentation.Streams, function (index, stream) {
            var info = [];
            info.push('StreamType=' + stream.StreamType);
            info.push('Priority=' + stream.Priority);
            info.push('AspectRatio=' + stream.AspectRatio);
            if (stream.HasSlides()) {
                info.push(stream.Slides.length + ' slides');
            } else {
                info.push('No slides');
            }
            if (stream.HasVideo()) {
                $.each(stream.VideoUrls, function (index, video) {
                    var videoNum = stream.VideoUrls.length > 1
                        ? 'Video ' + (index + 1) + '/' + stream.VideoUrls.length
                        : 'Video';
                    info.push(videoNum + '=' + video.Location);
                });
            }

            info = info.join('\n');
            logger.Info(info);
        });

        //Create Player View
        playerView = new playerOptions.View(playerContext);

        //Load Player HTML
        dataProvider.LoadMarkup(playerOptions.MarkupUrl, Mediasite.getVersionToken(), continueLoadingPlayer);
    }

    function continueLoadingPlayer() {
        //MediaElement Options
        mediaPlayerModelOptions = $.extend({}, Mediasite.MediaPlayer.ViewOptions, playerOptions.MediaElementOptions,
        {
            mediaPlayerType: playerContext.GlobalOptions.PlayerContentPlugin.MediaPlayerType,
            pluginMimeType: playerContext.GlobalOptions.PlayerContentPlugin.MimeType,
            height: playerContext.PlayerLayoutOptions.VideoHeight,
            width: playerContext.PlayerLayoutOptions.VideoWidth,
            isStandAlone: playerContext.CurrentPresentation.IsStandAlone,
            isMobile: Mediasite.BrowserDetect.Mobile(),
            playButtonText: Mediasite.Player.Localization.Buttons.Play,
            liveSmoothStreamingOffset: playerContext.GlobalOptions.LiveSmoothStreamingOffset
        });

        //Create Player Model
        playerModel = new Mediasite.Player.Model(dataProvider);
        playerModel.Initialize(playerContext);

        search = new Mediasite.Player.PresentationContentSearch(dataProvider, playerContext.CurrentPresentation.PlaybackTicketId);

        //Create Event Handlers
        if (!playerContext.GlobalOptions.IsLayoutPreview) {
            initializeEvents();
            playerStateManager.MediaStateChange(Mediasite.Player.MediaState.Undefined);
        }

        //Initialize Player View and Create Stream View Handlers
        playerView.LoadLayout();
        var viewContext = {
            getStreamViewHandler: playerView.GetStreamViewHandler.bind(playerView),
            contentCapability: playerOptions.ContentCapability
        };
        streamViewerManager = new Mediasite.Player.StreamViewerManager(playerContext.CurrentPresentation.Streams, mediaPlayerModelOptions, mediaPlayerEventHandlers, slideTrackerEventHandlers, viewContext, playerModel, playerContext);

        if (playerContext.GlobalOptions.IsLayoutPreview) {
            playerView.LoadLayout();
        } else {
            playerView.UpdatePresentationData(playerContext.CurrentPresentation);
            playerView.UpdateTimelineMarkers(playerModel.GetTimelineMarkers());
            updateUserPreferences();

            playerModel.SetInactivityTimeout(playerContext.GlobalOptions.SessionTimeout);

            connectAPI();

            loadExtensions();

            //Load Player Media Content
            playerModel.LoadMedia();
            logger.Debug("Player Loaded...");
        }
    }

    function isPlayerCompatible() {

        var compatible = true;

        if (playerOptions && playerContext && playerContext.CurrentPresentation && !playerContext.GlobalOptions.IsLayoutPreview) {
            if (playerOptions.ContentCapability == Mediasite.Player.ContentCapability.VideoAndSlides) {

                if (playerContext.CurrentPresentation.Streams.length > 2) {
                    compatible = false;
                } else {

                    var videoCount = 0;
                    $.each(playerContext.CurrentPresentation.Streams, function (index, stream) {
                        if (stream.StreamType != Mediasite.ContentStreamType.Slide) {
                            videoCount++;
                        }
                    });

                    if (videoCount > 1) {
                        compatible = false;
                    }
                }
            }
        }

        return compatible;
    }

    function showIncompatiblePlayerError() {
        var errorMessage = Mediasite.Player.Localization.ClientDetection.NeedMultiView;

        loadingOverlay.Hide();

        Mediasite.Player.DisplayMessage({
            message: errorMessage,
            isError: true,
            width: '500',
            buttons: []

        });
    }

    function initializeEvents() {
        playerView = $.extend(new Mediasite.Player.BaseView(), playerView);
        playerModel = $.extend(new Mediasite.Player.BaseModel(), playerModel);

        viewTracking = new Mediasite.Player.CurrentViewTracking();
        stateReporting = new Mediasite.Player.StateReporting();
        ariaMessageFactory = new Mediasite.Player.AriaMessageFactory();

        playerStateManager.AddEventHandler({
            PlayerStateChanged: function (playerState) {
                playerModel.UpdatePlayerState(playerState);
            }
        });

        mediaPlayerEventHandlers = {
            CommonHandlers: {
                MediaError: function (error) {
                    playerStateManager.MediaError(error);
                    playerModel.HandleMediaError(error);
                },

                MediaLoaded: function (mediaInfo) {
                    logger.Debug("Stream media metadata loaded", mediaInfo);
                    var mediaData = streamViewerManager.IsMediaLoaded(mediaInfo);
                    if (mediaData != undefined) {
                        connectBookmarks(mediaData.duration);
                        playerModel.UpdateMediaInfo(mediaData.videoInfo);
                        playerView.UpdateMediaInfo(mediaData.videoInfo);

                        if (playerContext.PlaybackOptions.StartPosition > 0) {
                            streamViewerManager.ExecuteMediaPlayerModelMethod('SetPosition', playerContext.PlaybackOptions.StartPosition);
                        }

                        if (playerContext.PlaybackOptions.AutoStart && !(playerContext.GlobalOptions.UseScreenReader)) {
                            streamViewerManager.ExecuteMediaPlayerModelMethod('Play');
                        } else {
                            if (!Mediasite.BrowserDetect.Mobile()) {
                                streamViewerManager.ExecuteMediaPlayerModelMethod('Pause');
                            }
                            playerContext.PlaybackOptions.AutoStart = true;
                        }
                    }
                },

                MediaUpdated: function (mediaInfo) {
                    var mediaData = streamViewerManager.IsMediaLoaded(mediaInfo);
                    logger.Debug("Stream media metadata updated", mediaInfo || "no media info", mediaData || "no collated media data");
                    if (mediaData != undefined) {
                        logger.Debug("update model/view!");
                        playerModel.UpdateMediaInfo(mediaData.videoInfo);
                        playerView.UpdateMediaInfo(mediaData.videoInfo);
                    }
                },

                MediaFidelityChanged: function (fidelitySummary) {
                    playerView.UpdateMediaFidelity(fidelitySummary);
                }
            },

            MainHandlers: {
                MediaLoadStart: function () {
                    playerView.MediaLoadStart();
                },
                MediaEvent: function (event) {
                    playerModel.HandleMediaEvent(event);
                },

                StateChanged: function (state) {
                    playerStateManager.MediaStateChange(state);
                    playerState.mediaState = state;
                    playerModel.UpdateMediaState(state);
                    playerView.UpdateMediaState(state);
                    executeSlideTrackerMethod("UpdateMediaState", { State: state });
                },
                VolumeChanged: function (volume) {
                    playerModel.UpdateMediaVolume(volume);
                    playerView.UpdateMediaVolume(volume);
                },
                PlaybackRateChanged: function (rateInfo) {
                    playerView.UpdatePlaybackRate(rateInfo);
                    streamViewerManager.UpdatePlaybackRate(rateInfo.Current);
                },
                PositionChanged: function (position, isFromMediaPlayer) {
                    playerModel.UpdatePosition(position, isFromMediaPlayer);
                    playerView.UpdatePosition(position, isFromMediaPlayer);
                    streamViewerManager.UpdateStreamViewerPosition(position, playerContext.CurrentPresentation.IsLivePresentation());

                    //Pause after specified duration
                    if (playerContext.PlaybackOptions.PauseAt > 0 && playerContext.PlaybackOptions.PauseAt <= position) {
                        streamViewerManager.ExecuteMediaPlayerModelMethod('Pause');
                        playerContext.PlaybackOptions.PauseAt = -1;
                    }

                },
                EnableLiveJumpBackDetection: function () {
                    playerModel.EnableLiveJumpBackDetection();
                },
                EnableLiveStartDelay: function (delayInMs) {
                    playerModel.EnableLiveStartDelay(delayInMs);
                },
                SeekStarting: function () {
                    playerModel.SetIsSeeking(true);
                },
                SeekEnding: function () {
                    playerModel.SetIsSeeking(false);
                }
            }
        };

        slideTrackerEventHandlers = {
            SlideChange: function (slide) {
                streamViewerManager.UpdateCurrentSlide(slide);
                playerModel.FireEvent(Mediasite.Player.StreamViewerEvent.SlideChange, slide);
            },
            AddNewSlide: function (slide) {
                streamViewerManager.AddNewSlide(slide);
                playerModel.FireEvent(Mediasite.Player.StreamViewerEvent.AddNewSlide, slide);
            }
        };

        playerModel.AddEventHandler({
            InactivityExceeded: function () {
                playerView.InactivityExceeded();
                streamViewerManager.ExecuteMediaPlayerModelMethod('InactivityExceeded');
            },
            EmailInviteLoaded: function (emailData) {
                playerView.UpdateEmailInvite(emailData);
            },
            UserEmailAddressLoaded: function (emailAddress) {
                playerView.UpdateUserEmailAddress(emailAddress);
            },
            StartMedia: function (mediaUrls) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SetupMediaElement', mediaUrls);
            },
            CaptionChange: function (captions) {
                var loneCaption;

                if (captions && captions.length > 0) {
                    loneCaption = captions[captions.length - 1];
                }

                // Old, obsolete single caption method.
                playerView.UpdateCurrentCaption(loneCaption);

                // New plural caption hotness.
                playerView.UpdateCurrentCaptions(captions);
            },
            SendQuestionComplete: function (success, message) {
                playerView.SendQuestionComplete(success, message);
            },
            SendEmailComplete: function (success, message) {
                playerView.SendEmailComplete(success, message);
            },
            PlayerStateChanged: function (playerState) {
                playerView.UpdatePlayerState(playerState);
                if (playerState.IsLive && playerState.State === Mediasite.Player.PlayerState.Ended) {
                    streamViewerManager.ExecuteMediaPlayerModelMethod('FinalizeLive');
                }
            },
            VisibleStreamsChanged: function (streamTypes) {
                playerView.UpdateVisibleStreams(streamTypes);
            },
            LiveStatusChanged: function (status) {
                playerStateManager.LiveStatusChange(status);
                playerView.LiveStatusChange(status);
                streamViewerManager.ExecuteMediaPlayerModelMethod('LiveStatusChange', status);

                if (playCover) {
                    playCover.presentationStatus = status;
                }
            },
            SetLiveStartTime: function (time) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SetLiveStartTime', time);
            },
            MediaError: function (error) {
                playerView.ShowErrorMessage(Mediasite.Player.Localization.MediaPlayer.ErrorTitle, error);
            },
            TimelineMarkerAdded: function (timelineMarker) {
                playerView.AddTimelineMarker(timelineMarker);
            },
            TimelineMarkerRemoved: function (timelineMarkerId) {
                playerView.RemoveTimelineMarker(timelineMarkerId);
            },
            TimelineMarkerUpdated: function (timelineMarker) {
                playerView.RemoveTimelineMarker(timelineMarker.id);
                playerView.AddTimelineMarker(timelineMarker);
            }
        });

        search.AddEventHandler({
            SearchComplete: function (searchTerm, results) {
                playerView.DisplaySearchResults(searchTerm, results);
            },
            SearchError: function () {
                playerView.DisplaySearchError();
            }
        });

        playerView.AddEventHandler({
            AudioLanguageChanged: function (language) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SetAudioLanguage', language);
            },
            SendQuestion: function (question) {
                playerModel.SendQuestion(question);
            },
            SendEmail: function (email) {
                playerModel.SendEmail(email);
            },
            Search: function (searchTerm) {
                search.search(searchTerm);
            },
            VolumeChanged: function (volume) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SetVolume', volume);
            },
            PlaybackRateChanged: function (speed) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SetPlaybackRate', speed);
            },
            PlaybackRateFaster: function (doLoop) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('PlayFaster', doLoop);
            },
            PlaybackRateSlower: function (doLoop) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('PlaySlower', doLoop);
            },
            PositionChanged: function (position) {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SetPosition', position);
            },
            PreferenceChanged: function (pref, val) {
                playerModel.SetPreference(pref, val);
            },
            VisibleStreamsChanged: function (visibleStreamTypes) {
                playerModel.SetVisibleStreamTypes(visibleStreamTypes);
            },
            TogglePlayPause: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('TogglePlayPause');
            },
            ToggleSlideShow: function () {
                playerView.ToggleSlideBrowser();
            },
            SkipBack: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SkipBack');
            },
            SkipForward: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('SkipForward');
            },
            ToggleCaptions: function () {
                playerView.ToggleCaptionDisplay();
            },
            ToggleSearch: function () {
                playerView.ToggleSearch();
            },
            FullScreen: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('FullScreen');
            },
            Mute: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('ToggleMute');
            },
            VolumeUp: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('StepVolumeUp');
            },
            VolumeDown: function () {
                streamViewerManager.ExecuteMediaPlayerModelMethod('StepVolumeDown');
            },
            AskQuestion: function () {
                playerModel.GetUserEmailAddress();
            },
            UpdateAskQuestionEmailAddress: function (emailAddress) {
                playerModel.UpdateAskQuestionEmailAddress(emailAddress);
            },
            OpenEmail: function () {
                playerModel.GetEmailInvite();
            },
            ShowPolls: function () {
                playerView.ShowPolls();
            },
            ShowLinks: function () {
                playerView.ShowLinks();
            },
            ShowHelp: function () {
                playerView.ShowHelp();
            },
            ShowChapters: function () {
                playerView.ShowChapters();
            },
            ShowSlideList: function () {
                playerView.UpdateSlideBrowserView(Mediasite.Player.SlideDisplayPref.List);
                playerModel.SetPreference(Mediasite.Player.Options.SlideDisplay, Mediasite.Player.SlideDisplayPref.List);
            },
            ShowSlideSmallThumbs: function () {
                playerView.UpdateSlideBrowserView(Mediasite.Player.SlideDisplayPref.SmallThumbs);
                playerModel.SetPreference(Mediasite.Player.Options.SlideDisplay, Mediasite.Player.SlideDisplayPref.SmallThumbs);
            },
            ShowSlideLargeThumbs: function () {
                playerView.UpdateSlideBrowserView(Mediasite.Player.SlideDisplayPref.LargeThumbs);
                playerModel.SetPreference(Mediasite.Player.Options.SlideDisplay, Mediasite.Player.SlideDisplayPref.LargeThumbs);
            },
            ShowSlideText: function () {
                playerView.ToggleSlideText();
            },
            ShowInfo: function () {
                playerView.ShowInfo();
            },
            PopOut: function () {
                var currentMediaState = playerState.mediaState;
                if (typeof currentMediaState != "undefined") {
                    streamViewerManager.ExecuteMediaPlayerModelMethod('Pause');
                }
                playerView.LaunchPopOut(currentMediaState);
            },
            PlayAsVideo: function (streamType) {
                streamViewerManager.PlayAsVideo(streamType);
            },
            DismissPanels: function () {
                playerView.DismissPanels();
            },
            ToggleLogViewer: function () {
                if (!Mediasite.LogViewer.Loaded()) {
                    Mediasite.LogViewer.Load();
                } else {
                    Mediasite.LogViewer.Destroy();
                }
            },
            ToggleScreenReader: function () {
                if (typeof window.toggleScreenReaderMode === "function") {
                    // In stand-alone mode, there will exist a function to handle
                    // the transition to/from screen reader mode.
                    window.toggleScreenReaderMode();
                } else {
                    playerModel.TogglePreference(Mediasite.Player.Options.UseScreenReader);
                    window.location.reload();
                }
            }
        });

        function executeSlideTrackerMethod(method, slideData) {
            var slide = streamViewerManager.ExecuteSlideTrackerMethod(method, slideData);

            if (slide) {
                playerModel.UpdatePosition(slide.Time);
                playerModel.FireEvent(Mediasite.Player.ModelEvent.PositionChange, slide.Time);
            }
        }
    }

    function connectAPI() {
        Mediasite.Player.API._registerModels(streamViewerManager.MainStreamViewer.MediaPlayerModel, playerModel, playerView, playerContext.UserData.PastSessionPlayedSegments);
        Mediasite.Player.APIBroker.initialize(Mediasite.Player.API, playerContext.GlobalOptions.AllowedPlayerIFrameAPISites); // TODO: pull this from playerContext

        viewTracking.reportToDataProvider(playerContext.CurrentPresentation.PlaybackTicketId, dataProvider);
        viewTracking.trackPresentation(Mediasite.Player.API);

        stateReporting.reportToDataProvider(playerContext.CurrentPresentation.PlaybackTicketId, dataProvider);
        stateReporting.watchPlayer(Mediasite.Player.API);
        stateReporting.setMediaPlayerType(mediaPlayerModelOptions.mediaPlayerType);

        ariaMessageFactory.watchPlayerApi(Mediasite.Player.API);
    }

    function connectBookmarks(presentationDuration) {
        if (playerContext.CurrentPresentation.PlayStatus == Mediasite.Player.PresentationStatus.OnDemand) {
            bookmarkStore = new Mediasite.Player.BookmarkStore(playerContext.CurrentPresentation.PresentationId, presentationDuration, false, playerContext.CurrentPresentation.ServerClockSkew);
            bookmarkStore.watchViewTracking(viewTracking, playerContext.CurrentPresentation.PlaybackTicketId);
        }
    }

    function updateUserPreferences() {
        playerView.UpdateOptions(playerContext.UserData.UserPreferences);
        streamViewerManager.ExecuteMediaPlayerModelMethod('UpdateOptions', playerContext.UserData.UserPreferences);
    }

    function loadExtensions() {

        if (!playerContext.GlobalOptions.UseExtensions) return;


        var usableExtensions = $.grep(playerContext.CurrentPresentation.PlayerExtensions, function (extension) {
            var supportsPlayerType = !extension.PlayerTypes.length
                || $.inArray(playerContext.PlayerLayoutOptions.PlayerType, extension.PlayerTypes) != -1;

            return supportsPlayerType;
        });

        var extensionScriptArray = $.map(usableExtensions, function (extension, index) {
            return extension.ExtensionBasePath + 'Extension.js';
        });

        if (extensionScriptArray.length > 0) {

            //Load Extension Scripts
            Mediasite.loadScripts(extensionScriptArray, function () {

                //Load any registered extensions
                $.each(Mediasite.Player.Register.Extensions, function (key, extension) {
                    var selectedExtension = playerContext.CurrentPresentation.GetPlayerExtension(key);
                    if (selectedExtension) {
                        new extension.Constructor(Mediasite.Player.API, selectedExtension, ariaMessageFactory);
                    }
                });
            });
        }
    }

    function parsePlaybackSpeedsString(theString) {
        var pattern = /([\d\.]+)/g;
        var matches, i, num;
        var results = [];

        if (typeof theString !== 'string') {
            return [];
        }

        matches = theString.match(pattern);

        if (!matches) {
            return [];
        }

        for (i = 0; i < matches.length; i += 1) {
            num = Number(matches[i]);
            if (!isNaN(num)) {
                results.push(num);
            }
        }

        return results;
    }
};
