// <reference path="../ScriptReference/jquery-1.7.1-vsdoc.js"/>
/// <reference path="Mediasite.Core.js"/>
/// <reference path="Mediasite.Player.Core.js"/>
/// <reference path="Mediasite.Player.Localization.js"/>
/*global Mediasite OnDSPlayStateChangeEvt : true, OnDSPositionChangeEvt : true, OnDSOpenStateChangeEvt : true, OnDSScriptCommandEvt : true, OnDSMediaErrorEvt : true */

Mediasite.namespace("MediaPlayer");


// MediaPlayerSelectionEngine
(function () {

    function SourceMatcher(sourceSpec) {
        var self = this;

        this.mediaServerType;
        this.mediaType;
        this.mimeType;


        if (typeof sourceSpec === 'object') {
            this.mediaServerType = sourceSpec.ServerType;
            this.mediaType = sourceSpec.MediaType;
            this.mediaMimeType = sourceSpec.MimeType;
        }


        this.match = function (videoSource) {

            return videoSource &&
                videoSource.MediaType === self.mediaType &&
                videoSource.MimeType === self.mediaMimeType &&
                videoSource.ServerType === self.mediaServerType;
        };
    }

    function CompositeAnySourceMatcher(matchers) {
        var self = this;

        matchers = matchers || [];

        this.addMatcher = function (matcher) {
            matchers.push(matcher);
        };

        this.match = function (videoSource) {
            var i;

            for (i = 0; i < matchers.length; i += 1) {
                if (matchers[i].match(videoSource)) {
                    return true;
                }
            }
        };
    }

    function StandardMatcher(sourceMatcher, pluginType) {
        var self = this;

        this.requiredCapabilities = [];
        this.sourceMatcher = sourceMatcher;
        this.pluginType = pluginType;

        this.match = function (clientCaps, videoSource) {
            return (clientCaps & self.pluginType) &&
                sourceMatcher.match(videoSource);
        };
    }

    

    function MediaPlayerSelectionEngine (matchers) {
        var self = this;

        // returns Array.
        this.calculateMediaPlayers = function (clientCapabilities, videoSources) {
            var results = [];
            var i, j;
            var matcher, source;

            // TODO: Validate clientCapabilities and video source params.

            if (!matchers || typeof matchers.length !== 'number') {
                return [];
            }

            for (i = 0; i < matchers.length; i += 1) {
                matcher = matchers[i];
                for (j = 0; j < videoSources.length; j += 1) {
                    source = videoSources[j];
                    if (matcher.match(clientCapabilities, source)) {
                        results.push({ pluginType: matcher.pluginType, source: source, attempts: 0 });
                    }
                }
            }

            return results;
        };

    }

    // Source Matchers
    var wms = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.WMS,
        MediaType: Mediasite.Player.MediaTypes.WMV,
        MimeType: Mediasite.Player.MimeTypes.WMV
    });
    var wmv = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.IIS,
        MediaType: Mediasite.Player.MediaTypes.WMV,
        MimeType: Mediasite.Player.MimeTypes.WMV
    });
    var mp4_iis = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.IIS,
        MediaType: Mediasite.Player.MediaTypes.MP4,
        MimeType: Mediasite.Player.MimeTypes.MP4
    });
    var mp4_deliver = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.Deliver,
        MediaType: Mediasite.Player.MediaTypes.MP4,
        MimeType: Mediasite.Player.MimeTypes.MP4
    });
    var mp4_any = new CompositeAnySourceMatcher([mp4_iis, mp4_deliver]);
    var dash = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.Deliver,
        MediaType: Mediasite.Player.MediaTypes.Dash,
        MimeType: Mediasite.Player.MimeTypes.Dash
    });
    var hls_iis = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.IIS,
        MediaType: Mediasite.Player.MediaTypes.MP4,
        MimeType: Mediasite.Player.MimeTypes.M3U
    });
    var hls_deliver = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.Deliver,
        MediaType: Mediasite.Player.MediaTypes.MP4,
        MimeType: Mediasite.Player.MimeTypes.M3U
    });
    var hls_anyUnicast = new CompositeAnySourceMatcher([hls_iis, hls_deliver]);
    var ss_iis = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.IIS,
        MediaType: Mediasite.Player.MediaTypes.SS,
        MimeType: Mediasite.Player.MimeTypes.SS
    });
    var ss_deliver = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.Deliver,
        MediaType: Mediasite.Player.MediaTypes.SS,
        MimeType: Mediasite.Player.MimeTypes.SS
    });
    var ss_any = new CompositeAnySourceMatcher([ss_iis, ss_deliver]);
    var hls_ramp = new SourceMatcher({
        ServerType: Mediasite.Player.ServerTypes.Ramp,
        MediaType: Mediasite.Player.MediaTypes.MP4,
        MimeType: Mediasite.Player.MimeTypes.M3U
    });

    // Playback Strategy Matchers
    var dash_inHtml5 = new StandardMatcher(dash, Mediasite.Player.MediaPlugins.HTML5Dash);
    var mp4_inHtml5 = new StandardMatcher(mp4_any, Mediasite.Player.MediaPlugins.HTML5);
    var wms_inWmp = new StandardMatcher(wms, Mediasite.Player.MediaPlugins.WindowsMedia);
    var wmv_inSilverlight = new StandardMatcher(wmv, Mediasite.Player.MediaPlugins.Silverlight);
    var mp4_inSilverlight = new StandardMatcher(mp4_any, Mediasite.Player.MediaPlugins.Silverlight);
    var wmv_inWmp = new StandardMatcher(wmv, Mediasite.Player.MediaPlugins.WindowsMedia);
    var ss_inSilverlight = new StandardMatcher(ss_any, Mediasite.Player.MediaPlugins.Silverlight);
    var ss_inFlash = new StandardMatcher(ss_any, Mediasite.Player.MediaPlugins.Flash);
    var wms_inSilverlight = new StandardMatcher(wms, Mediasite.Player.MediaPlugins.Silverlight);
    var hls_inHtml5 = new StandardMatcher(hls_anyUnicast, Mediasite.Player.MediaPlugins.Hls);
    var hls_inHLSjs = new StandardMatcher(hls_anyUnicast, Mediasite.Player.MediaPlugins.HLSjs);
    var hls_inRamp = new StandardMatcher(hls_ramp, Mediasite.Player.MediaPlugins.RampHls);
 


    function getOnDemandMatchers() {
        return [
            dash_inHtml5,
            hls_inHLSjs,
            hls_inHtml5,
            mp4_inHtml5,
            wmv_inSilverlight,
            mp4_inSilverlight, // Large MP4 files break in 32bit Silverlight.
            wmv_inWmp,
            ss_inSilverlight,
            ss_inFlash
        ];
    }

    function getOnDemandFavorHlsMatchers() {
        return [
            hls_inHLSjs,
            hls_inHtml5,
            dash_inHtml5,
            mp4_inHtml5,
            wmv_inSilverlight,
            mp4_inSilverlight, // Large MP4 files break in 32bit Silverlight.
            wmv_inWmp,
            ss_inSilverlight,
            ss_inFlash
        ];
    }

    function getLiveMatchers () {
        return [
            hls_inRamp,
            dash_inHtml5,
            hls_inHLSjs,
            hls_inHtml5,
            ss_inSilverlight,
            ss_inFlash
        ];
    }

    function getLiveFavorHlsMatchers() {
        return [
            hls_inRamp,
            hls_inHLSjs,
            hls_inHtml5,
            dash_inHtml5,
            ss_inSilverlight,
            ss_inFlash
        ];
    }
    
    function selectionEngineFactoryMethod(isLive, favorHls) {
        var matchers;

        if (isLive && favorHls) {
            matchers = getLiveFavorHlsMatchers();
        } else if (isLive && !favorHls) {
            matchers = getLiveMatchers();
        } else if (!isLive && favorHls) {
            matchers = getOnDemandFavorHlsMatchers();
        } else { // !isLive && !favorHls
            matchers = getOnDemandMatchers();
        }

        return new MediaPlayerSelectionEngine(matchers);
    }


    Mediasite.MediaPlayer.MediaPlayerSelectionEngine = MediaPlayerSelectionEngine;
    Mediasite.MediaPlayer.MediaPlayerSelectionEngine.getOnDemandMatchers = getOnDemandMatchers;
    Mediasite.MediaPlayer.MediaPlayerSelectionEngine.getLiveMatchers = getLiveMatchers;
    Mediasite.MediaPlayer.MediaPlayerSelectionEngine.getLiveFavorHlsMatchers = getLiveFavorHlsMatchers;
    Mediasite.MediaPlayer.MediaPlayerSelectionEngine.create = selectionEngineFactoryMethod;
})();


Mediasite.MediaPlayer.calculateLiveStartUnsafeWindow = function (values, segmentLengthSeconds) {
    var DEFAULT = 15.0;

    if (values && typeof values[segmentLengthSeconds] === 'number') {
        return values[segmentLengthSeconds];
    } else {
        return DEFAULT;
    }
};


Mediasite.MediaPlayer.CreateModel = function (options) {

    var modelConstructor;
    var mediaPlayerModel = undefined;

    function getModelConstructorByMediaPlayerType(mediaPlayerType) {
        switch (mediaPlayerType) {
            case Mediasite.Player.MediaPlayerType.HTML5:
                return Mediasite.MediaPlayer.ModelHtml5;
                break;
            case Mediasite.Player.MediaPlayerType.HTML5Dash:
                return Mediasite.MediaPlayer.ModelHtml5Dash;
                break;
            case Mediasite.Player.MediaPlayerType.Flash:
                return Mediasite.MediaPlayer.ModelFlash;
                break;
            case Mediasite.Player.MediaPlayerType.WindowsMedia:
            case Mediasite.Player.MediaPlayerType.Port25:
                return Mediasite.MediaPlayer.ModelWindowsMedia;
                break;
            case Mediasite.Player.MediaPlayerType.RampHLS:
                return Mediasite.MediaPlayer.ModelHtml5Ramp;
                break;
            case Mediasite.Player.MediaPlayerType.HLSjs:
                return Mediasite.MediaPlayer.ModelHlsDotJs;
                break;
            case Mediasite.Player.MediaPlayerType.Silverlight:
            default:
                return Mediasite.MediaPlayer.ModelXap;
                break;
        }
    }

    modelConstructor = getModelConstructorByMediaPlayerType(options.selectedMediaPlayerType);
    mediaPlayerModel = new modelConstructor(options);

    return mediaPlayerModel;
};


Mediasite.MediaPlayer.LiveMediaOpenReconnector = function () {
    var allowedReconnectAttempts = 5;
    var reconnectDelay = 2 * 1000;
    var reconnectAttempts = 0;
    var liveStartGraceSeconds = 2 * 60;
    var willAttemptReconnect = false;
    var liveStatus;
    var liveStartTime = new Date(0); // Expected to be set to a reasonable value later.
    var hasSeenPlayingState = false;
    var logger = Mediasite.Logging.LoggerFactory("Media Live Open Reconnector", { separator: "\n" });


    this.setAllowedReconnectAttempts = function (num) {
        allowedReconnectAttempts = num;
    };

    this.setLiveStartGraceSeconds = function (seconds) {
        liveStartGraceSeconds = seconds;
    }

    this.setLiveStatus = function (status) {
        liveStatus = status;
    };

    this.setLiveStartTime = function (time) {
        liveStartTime = time;
    };

    this.setMediaState = function (state) {
        hasSeenPlayingState = hasSeenPlayingState || (state == Mediasite.Player.MediaState.Playing);
    };

    this.HandleLiveMediaOpenFailure = function (reconnectDelegate) {
        var hasAllowedAttemptsLeft;

        if (hasSeenPlayingState || liveStatus != Mediasite.Player.PresentationStatus.Live) {
            // This does not appear to be an error during initial live media open.
            return false;
        }

        if (willAttemptReconnect) {
            // We've already got a reconnect scheduled.
            // Notify caller that this is already being handled.
            return true;
        }

        // Consider the media error as unrecoverable, if we've exceeded the allowed reconnection attempts 
        // and we're not within the grace period from the live start time.
        hasAllowedAttemptsLeft = (reconnectAttempts < allowedReconnectAttempts);

        if (!isWithinLiveStartGrace() && !hasAllowedAttemptsLeft) {
            logger.Debug('The live media reconnection attempts has exceeded the allowed maximum of ' + allowedReconnectAttempts + ' and is not within the grace of ' + liveStartGraceSeconds + ' seconds of the live start time.');

            reconnectAttempts = 0;
            return false; // Notify caller that we're not going to handle this.
        }

        
        // Schedule a reconnection attempt for a short time in the future.
        window.setTimeout(function () {
            logger.Debug('Attempting live media reconnection ' + reconnectAttempts);
            reconnectDelegate();
            willAttemptReconnect = false;
        }, reconnectDelay);


        reconnectAttempts++;
        willAttemptReconnect = true;
        return true; // Notify caller that we're handling everything.
    };

    function isWithinLiveStartGrace() {
        var timeSinceLiveStart = new Date() - liveStartTime;
        return (timeSinceLiveStart < liveStartGraceSeconds * 1000);
    }
}


//*****************************************************************
//* ViewOptions
//*
//* options 
//*    mediaPlayerType: Mediasite.Player.MediaPlayerType.Unknown,
//*    mediaContainer: $('#mediaElementArea'),
//*    backgroundElement: $('.contentBox'),
//*    playButtonText: 'Play',
//*    isMobile: false,
//*    playCoverOnPause: false,
//*    allowFullScreenVideo: false,
//*    enableContextMenu: false,
//*    disableVolume: false,
//*    playbackRates: [0.5, 1, 1.4, 1.6, 2],
//*    silverlightFullScreenPrompt: '',
//*    height: undefined,
//*    width: undefined,
//*    liveSmoothStreamingOffset
//*
//*****************************************************************
Mediasite.MediaPlayer.ViewOptions =
{
    mediaPlayerType: Mediasite.Player.MediaPlayerType.Unknown,
    mediaContainer: $('#mediaElementArea'),
    backgroundElement: $('.contentBox'),
    playButtonText: 'Play',
    isMobile: false,
    playCoverOnPause: false,
    allowFullScreenVideo: false,
    enableContextMenu: false,
    disableVolume: false,
    playbackRates: [0.5, 1, 1.4, 1.6, 2],
    silverlightFullScreenPrompt: '',
    height: '100%',
    width: '100%',
    startPosition: 0,
    autoStart: true,
    pauseAt: -1,
    pluginMimeType: Mediasite.Player.MimeTypes.MP4
};
