/*
Default options
*/
mejs.MediaElementDefaults = {
    // allows testing on HTML5, flash, silverlight
    // auto: attempts to detect what the browser can do
    // auto_plugin: prefer plugins and then attempt native HTML5
    // native: forces HTML5 playback
    // shim: disallows HTML5, will attempt either Flash or Silverlight
    // none: forces fallback view
    mode: 'auto',
    // remove or reorder to change plugin priority and availability
    plugins: ['flash', 'silverlight', 'youtube', 'vimeo'],
    // shows debug errors on screen
    enablePluginDebug: false,
    // use plugin for browsers that have trouble with Basic Authentication on HTTPS sites
    httpsBasicAuthSite: false,
    // overrides the type specified, useful for dynamic instantiation
    type: '',
    // path to Flash and Silverlight plugins
    pluginPath: mejs.Utility.getScriptPath(['mediaelement.js', 'mediaelement.min.js', 'mediaelement-and-player.js', 'mediaelement-and-player.min.js']),
    // name of flash file
    flashName: 'flashmediaelement.swf',
    // streamer for RTMP streaming
    flashStreamer: '',
    // set to 'always' for CDN version
    flashScriptAccess: 'sameDomain',
    // turns on the smoothing filter in Flash
    enablePluginSmoothing: false,
    // enabled pseudo-streaming (seek) on .mp4 files
    enablePseudoStreaming: false,
    // start query parameter sent to server for pseudo-streaming
    pseudoStreamingStartQueryParam: 'start',
    // name of silverlight file
    silverlightName: 'silverlightmediaelement.xap',
    // default if the <video width> is not specified
    defaultVideoWidth: 480,
    // default if the <video height> is not specified
    defaultVideoHeight: 270,
    // overrides <video width>
    pluginWidth: -1,
    // overrides <video height>
    pluginHeight: -1,
    // additional plugin variables in 'key=value' form
    pluginVars: [],
    // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
    // larger number is less accurate, but less strain on plugin->JavaScript bridge
    timerRate: 250,
    // initial volume for player
    startVolume: 0.8,
    success: function () {
    },
    error: function () {
    }
};

/*
Determines if a browser supports the <video> or <audio> element
and returns either the native element or a Flash/Silverlight version that
mimics HTML5 MediaElement
*/
mejs.MediaElement = function (el, o) {
    return mejs.HtmlMediaElementShim.create(el, o);
};

mejs.HtmlMediaElementShim = {

    create: function (el, o) {
        var
            options = {},
            htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
            tagName = htmlMediaElement.tagName.toLowerCase(),
            isMediaTag = (tagName === 'audio' || tagName === 'video'),
            src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
            poster = htmlMediaElement.getAttribute('poster'),
            autoplay = htmlMediaElement.getAttribute('autoplay'),
            preload = htmlMediaElement.getAttribute('preload'),
            controls = htmlMediaElement.getAttribute('controls'),
            playback,
            prop;

        // extend options
        for (prop in mejs.MediaElementDefaults) {
            options[prop] = mejs.MediaElementDefaults[prop];
        }
        for (prop in o) {
            options[prop] = o[prop];
        }


        // clean up attributes
        src = (typeof src == 'undefined' || src === null || src == '') ? null : src;
        poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
        preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
        autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
        controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');

        // test for HTML5 and plugin capabilities
        playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
        playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
        playback.scheme = mejs.Utility.determineScheme(playback.url);

        if (playback.method == 'native') {
            // second fix for android
            if (mejs.MediaFeatures.isBustedAndroid) {
                htmlMediaElement.src = playback.url;
                htmlMediaElement.addEventListener('click', function () {
                    htmlMediaElement.play();
                }, false);
            }

            // add methods to native HTMLMediaElement
            return this.updateNative(playback, options, autoplay, preload);
        } else if (playback.method !== '') {
            // create plugin to mimic HTMLMediaElement

            return this.createPlugin(playback, options, poster, autoplay, preload, controls);
        } else {
            // boo, no HTML5, no Flash, no Silverlight.
            this.createErrorMessage(playback, options, poster);

            return this;
        }
    },

    determinePlayback: function (htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
        var
            mediaFiles = [],
            i,
            j,
            k,
            l,
            n,
            type,
            result = {method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio'), scheme: ''},
            pluginName,
            pluginVersions,
            pluginInfo,
            dummy,
            media;

        // STEP 1: Get URL and type from <video src> or <source src>

        // supplied type overrides <video type> and <source type>
        if (typeof options.type != 'undefined' && options.type !== '') {

            // accept either string or array of types
            if (typeof options.type == 'string') {
                mediaFiles.push({type: options.type, url: src});
            } else {

                for (i = 0; i < options.type.length; i++) {
                    mediaFiles.push({type: options.type[i], url: src});
                }
            }

            // test for src attribute first
        } else if (src !== null) {
            type = this.formatType(src, htmlMediaElement.getAttribute('type'));
            mediaFiles.push({type: type, url: src});

            // then test for <source> elements
        } else {
            // test <source> types to see if they are usable
            for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
                n = htmlMediaElement.childNodes[i];
                if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
                    src = n.getAttribute('src');
                    type = this.formatType(src, n.getAttribute('type'));
                    media = n.getAttribute('media');

                    if (!media || !window.matchMedia || (window.matchMedia && window.matchMedia(media).matches)) {
                        mediaFiles.push({type: type, url: src});
                    }
                }
            }
        }

        // in the case of dynamicly created players
        // check for audio types
        if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
            result.isVideo = false;
        }


        // STEP 2: Test for playback method

        // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
        if (mejs.MediaFeatures.isBustedAndroid) {
            htmlMediaElement.canPlayType = function (type) {
                return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
            };
        }

        // special case for Chromium to specify natively supported video codecs (i.e. WebM and Theora) 
        if (mejs.MediaFeatures.isChromium) {
            htmlMediaElement.canPlayType = function (type) {
                return (type.match(/video\/(webm|ogv|ogg)/gi) !== null) ? 'maybe' : '';
            };
        }

        // test for native playback first
        if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'native') && !(mejs.MediaFeatures.isBustedNativeHTTPS && options.httpsBasicAuthSite === true)) {

            if (!isMediaTag) {

                // create a real HTML5 Media Element 
                dummy = document.createElement(result.isVideo ? 'video' : 'audio');
                htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
                htmlMediaElement.style.display = 'none';

                // use this one from now on
                result.htmlMediaElement = htmlMediaElement = dummy;
            }

            for (i = 0; i < mediaFiles.length; i++) {
                // normal check
                if (mediaFiles[i].type == "video/m3u8" || htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
                    // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
                    || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/, 'mpeg')).replace(/no/, '') !== ''
                    // special case for m4a supported by detecting mp4 support
                    || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/m4a/, 'mp4')).replace(/no/, '') !== '') {
                    result.method = 'native';
                    result.url = mediaFiles[i].url;
                    break;
                }
            }

            if (result.method === 'native') {
                if (result.url !== null) {
                    htmlMediaElement.src = result.url;
                }

                // if `auto_plugin` mode, then cache the native result but try plugins.
                if (options.mode !== 'auto_plugin') {
                    return result;
                }
            }
        }

        // if native playback didn't work, then test plugins
        if (options.mode === 'auto' || options.mode === 'auto_plugin' || options.mode === 'shim') {
            for (i = 0; i < mediaFiles.length; i++) {
                type = mediaFiles[i].type;

                // test all plugins in order of preference [silverlight, flash]
                for (j = 0; j < options.plugins.length; j++) {

                    pluginName = options.plugins[j];

                    // test version of plugin (for future features)
                    pluginVersions = mejs.plugins[pluginName];

                    for (k = 0; k < pluginVersions.length; k++) {
                        pluginInfo = pluginVersions[k];

                        // test if user has the correct plugin version

                        // for youtube/vimeo
                        if (pluginInfo.version == null ||

                            mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {

                            // test for plugin playback types
                            for (l = 0; l < pluginInfo.types.length; l++) {
                                // find plugin that can play the type
                                if (type.toLowerCase() == pluginInfo.types[l].toLowerCase()) {
                                    result.method = pluginName;
                                    result.url = mediaFiles[i].url;
                                    return result;
                                }
                            }
                        }
                    }
                }
            }
        }

        // at this point, being in 'auto_plugin' mode implies that we tried plugins but failed.
        // if we have native support then return that.
        if (options.mode === 'auto_plugin' && result.method === 'native') {
            return result;
        }

        // what if there's nothing to play? just grab the first available
        if (result.method === '' && mediaFiles.length > 0) {
            result.url = mediaFiles[0].url;
        }

        return result;
    },

    formatType: function (url, type) {
        // if no type is supplied, fake it with the extension
        if (url && !type) {
            return this.getTypeFromFile(url);
        } else {
            // only return the mime part of the type in case the attribute contains the codec
            // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
            // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`

            if (type && ~type.indexOf(';')) {
                return type.substr(0, type.indexOf(';'));
            } else {
                return type;
            }
        }
    },

    getTypeFromFile: function (url) {
        url = url.split('?')[0];
        var
            ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase(),
            av = /(mp4|m4v|ogg|ogv|m3u8|webm|webmv|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video/' : 'audio/';
        return this.getTypeFromExtension(ext, av);
    },

    getTypeFromExtension: function (ext, av) {
        av = av || '';

        switch (ext) {
            case 'mp4':
            case 'm4v':
            case 'm4a':
            case 'f4v':
            case 'f4a':
                return av + 'mp4';
            case 'flv':
                return av + 'x-flv';
            case 'webm':
            case 'webma':
            case 'webmv':
                return av + 'webm';
            case 'ogg':
            case 'oga':
            case 'ogv':
                return av + 'ogg';
            case 'm3u8':
                return 'application/x-mpegurl';
            case 'ts':
                return av + 'mp2t';
            default:
                return av + ext;
        }
    },

    createErrorMessage: function (playback, options, poster) {
        var
            htmlMediaElement = playback.htmlMediaElement,
            errorContainer = document.createElement('div'),
            errorContent = options.customError;

        errorContainer.className = 'me-cannotplay';

        try {
            errorContainer.style.width = htmlMediaElement.width + 'px';
            errorContainer.style.height = htmlMediaElement.height + 'px';
        } catch (e) {
        }

        if (!errorContent) {
            errorContent = '<a href="' + playback.url + '">';

            if (poster !== '') {
                errorContent += '<img src="' + poster + '" width="100%" height="100%" alt="" />';
            }

            errorContent += '<span>' + mejs.i18n.t('Download File') + '</span></a>';
        }

        errorContainer.innerHTML = errorContent;

        htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
        htmlMediaElement.style.display = 'none';

        options.error(htmlMediaElement);
    },

    createPlugin: function (playback, options, poster, autoplay, preload, controls) {
        var
            htmlMediaElement = playback.htmlMediaElement,
            width = 1,
            height = 1,
            pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
            pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
            container = document.createElement('div'),
            specialIEContainer,
            node,
            initVars;

        // copy tagName from html media element
        pluginMediaElement.tagName = htmlMediaElement.tagName

        // copy attributes from html media element to plugin media element
        for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
            var attribute = htmlMediaElement.attributes[i];
            if (attribute.specified) {
                pluginMediaElement.setAttribute(attribute.name, attribute.value);
            }
        }

        // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
        node = htmlMediaElement.parentNode;

        while (node !== null && node.tagName != null && node.tagName.toLowerCase() !== 'body' &&
        node.parentNode != null && node.parentNode.tagName != null && node.parentNode.constructor != null && node.parentNode.constructor.name === "ShadowRoot") {
            if (node.parentNode.tagName.toLowerCase() === 'p') {
                node.parentNode.parentNode.insertBefore(node, node.parentNode);
                break;
            }
            node = node.parentNode;
        }

        if (playback.isVideo) {
            width = (options.pluginWidth > 0) ? options.pluginWidth : (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
            height = (options.pluginHeight > 0) ? options.pluginHeight : (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;

            // in case of '%' make sure it's encoded
            width = mejs.Utility.encodeUrl(width);
            height = mejs.Utility.encodeUrl(height);

        } else {
            if (options.enablePluginDebug) {
                width = 320;
                height = 240;
            }
        }

        // register plugin
        pluginMediaElement.success = options.success;

        // add container (must be added to DOM before inserting HTML for IE)
        container.className = 'me-plugin';
        container.id = pluginid + '_container';

        if (playback.isVideo) {
            htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
        } else {
            document.body.insertBefore(container, document.body.childNodes[0]);
        }

        if (playback.method === 'flash' || playback.method === 'silverlight') {

            // flash/silverlight vars
            initVars = [
                'id=' + pluginid,
                'isvideo=' + ((playback.isVideo) ? "true" : "false"),
                'autoplay=' + ((autoplay) ? "true" : "false"),
                'preload=' + preload,
                'width=' + width,
                'startvolume=' + options.startVolume,
                'timerrate=' + options.timerRate,
                'flashstreamer=' + options.flashStreamer,
                'height=' + height,
                'pseudostreamstart=' + options.pseudoStreamingStartQueryParam];

            if (playback.url !== null) {
                if (playback.method == 'flash') {
                    initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
                } else {
                    initVars.push('file=' + playback.url);
                }
            }
            if (options.enablePluginDebug) {
                initVars.push('debug=true');
            }
            if (options.enablePluginSmoothing) {
                initVars.push('smoothing=true');
            }
            if (options.enablePseudoStreaming) {
                initVars.push('pseudostreaming=true');
            }
            if (controls) {
                initVars.push('controls=true'); // shows controls in the plugin if desired
            }
            if (options.pluginVars) {
                initVars = initVars.concat(options.pluginVars);
            }

            // call from plugin
            window[pluginid + '_init'] = function () {
                switch (pluginMediaElement.pluginType) {
                    case 'flash':
                        pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(pluginid);
                        break;
                    case 'silverlight':
                        pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
                        pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
                        break;
                }

                if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
                    pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
                }
            }

            // event call from plugin
            window[pluginid + '_event'] = function (eventName, values) {

                var
                    e,
                    i,
                    bufferedTime;

                // fake event object to mimic real HTML media event.
                e = {
                    type: eventName,
                    target: pluginMediaElement
                };

                // attach all values to element and event object
                for (i in values) {
                    pluginMediaElement[i] = values[i];
                    e[i] = values[i];
                }

                // fake the newer W3C buffered TimeRange (loaded and total have been removed)
                bufferedTime = values.bufferedTime || 0;

                e.target.buffered = e.buffered = {
                    start: function (index) {
                        return 0;
                    },
                    end: function (index) {
                        return bufferedTime;
                    },
                    length: 1
                };

                pluginMediaElement.dispatchEvent(e);
            }


        }

        switch (playback.method) {
            case 'silverlight':
                container.innerHTML =
                    '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
                    '<param name="initParams" value="' + initVars.join(',') + '" />' +
                    '<param name="windowless" value="true" />' +
                    '<param name="background" value="black" />' +
                    '<param name="minRuntimeVersion" value="3.0.0.0" />' +
                    '<param name="autoUpgrade" value="true" />' +
                    '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
                    '</object>';
                break;

            case 'flash':

                if (mejs.MediaFeatures.isIE) {
                    specialIEContainer = document.createElement('div');
                    container.appendChild(specialIEContainer);
                    specialIEContainer.outerHTML =
                        '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
                        'id="' + pluginid + '" width="' + width + '" height="' + height + '" class="mejs-shim">' +
                        '<param name="movie" value="' + options.pluginPath + options.flashName + '?' + (new Date().getTime()) + '" />' +
                        '<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
                        '<param name="quality" value="high" />' +
                        '<param name="bgcolor" value="#000000" />' +
                        '<param name="wmode" value="transparent" />' +
                        '<param name="allowScriptAccess" value="' + options.flashScriptAccess + '" />' +
                        '<param name="allowFullScreen" value="true" />' +
                        '<param name="scale" value="default" />' +
                        '</object>';

                } else {

                    container.innerHTML =
                        '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
                        'play="true" ' +
                        'loop="false" ' +
                        'quality="high" ' +
                        'bgcolor="#000000" ' +
                        'wmode="transparent" ' +
                        'allowScriptAccess="' + options.flashScriptAccess + '" ' +
                        'allowFullScreen="true" ' +
                        'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
                        'src="' + options.pluginPath + options.flashName + '" ' +
                        'flashvars="' + initVars.join('&') + '" ' +
                        'width="' + width + '" ' +
                        'height="' + height + '" ' +
                        'scale="default"' +
                        'class="mejs-shim"></embed>';
                }
                break;

            case 'youtube':


                var videoId;
                // youtu.be url from share button
                if (playback.url.lastIndexOf("youtu.be") != -1) {
                    videoId = playback.url.substr(playback.url.lastIndexOf('/') + 1);
                    if (videoId.indexOf('?') != -1) {
                        videoId = videoId.substr(0, videoId.indexOf('?'));
                    }
                }
                else {
                    // https://www.youtube.com/watch?v=
                    var videoIdMatch = playback.url.match(/[?&]v=([^&#]+)|&|#|$/);
                    if (videoIdMatch) {
                        videoId = videoIdMatch[1];
                    }
                }
                youtubeSettings = {
                    container: container,
                    containerId: container.id,
                    pluginMediaElement: pluginMediaElement,
                    pluginId: pluginid,
                    videoId: videoId,
                    height: height,
                    width: width,
                    scheme: playback.scheme
                };

                // favor iframe version of YouTube
                if (window.postMessage) {
                    mejs.YouTubeApi.enqueueIframe(youtubeSettings);
                } else if (mejs.PluginDetector.hasPluginVersion('flash', [10, 0, 0])) {
                    mejs.YouTubeApi.createFlash(youtubeSettings, options);
                }

                break;

            // DEMO Code. Does NOT work.
            case 'vimeo':
                var player_id = pluginid + "_player";
                pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/') + 1);

                container.innerHTML = '<iframe src="' + playback.scheme + 'player.vimeo.com/video/' + pluginMediaElement.vimeoid + '?api=1&portrait=0&byline=0&title=0&player_id=' + player_id + '" width="' + width + '" height="' + height + '" frameborder="0" class="mejs-shim" id="' + player_id + '" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
                if (typeof($f) == 'function') { // froogaloop available
                    var player = $f(container.childNodes[0]),
                        playerState = -1;

                    player.addEvent('ready', function () {

                        player.playVideo = function () {
                            player.api('play');
                        }
                        player.stopVideo = function () {
                            player.api('unload');
                        }
                        player.pauseVideo = function () {
                            player.api('pause');
                        }
                        player.seekTo = function (seconds) {
                            player.api('seekTo', seconds);
                        }
                        player.setVolume = function (volume) {
                            player.api('setVolume', volume);
                        }
                        player.setMuted = function (muted) {
                            if (muted) {
                                player.lastVolume = player.api('getVolume');
                                player.api('setVolume', 0);
                            } else {
                                player.api('setVolume', player.lastVolume);
                                delete player.lastVolume;
                            }
                        }
                        // parity with YT player
                        player.getPlayerState = function () {
                            return playerState;
                        }

                        function createEvent(player, pluginMediaElement, eventName, e) {
                            var event = {
                                type: eventName,
                                target: pluginMediaElement
                            };
                            if (eventName == 'timeupdate') {
                                pluginMediaElement.currentTime = event.currentTime = e.seconds;
                                pluginMediaElement.duration = event.duration = e.duration;
                            }
                            pluginMediaElement.dispatchEvent(event);
                        }

                        player.addEvent('play', function () {
                            playerState = 1;
                            createEvent(player, pluginMediaElement, 'play');
                            createEvent(player, pluginMediaElement, 'playing');
                        });

                        player.addEvent('pause', function () {
                            playerState = 2;
                            createEvent(player, pluginMediaElement, 'pause');
                        });

                        player.addEvent('finish', function () {
                            playerState = 0;
                            createEvent(player, pluginMediaElement, 'ended');
                        });

                        player.addEvent('playProgress', function (e) {
                            createEvent(player, pluginMediaElement, 'timeupdate', e);
                        });

                        player.addEvent('seek', function (e) {
                            playerState = 3;
                            createEvent(player, pluginMediaElement, 'seeked', e);
                        });

                        player.addEvent('loadProgress', function (e) {
                            playerState = 3;
                            createEvent(player, pluginMediaElement, 'progress', e);
                        });

                        pluginMediaElement.pluginElement = container;
                        pluginMediaElement.pluginApi = player;

                        pluginMediaElement.success(pluginMediaElement, pluginMediaElement.pluginElement);
                    });
                }
                else {
                    console.warn("You need to include froogaloop for vimeo to work");
                }
                break;
        }
        // hide original element
        htmlMediaElement.style.display = 'none';
        // prevent browser from autoplaying when using a plugin
        htmlMediaElement.removeAttribute('autoplay');

        return pluginMediaElement;
    },

    updateNative: function (playback, options, autoplay, preload) {

        var htmlMediaElement = playback.htmlMediaElement,
            m;


        // add methods to video object to bring it into parity with Flash Object
        for (m in mejs.HtmlMediaElement) {
            htmlMediaElement[m] = mejs.HtmlMediaElement[m];
        }

        /*
        Chrome now supports preload="none"
        if (mejs.MediaFeatures.isChrome) {
        
            // special case to enforce preload attribute (Chrome doesn't respect this)
            if (preload === 'none' && !autoplay) {
            
                // forces the browser to stop loading (note: fails in IE9)
                htmlMediaElement.src = '';
                htmlMediaElement.load();
                htmlMediaElement.canceledPreload = true;

                htmlMediaElement.addEventListener('play',function() {
                    if (htmlMediaElement.canceledPreload) {
                        htmlMediaElement.src = playback.url;
                        htmlMediaElement.load();
                        htmlMediaElement.play();
                        htmlMediaElement.canceledPreload = false;
                    }
                }, false);
            // for some reason Chrome forgets how to autoplay sometimes.
            } else if (autoplay) {
                htmlMediaElement.load();
                htmlMediaElement.play();
            }
        }
        */

        // fire success code
        options.success(htmlMediaElement, htmlMediaElement);

        return htmlMediaElement;
    }
};

/*
 - test on IE (object vs. embed)
 - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
 - fullscreen?
*/

// YouTube Flash and Iframe API
mejs.YouTubeApi = {
    isIframeStarted: false,
    isIframeLoaded: false,
    loadIframeApi: function (yt) {
        if (!this.isIframeStarted) {
            var tag = document.createElement('script');
            tag.src = yt.scheme + "www.youtube.com/player_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
            this.isIframeStarted = true;
        }
    },
    iframeQueue: [],
    enqueueIframe: function (yt) {

        if (this.isLoaded) {
            this.createIframe(yt);
        } else {
            this.loadIframeApi(yt);
            this.iframeQueue.push(yt);
        }
    },
    createIframe: function (settings) {

        var
            pluginMediaElement = settings.pluginMediaElement,
            player = new YT.Player(settings.containerId, {
                height: settings.height,
                width: settings.width,
                videoId: settings.videoId,
                playerVars: {controls: 0, wmode: 'transparent'},
                events: {
                    'onReady': function () {

                        // wrapper to match
                        player.setVideoSize = function (width, height) {
                            player.setSize(width, height);
                        }

                        // hook up iframe object to MEjs
                        settings.pluginMediaElement.pluginApi = player;
                        settings.pluginMediaElement.pluginElement = document.getElementById(settings.containerId);

                        // init mejs
                        pluginMediaElement.success(pluginMediaElement, pluginMediaElement.pluginElement);

                        // create timer
                        setInterval(function () {
                            mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
                        }, 250);
                    },
                    'onStateChange': function (e) {

                        mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);

                    }
                }
            });
    },

    createEvent: function (player, pluginMediaElement, eventName) {
        var event = {
            type: eventName,
            target: pluginMediaElement
        };

        if (player && player.getDuration) {

            // time 
            pluginMediaElement.currentTime = event.currentTime = player.getCurrentTime();
            pluginMediaElement.duration = event.duration = player.getDuration();

            // state
            event.paused = pluginMediaElement.paused;
            event.ended = pluginMediaElement.ended;

            // sound
            event.muted = player.isMuted();
            event.volume = player.getVolume() / 100;

            // progress
            event.bytesTotal = player.getVideoBytesTotal();
            event.bufferedBytes = player.getVideoBytesLoaded();

            // fake the W3C buffered TimeRange
            var bufferedTime = event.bufferedBytes / event.bytesTotal * event.duration;

            event.target.buffered = event.buffered = {
                start: function (index) {
                    return 0;
                },
                end: function (index) {
                    return bufferedTime;
                },
                length: 1
            };

        }

        // send event up the chain
        pluginMediaElement.dispatchEvent(event);
    },

    iFrameReady: function () {

        this.isLoaded = true;
        this.isIframeLoaded = true;

        while (this.iframeQueue.length > 0) {
            var settings = this.iframeQueue.pop();
            this.createIframe(settings);
        }
    },

    // FLASH!
    flashPlayers: {},
    createFlash: function (settings) {

        this.flashPlayers[settings.pluginId] = settings;

        /*
        settings.container.innerHTML =
            '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + settings.scheme + 'www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId  + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
                'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
                '<param name="allowScriptAccess" value="sameDomain">' +
                '<param name="wmode" value="transparent">' +
            '</object>';
        */

        var specialIEContainer,
            youtubeUrl = settings.scheme + 'www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0';

        if (mejs.MediaFeatures.isIE) {

            specialIEContainer = document.createElement('div');
            settings.container.appendChild(specialIEContainer);
            specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="' + settings.scheme + 'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
                'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '" class="mejs-shim">' +
                '<param name="movie" value="' + youtubeUrl + '" />' +
                '<param name="wmode" value="transparent" />' +
                '<param name="allowScriptAccess" value="' + options.flashScriptAccess + '" />' +
                '<param name="allowFullScreen" value="true" />' +
                '</object>';
        } else {
            settings.container.innerHTML =
                '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
                'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; " class="mejs-shim">' +
                '<param name="allowScriptAccess" value="' + options.flashScriptAccess + '">' +
                '<param name="wmode" value="transparent">' +
                '</object>';
        }

    },

    flashReady: function (id) {
        var
            settings = this.flashPlayers[id],
            player = document.getElementById(id),
            pluginMediaElement = settings.pluginMediaElement;

        // hook up and return to MediaELementPlayer.success	
        pluginMediaElement.pluginApi =
            pluginMediaElement.pluginElement = player;

        settings.success(pluginMediaElement, pluginMediaElement.pluginElement);

        // load the youtube video
        player.cueVideoById(settings.videoId);

        var callbackName = settings.containerId + '_callback';

        window[callbackName] = function (e) {
            mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
        }

        player.addEventListener('onStateChange', callbackName);

        setInterval(function () {
            mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
        }, 250);

        mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'canplay');
    },

    handleStateChange: function (youTubeState, player, pluginMediaElement) {
        switch (youTubeState) {
            case -1: // not started
                pluginMediaElement.paused = true;
                pluginMediaElement.ended = true;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
                //createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
                break;
            case 0:
                pluginMediaElement.paused = false;
                pluginMediaElement.ended = true;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
                break;
            case 1:
                pluginMediaElement.paused = false;
                pluginMediaElement.ended = false;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
                break;
            case 2:
                pluginMediaElement.paused = true;
                pluginMediaElement.ended = false;
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
                break;
            case 3: // buffering
                mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
                break;
            case 5:
                // cued?
                break;

        }

    }
}
// IFRAME
window.onYouTubePlayerAPIReady = function () {
    mejs.YouTubeApi.iFrameReady();
};
// FLASH
window.onYouTubePlayerReady = function (id) {
    mejs.YouTubeApi.flashReady(id);
};

window.mejs = mejs;
window.MediaElement = mejs.MediaElement;
