(function ($, window, undefined) {
    var plugin = {};

    plugin.options = {
        document: document.body,
        canexpand: false,
        classes: {
            callout: 'fidelity-callout',
            panel: 'fidelity-panel',
            infoContainer: 'fidelity-info',
            streamSummary: 'fidelity-stream-info',
            bitrate: 'fidelity-bitrate',
            resolution: 'fidelity-resolution',
            currentTrack: 'fidelity-current-track'
        },
        streams: [] // collection of { streamType: ..., container: jQuery selector }
    };

    plugin._create = function () {
        this._super();
        this._setOption('show', this._updateCallout.bind(this));
        this._setOption('hide', this._onHide.bind(this));
        this._applyBaseStyle();
    };

    plugin._sibInstance = {};

    plugin._populateElements = function () {
        var self = this;
        this._super();

        var $buttonElement = self.element.find('button');
        $buttonElement.attr("title", Mediasite.Player.Localization.MediaPlayer.MediaFidelityToolTip);
        
    };

    plugin._applyBaseStyle = function () {
        this._super();

        this.element.find(this.selectors.popout).addClass(this.options.classes.callout);
    };

    plugin.update = function (fidelityInfo) {
        this.streamsFidelityInfo = fidelityInfo;
        this._updateCallout();
        this._updatePanel();
    };

    plugin.setFocusedStream = function (streamType) {
        this._focusedStream = streamType;
        this._updateCallout();
    };
    plugin.clearFocusedStream = function () {
        this._focusedStream = void 0;
        this._updateCallout();
    }

    plugin._updateCallout = function () {
        var self = this;
        var streamsFidelityInfo = this._getOrderedInfo();

        var info = $.map(streamsFidelityInfo, this._formatCurrentTrackInfo.bind(this));
        $.each(info, function (i, element) {
            if (self._focusedStream == void 0 || self._focusedStream === element.data("streamType")) {
                element.on('click', self._onInteract.bind(self));
            } else {
                element.attr("disabled", true);
            }
        });
        this._populateContents(info);
    };

    plugin._formatStreamTrackInfo = function (fidelityInfo) {
        var container = $("<div />").addClass(this.options.classes.streamSummary);
        for (var i = 0, length = fidelityInfo.tracks.length; i < length; i++) {
            var track = fidelityInfo.tracks[i];
            var trackElement = this._formatFidelityInfo(track);
            if (track == fidelityInfo.currentTrack) {
                trackElement.addClass(this.options.classes.currentTrack);
            }

            trackElement.appendTo(container);
        }

        return container;
    };

    plugin._formatCurrentTrackInfo = function (fidelityInfo) {
        var element = this._formatFidelityInfo(fidelityInfo.currentTrack);
        element.data("streamType", fidelityInfo.streamType);
        return element;
    };

    plugin._formatFidelityInfo = function (trackInfo) {
        var bitrate = this._formatBitRate(trackInfo.bitrate);
        var resolution = this._formatResolution(trackInfo.width, trackInfo.height);

        var element = $('<p />').addClass(this.options.classes.infoContainer);
        $("<span />").addClass(this.options.classes.resolution).text(resolution).appendTo(element);
        $("<span />").addClass(this.options.classes.bitrate).text(bitrate).appendTo(element);

        return element;

    };

    plugin._formatFidelityInfoPlaintext = function (trackInfo) {
        var bitrate = this._formatBitRate(trackInfo.bitrate);
        var resolution = this._formatResolution(trackInfo.width, trackInfo.height);

        var formatted = resolution + ' (' + bitrate + ')';
        return formatted;
    };

    plugin._formatBitRate = function (bitrate) {
        var bytesInK = 1000;
        var bytesInM = bytesInK * 1000;

        if (bitrate >= bytesInM) {
            var displayRate = Math.floor(bitrate / bytesInM);

            return Mediasite.Player.Localization.MediaPlayer.BitrateMbpsFormat.replaceholders(displayRate);
        }
        else {
            var displayRate = bitrate / bytesInK;
            displayRate = Math.floor(displayRate * 1000) / 1000;
            return Mediasite.Player.Localization.MediaPlayer.BitrateKbpsFormat.replaceholders(displayRate);
        }
    };

    plugin._formatResolution = function (width, height) {
        // TODO: friendlier resolution names

        var displayResolution = Mediasite.Player.Localization.MediaPlayer.ResolutionFormat.replaceholders(width, height);
        return displayResolution;

    };

    plugin._updatePanel = function (streamType) {
        if (typeof streamType == "undefined") {
            streamType = this._panelCurrentStreamType;
        } else {
            this._panelCurrentStreamType = streamType;
        }

        if (typeof streamType == "undefined") return;

        var fidelityInfo = this.streamsFidelityInfo[streamType];
        var panel = this._formatStreamTrackInfo(fidelityInfo);
        if (this._panel) {
            this._panel.replaceWith(panel);
        }
        this._panel = panel;
    };

    plugin._showPanel = function () {
        if (!this._panel) return;

        if (!this._panel.parent().length) {
            this._panel.appendTo(this.options.document);
            this._panel.fadeIn();
        }
        this.updateLayout();
    };

    plugin.updateLayout = function () {
        var streamElement = this._getStreamElement(this._panelCurrentStreamType);
        if (this._panel && streamElement && streamElement.length) {

            this._panel.position({
                my: "center center",
                at: "center center",
                of: streamElement
            });
        }
    };

    plugin._onHide = function(e) {
        this._hidePanel(e.data && e.data.fast);
    };

    plugin.hideStreamDetails = function() {
        this._hidePanel(true);
    };


    plugin._hidePanel = function (fast) {
        var self = this;
        if (!this._panel) return;

        if (fast) {
            this._panel.stop(true, true).hide()
            remove();
        } else {
            this._panel.stop(true, true).fadeOut(200, remove);
        }

        function remove() {
            self._panel.remove();
            self._panel = null;
        }
    };

    plugin._getOrderedInfo = function () {
        var infoMapping = $.extend(true, {}, this.streamsFidelityInfo);

        // Add stream.element to that stream's fidelity info
        for (var i = 0, length = this.options.streams.length; i < length; i++) {
            var stream = this.options.streams[i];
            var streamType = stream.streamDefinition.StreamType
            var info = infoMapping[streamType];
            if (info) {
                info.element = stream.element;
            }
        }

        var orderedInfo = [];
        // Order fidelity info per stream ordering
        for (var i = 0, length = this.options.streams.length; i < length; i++) {
            var stream = this.options.streams[i];
            var streamType = stream.streamDefinition.StreamType;
            var info = infoMapping[streamType];
            if (info) {
                orderedInfo.push(info);
                delete infoMapping[streamType];
            }
        }

        // Append fidelity infos which were not included in stream ordering (because insufficient data)
        for (var streamType in infoMapping) {
            if (!infoMapping.hasOwnProperty(streamType)) continue;
            var info = infoMapping[streamType];
            orderedInfo.push(info);
        }

        return orderedInfo;
    };

    plugin._getStreamElement = function (streamType) {
        if (typeof streamType == "undefined") return;
        for (var i = 0, length = this.options.streams.length; i < length; i++) {
            var stream = this.options.streams[i];
            if (stream.streamDefinition.StreamType == streamType) {
                return stream.outerElement;
            }
        }
    };


    plugin._onInteract = function (e) {
        var streamType = $(e.delegateTarget).data('streamType');
        this._updatePanel(streamType);
        this._showPanel();
    };




    $.widget("ui.smartplayerfidelity", $.ui.responsiveContainer, plugin);
})(jQuery, window);