(function ($) {

    $.extend(mejs.MepDefaults, {
        muteText: mejs.i18n.t('Mute Toggle'),
        allyVolumeControlText: mejs.i18n.t('Use Up/Down Arrow keys to increase or decrease volume.'),
        hideVolumeOnTouchDevices: true,

        audioVolume: 'horizontal',
        videoVolume: 'vertical'
    });

    $.extend(MediaElementPlayer.prototype, {
        buildvolume: function (player, controls, layers, media) {

            // Android and iOS don't support volume controls
            if ((mejs.MediaFeatures.isAndroid || mejs.MediaFeatures.isiOS) && this.options.hideVolumeOnTouchDevices)
                return;

            var t = this,
                mode = (t.isVideo) ? t.options.videoVolume : t.options.audioVolume,
                mute = (mode == 'horizontal') ?

                    // horizontal version
                    $('<div class="mejs-button mejs-volume-button mejs-mute">' +
                        '<button type="button" aria-controls="' + t.id +
                        '" title="' + t.options.muteText +
                        '" aria-label="' + t.options.muteText +
                        '"></button>' +
                        '</div>' +
                        '<a href="javascript:void(0);" class="mejs-horizontal-volume-slider">' + // outer background
                        '<span class="mejs-offscreen">' + t.options.allyVolumeControlText + '</span>' +
                        '<div class="mejs-horizontal-volume-total"></div>' + // line background
                        '<div class="mejs-horizontal-volume-current"></div>' + // current volume
                        '<div class="mejs-horizontal-volume-handle"></div>' + // handle
                        '</a>'
                    )
                        .appendTo(controls) :

                    // vertical version
                    $('<div class="mejs-button mejs-volume-button mejs-mute">' +
                        '<button type="button" aria-controls="' + t.id +
                        '" title="' + t.options.muteText +
                        '" aria-label="' + t.options.muteText +
                        '"></button>' +
                        '<a href="javascript:void(0);" class="mejs-volume-slider">' + // outer background
                        '<span class="mejs-offscreen">' + t.options.allyVolumeControlText + '</span>' +
                        '<div class="mejs-volume-total"></div>' + // line background
                        '<div class="mejs-volume-current"></div>' + // current volume
                        '<div class="mejs-volume-handle"></div>' + // handle
                        '</a>' +
                        '</div>')
                        .appendTo(controls),
                volumeSlider = t.container.find('.mejs-volume-slider, .mejs-horizontal-volume-slider'),
                volumeTotal = t.container.find('.mejs-volume-total, .mejs-horizontal-volume-total'),
                volumeCurrent = t.container.find('.mejs-volume-current, .mejs-horizontal-volume-current'),
                volumeHandle = t.container.find('.mejs-volume-handle, .mejs-horizontal-volume-handle'),

                positionVolumeHandle = function (volume, secondTry) {

                    if (!volumeSlider.is(':visible') && typeof secondTry == 'undefined') {
                        volumeSlider.show();
                        positionVolumeHandle(volume, true);
                        volumeSlider.hide();
                        return;
                    }

                    // correct to 0-1
                    volume = Math.max(0, volume);
                    volume = Math.min(volume, 1);

                    // ajust mute button style
                    if (volume === 0) {
                        mute.removeClass('mejs-mute').addClass('mejs-unmute');
                        mute.children('button').attr('title', mejs.i18n.t('Unmute')).attr('aria-label', mejs.i18n.t('Unmute'));
                    } else {
                        mute.removeClass('mejs-unmute').addClass('mejs-mute');
                        mute.children('button').attr('title', mejs.i18n.t('Mute')).attr('aria-label', mejs.i18n.t('Mute'));
                    }

                    // top/left of full size volume slider background
                    var totalPosition = volumeTotal.position();
                    // position slider 
                    if (mode == 'vertical') {
                        var
                            // height of the full size volume slider background
                            totalHeight = volumeTotal.height(),

                            // the new top position based on the current volume
                            // 70% volume on 100px height == top:30px
                            newTop = totalHeight - (totalHeight * volume);

                        // handle
                        volumeHandle.css('top', Math.round(totalPosition.top + newTop - (volumeHandle.height() / 2)));

                        // show the current visibility
                        volumeCurrent.height(totalHeight - newTop);
                        volumeCurrent.css('top', totalPosition.top + newTop);
                    } else {
                        var
                            // height of the full size volume slider background
                            totalWidth = volumeTotal.width(),

                            // the new left position based on the current volume
                            newLeft = totalWidth * volume;

                        // handle
                        volumeHandle.css('left', Math.round(totalPosition.left + newLeft - (volumeHandle.width() / 2)));

                        // rezize the current part of the volume bar
                        volumeCurrent.width(Math.round(newLeft));
                    }
                },
                handleVolumeMove = function (e) {

                    var volume = null,
                        totalOffset = volumeTotal.offset();

                    // calculate the new volume based on the moust position
                    if (mode === 'vertical') {

                        var
                            railHeight = volumeTotal.height(),
                            newY = e.pageY - totalOffset.top;

                        volume = (railHeight - newY) / railHeight;

                        // the controls just hide themselves (usually when mouse moves too far up)
                        if (totalOffset.top === 0 || totalOffset.left === 0) {
                            return;
                        }

                    } else {
                        var
                            railWidth = volumeTotal.width(),
                            newX = e.pageX - totalOffset.left;

                        volume = newX / railWidth;
                    }

                    // ensure the volume isn't outside 0-1
                    volume = Math.max(0, volume);
                    volume = Math.min(volume, 1);

                    // position the slider and handle
                    positionVolumeHandle(volume);

                    // set the media object (this will trigger the volumechanged event)
                    if (volume === 0) {
                        media.setMuted(true);
                    } else {
                        media.setMuted(false);
                    }
                    media.setVolume(volume);
                },
                mouseIsDown = false,
                mouseIsOver = false;

            // SLIDER

            mute
                .hover(function () {
                    volumeSlider.show();
                    mouseIsOver = true;
                }, function () {
                    mouseIsOver = false;

                    if (!mouseIsDown && mode == 'vertical') {
                        volumeSlider.hide();
                    }
                });

            var updateVolumeSlider = function (e) {

                var volume = Math.floor(media.volume * 100);

                volumeSlider.attr({
                    'aria-label': mejs.i18n.t('Volume Slider'),
                    'aria-valuemin': 0,
                    'aria-valuemax': 100,
                    'aria-valuenow': volume,
                    'aria-valuetext': volume + '%',
                    'role': 'slider',
                    'tabindex': 0
                });

            };

            volumeSlider
                .bind('mouseover', function () {
                    mouseIsOver = true;
                })
                .bind('mousedown', function (e) {
                    handleVolumeMove(e);
                    t.globalBind('mousemove.vol', function (e) {
                        handleVolumeMove(e);
                    });
                    t.globalBind('mouseup.vol', function () {
                        mouseIsDown = false;
                        t.globalUnbind('.vol');

                        if (!mouseIsOver && mode == 'vertical') {
                            volumeSlider.hide();
                        }
                    });
                    mouseIsDown = true;

                    return false;
                })
                .bind('keydown', function (e) {
                    var keyCode = e.keyCode;
                    var volume = media.volume;
                    switch (keyCode) {
                        case 38: // Up
                            volume = Math.min(volume + 0.1, 1);
                            break;
                        case 40: // Down
                            volume = Math.max(0, volume - 0.1);
                            break;
                        default:
                            return true;
                    }

                    mouseIsDown = false;
                    positionVolumeHandle(volume);
                    media.setVolume(volume);
                    return false;
                });

            // MUTE button
            mute.find('button').click(function () {
                media.setMuted(!media.muted);
            });

            //Keyboard input
            mute.find('button').bind('focus', function () {
                volumeSlider.show();
            });

            // listen for volume change events from other sources
            media.addEventListener('volumechange', function (e) {
                if (!mouseIsDown) {
                    if (media.muted) {
                        positionVolumeHandle(0);
                        mute.removeClass('mejs-mute').addClass('mejs-unmute');
                    } else {
                        positionVolumeHandle(media.volume);
                        mute.removeClass('mejs-unmute').addClass('mejs-mute');
                    }
                }
                updateVolumeSlider(e);
            }, false);

            // mutes the media and sets the volume icon muted if the initial volume is set to 0
            if (player.options.startVolume === 0) {
                media.setMuted(true);
            }

            // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
            if (media.pluginType === 'native') {
                media.setVolume(player.options.startVolume);
            }

            t.container.on('controlsresize', function () {
                positionVolumeHandle(media.volume);
            });
        }
    });

})(mejs.$);
