define(['datetime', 'userdataButtons', 'itemHelper', 'events', 'browser', 'paper-icon-button-light'], function (datetime, userdataButtons, itemHelper, events, browser) {

    var currentPlayer;

    var currentTimeElement;
    var nowPlayingImageElement;
    var nowPlayingTextElement;
    var nowPlayingUserData;
    var unmuteButton;
    var muteButton;
    var volumeSlider;
    var volumeSliderContainer;
    var unpauseButtons;
    var pauseButtons;
    var positionSlider;
    var toggleRepeatButton;
    var toggleRepeatButtonIcon;

    var lastPlayerState;

    function getNowPlayingBarHtml() {

        var html = '';

        html += '<div class="nowPlayingBar hide">';

        html += '<div class="nowPlayingBarTop">';
        html += '<div class="nowPlayingBarPositionContainer sliderContainer">';
        html += '<input type="range" is="emby-slider" pin step=".1" min="0" max="100" value="0" class="nowPlayingBarPositionSlider"/>';
        html += '</div>';

        html += '<div class="nowPlayingBarInfoContainer">';
        html += '<div class="nowPlayingImage"></div>';
        html += '<div class="nowPlayingBarText"></div>';
        html += '</div>';

        // The onclicks are needed due to the return false above
        html += '<div class="nowPlayingBarCenter">';

        html += '<button is="paper-icon-button-light" class="previousTrackButton mediaButton autoSize"><i class="md-icon">skip_previous</i></button>';

        html += '<button is="paper-icon-button-light" class="unpauseButton mediaButton autoSize"><i class="md-icon">play_arrow</i></button>';
        html += '<button is="paper-icon-button-light" class="pauseButton mediaButton autoSize"><i class="md-icon">pause</i></button>';

        html += '<button is="paper-icon-button-light" class="stopButton mediaButton autoSize"><i class="md-icon">stop</i></button>';
        html += '<button is="paper-icon-button-light" class="nextTrackButton mediaButton autoSize"><i class="md-icon">skip_next</i></button>';

        html += '<div class="nowPlayingBarCurrentTime"></div>';
        html += '</div>';

        html += '<div class="nowPlayingBarRight">';

        html += '<button is="paper-icon-button-light" class="muteButton mediaButton autoSize"><i class="md-icon">volume_up</i></button>';
        html += '<button is="paper-icon-button-light" class="unmuteButton mediaButton autoSize"><i class="md-icon">volume_off</i></button>';

        html += '<div class="sliderContainer nowPlayingBarVolumeSliderContainer hide" style="width:100px;vertical-align:middle;display:inline-flex;">';
        html += '<input type="range" is="emby-slider" pin step="1" min="0" max="100" value="0" class="nowPlayingBarVolumeSlider"/>';
        html += '</div>';

        html += '<button is="paper-icon-button-light" class="toggleRepeatButton mediaButton autoSize"><i class="md-icon">repeat</i></button>';

        html += '<div class="nowPlayingBarUserDataButtons">';
        html += '</div>';

        html += '<button is="paper-icon-button-light" class="unpauseButton mediaButton autoSize"><i class="md-icon">play_arrow</i></button>';
        html += '<button is="paper-icon-button-light" class="pauseButton mediaButton autoSize"><i class="md-icon">pause</i></button>';
        html += '<button is="paper-icon-button-light" class="remoteControlButton mediaButton autoSize"><i class="md-icon">tablet_android</i></button>';
        html += '<button is="paper-icon-button-light" class="playlistButton mediaButton autoSize"><i class="md-icon">queue_music</i></button>';

        html += '</div>';
        html += '</div>';

        html += '</div>';

        return html;
    }

    function slideDown(elem) {

        if (elem.classList.contains('hide')) {
            return;
        }

        var onfinish = function () {
            elem.classList.add('hide');
        };

        if (!browser.animate || browser.slow) {
            onfinish();
            return;
        }

        requestAnimationFrame(function () {
            var keyframes = [
              { transform: 'none', offset: 0 },
              { transform: 'translateY(100%)', offset: 1 }];
            var timing = { duration: 200, iterations: 1, fill: 'both', easing: 'ease-out' };
            elem.animate(keyframes, timing).onfinish = onfinish;
        });
    }

    function slideUp(elem) {

        if (!elem.classList.contains('hide')) {
            return;
        }

        elem.classList.remove('hide');

        if (!browser.animate || browser.slow) {
            return;
        }

        requestAnimationFrame(function () {

            var keyframes = [
              { transform: 'translateY(100%)', offset: 0 },
              { transform: 'none', offset: 1 }];
            var timing = { duration: 200, iterations: 1, fill: 'both', easing: 'ease-out' };
            elem.animate(keyframes, timing);
        });
    }

    function slideUpToFullScreen(elem) {

        if (!elem.classList.contains('hide')) {
            return;
        }

        elem.classList.remove('hide');

        if (!browser.animate || browser.slow) {
            return;
        }

        requestAnimationFrame(function () {

            var keyframes = [
              { transform: 'none', offset: 0 },
              { transform: 'translateY(-100%)', offset: 1 }];
            var timing = { duration: 200, iterations: 1, fill: 'both', easing: 'ease-out' };
            elem.animate(keyframes, timing);
        });
    }

    function onPauseClick() {
        if (currentPlayer) {
            currentPlayer.pause();
        }
    }

    function onUnpauseClick() {
        if (currentPlayer) {
            currentPlayer.unpause();
        }
    }

    function bindEvents(elem) {

        currentTimeElement = elem.querySelector('.nowPlayingBarCurrentTime');
        nowPlayingImageElement = elem.querySelector('.nowPlayingImage');
        nowPlayingTextElement = elem.querySelector('.nowPlayingBarText');
        nowPlayingUserData = elem.querySelector('.nowPlayingBarUserDataButtons');

        unmuteButton = elem.querySelector('.unmuteButton');
        unmuteButton.addEventListener('click', function () {

            if (currentPlayer) {
                currentPlayer.unMute();
            }

        });

        muteButton = elem.querySelector('.muteButton');
        muteButton.addEventListener('click', function () {

            if (currentPlayer) {
                currentPlayer.mute();
            }

        });

        elem.querySelector('.stopButton').addEventListener('click', function () {

            if (currentPlayer) {
                currentPlayer.stop();
            }
        });

        var i, length;
        pauseButtons = elem.querySelectorAll('.pauseButton');
        for (i = 0, length = pauseButtons.length; i < length; i++) {
            pauseButtons[i].addEventListener('click', onPauseClick);
        }
        unpauseButtons = elem.querySelectorAll('.unpauseButton');
        for (i = 0, length = unpauseButtons.length; i < length; i++) {
            unpauseButtons[i].addEventListener('click', onUnpauseClick);
        }

        elem.querySelector('.nextTrackButton').addEventListener('click', function () {

            if (currentPlayer) {
                currentPlayer.nextTrack();
            }
        });

        elem.querySelector('.previousTrackButton').addEventListener('click', function () {

            if (currentPlayer) {
                currentPlayer.previousTrack();
            }
        });

        elem.querySelector('.remoteControlButton').addEventListener('click', function () {

            showRemoteControl();
        });

        elem.querySelector('.playlistButton').addEventListener('click', function () {

            showRemoteControl(2);
        });

        toggleRepeatButton = elem.querySelector('.toggleRepeatButton');
        toggleRepeatButton.addEventListener('click', function () {

            if (currentPlayer) {
                var state = lastPlayerState || {};

                switch ((state.PlayState || {}).RepeatMode) {
                    case 'RepeatAll':
                        currentPlayer.setRepeatMode('RepeatOne');
                        break;
                    case 'RepeatOne':
                        currentPlayer.setRepeatMode('RepeatNone');
                        break;
                    default:
                        currentPlayer.setRepeatMode('RepeatAll');
                        break;
                }
            }
        });

        toggleRepeatButtonIcon = toggleRepeatButton.querySelector('i');

        volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider');
        volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer');

        if (AppInfo.hasPhysicalVolumeButtons) {
            volumeSliderContainer.classList.add('hide');
        } else {
            volumeSliderContainer.classList.remove('hide');
        }

        volumeSlider.addEventListener('change', function () {

            if (currentPlayer) {
                currentPlayer.setVolume(this.value);
            }

        });

        positionSlider = elem.querySelector('.nowPlayingBarPositionSlider');
        positionSlider.addEventListener('change', function () {

            if (currentPlayer && lastPlayerState) {

                var newPercent = parseFloat(this.value);
                var newPositionTicks = (newPercent / 100) * lastPlayerState.NowPlayingItem.RunTimeTicks;

                currentPlayer.seek(Math.floor(newPositionTicks));
            }

        });

        positionSlider.getBubbleText = function (value) {

            var state = lastPlayerState;

            if (!state || !state.NowPlayingItem || !state.NowPlayingItem.RunTimeTicks) {
                return '--:--';
            }

            var ticks = state.NowPlayingItem.RunTimeTicks;
            ticks /= 100;
            ticks *= value;

            return datetime.getDisplayRunningTime(ticks);
        };
    }

    function showRemoteControl(tabIndex) {

        if (tabIndex) {
            Dashboard.navigate('nowplaying.html?tab=' + tabIndex);
        } else {
            Dashboard.navigate('nowplaying.html');
        }
    }

    var nowPlayingBarElement;
    function getNowPlayingBar() {

        if (nowPlayingBarElement) {
            return Promise.resolve(nowPlayingBarElement);
        }

        return new Promise(function (resolve, reject) {

            require(['appfooter-shared', 'itemShortcuts', 'css!css/nowplayingbar.css', 'emby-slider'], function (appfooter, itemShortcuts) {

                var parentContainer = appfooter.element;
                nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar');

                if (nowPlayingBarElement) {
                    resolve(nowPlayingBarElement);
                    return;
                }

                parentContainer.insertAdjacentHTML('afterbegin', getNowPlayingBarHtml());
                nowPlayingBarElement = parentContainer.querySelector('.nowPlayingBar');

                if (browser.safari && browser.slow) {
                    // Not handled well here. The wrong elements receive events, bar doesn't update quickly enough, etc.
                    nowPlayingBarElement.classList.add('noMediaProgress');
                }

                itemShortcuts.on(nowPlayingBarElement);

                bindEvents(nowPlayingBarElement);
                resolve(nowPlayingBarElement);
            });
        });
    }

    function showButton(button) {
        button.classList.remove('hide');
    }

    function hideButton(button) {
        button.classList.add('hide');
    }

    var lastUpdateTime = 0;

    function updatePlayerState(event, state) {

        if (!state.NowPlayingItem) {
            hideNowPlayingBar();
            return;
        }

        if (nowPlayingBarElement) {
            updatePlayerStateInternal(event, state);
            return;
        }

        getNowPlayingBar().then(function () {
            updatePlayerStateInternal(event, state);
        });
    }

    function updatePlayerStateInternal(event, state) {

        showNowPlayingBar();

        if (event.type == 'positionchange') {
            // Try to avoid hammering the document with changes
            var now = new Date().getTime();
            if ((now - lastUpdateTime) < 700) {

                return;
            }
            lastUpdateTime = now;
        }

        lastPlayerState = state;

        var playerInfo = MediaController.getPlayerInfo();

        var playState = state.PlayState || {};
        var i, length;

        if (playState.IsPaused) {

            for (i = 0, length = pauseButtons.length; i < length; i++) {
                hideButton(pauseButtons[i]);
            }
            for (i = 0, length = unpauseButtons.length; i < length; i++) {
                showButton(unpauseButtons[i]);
            }

        } else {

            for (i = 0, length = pauseButtons.length; i < length; i++) {
                showButton(pauseButtons[i]);
            }
            for (i = 0, length = unpauseButtons.length; i < length; i++) {
                hideButton(unpauseButtons[i]);
            }
        }

        updatePlayerVolumeState(state, playerInfo);

        var nowPlayingItem = state.NowPlayingItem || {};

        // See bindEvents for why this is necessary
        if (positionSlider) {
            if (!positionSlider.dragging) {

                if (nowPlayingItem.RunTimeTicks) {

                    var pct = playState.PositionTicks / nowPlayingItem.RunTimeTicks;
                    pct *= 100;

                    positionSlider.value = pct;

                } else {

                    positionSlider.value = 0;
                }

                positionSlider.disabled = !playState.CanSeek;
            }
        }

        var timeText = playState.PositionTicks == null ? '--:--' : datetime.getDisplayRunningTime(playState.PositionTicks);

        if (nowPlayingItem.RunTimeTicks) {

            timeText += " / " + datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks);

        }

        currentTimeElement.innerHTML = timeText;

        updateNowPlayingInfo(state);
    }

    function updatePlayerVolumeState(state, playerInfo) {

        playerInfo = playerInfo || MediaController.getPlayerInfo();

        var playState = state.PlayState || {};
        var supportedCommands = playerInfo.supportedCommands;

        var showMuteButton = true;
        var showUnmuteButton = true;
        var showVolumeSlider = true;

        if (supportedCommands.indexOf('Mute') == -1) {
            showMuteButton = false;
        }

        if (supportedCommands.indexOf('Unmute') == -1) {
            showUnmuteButton = false;
        }

        if (playState.IsMuted) {

            showMuteButton = false;
        } else {

            showUnmuteButton = false;
        }

        if (supportedCommands.indexOf('SetRepeatMode') == -1) {
            toggleRepeatButton.classList.add('hide');
        } else {
            toggleRepeatButton.classList.remove('hide');
        }

        if (playState.RepeatMode == 'RepeatAll') {
            toggleRepeatButtonIcon.innerHTML = "repeat";
            toggleRepeatButton.classList.add('repeatActive');
        }
        else if (playState.RepeatMode == 'RepeatOne') {
            toggleRepeatButtonIcon.innerHTML = "repeat_one";
            toggleRepeatButton.classList.add('repeatActive');
        } else {
            toggleRepeatButtonIcon.innerHTML = "repeat";
            toggleRepeatButton.classList.remove('repeatActive');
        }

        if (supportedCommands.indexOf('SetVolume') == -1) {
            showVolumeSlider = false;
        }

        if (playerInfo.isLocalPlayer && AppInfo.hasPhysicalVolumeButtons) {
            showMuteButton = false;
            showUnmuteButton = false;
            showVolumeSlider = false;
        }

        if (showMuteButton) {
            showButton(muteButton);
        } else {
            hideButton(muteButton);
        }

        if (showUnmuteButton) {
            showButton(unmuteButton);
        } else {
            hideButton(unmuteButton);
        }

        // See bindEvents for why this is necessary
        if (volumeSlider) {

            if (showVolumeSlider) {
                volumeSliderContainer.classList.remove('hide');
            } else {
                volumeSliderContainer.classList.add('hide');
            }

            if (!volumeSlider.dragging) {
                volumeSlider.value = playState.VolumeLevel || 0;
            }
        }
    }

    function getTextActionButton(item, text) {

        if (!text) {
            text = itemHelper.getDisplayName(item);
        }

        var html = '<button data-id="' + item.Id + '" data-type="' + item.Type + '" data-mediatype="' + item.MediaType + '" data-channelid="' + item.ChannelId + '" data-isfolder="' + item.IsFolder + '" type="button" class="itemAction textActionButton" data-action="link">';
        html += text;
        html += '</button>';

        return html;
    }

    var currentImgUrl;
    function updateNowPlayingInfo(state) {

        nowPlayingTextElement.innerHTML = MediaController.getNowPlayingNames(state.NowPlayingItem).map(function (nowPlayingName) {

            if (nowPlayingName.item) {
                return '<div>' + getTextActionButton(nowPlayingName.item, nowPlayingName.text) + '</div>';
            }

            return '<div>' + nowPlayingName.text + '</div>';

        }).join('');

        var url;
        var imgHeight = 70;

        var nowPlayingItem = state.NowPlayingItem;

        if (nowPlayingItem.PrimaryImageTag) {

            url = ApiClient.getScaledImageUrl(nowPlayingItem.PrimaryImageItemId, {
                type: "Primary",
                height: imgHeight,
                tag: nowPlayingItem.PrimaryImageTag
            });
        }
        else if (nowPlayingItem.BackdropImageTag) {

            url = ApiClient.getScaledImageUrl(nowPlayingItem.BackdropItemId, {
                type: "Backdrop",
                height: imgHeight,
                tag: nowPlayingItem.BackdropImageTag,
                index: 0
            });

        } else if (nowPlayingItem.ThumbImageTag) {

            url = ApiClient.getScaledImageUrl(nowPlayingItem.ThumbImageItemId, {
                type: "Thumb",
                height: imgHeight,
                tag: nowPlayingItem.ThumbImageTag
            });
        }

        else if (nowPlayingItem.Type == "TvChannel" || nowPlayingItem.Type == "Recording") {
            url = "css/images/items/detail/tv.png";
        }
        else if (nowPlayingItem.MediaType == "Audio") {
            url = "css/images/items/detail/audio.png";
        }
        else {
            url = "css/images/items/detail/video.png";
        }

        if (url == currentImgUrl) {
            return;
        }

        currentImgUrl = url;

        ImageLoader.lazyImage(nowPlayingImageElement, url);

        if (nowPlayingItem.Id) {
            ApiClient.getItem(Dashboard.getCurrentUserId(), nowPlayingItem.Id).then(function (item) {
                userdataButtons.fill({
                    item: item,
                    includePlayed: false,
                    element: nowPlayingUserData
                });
            });
        } else {
            userdataButtons.destroy({
                element: nowPlayingUserData
            });
        }
    }

    function onPlaybackStart(e, state) {

        console.log('nowplaying event: ' + e.type);

        var player = this;

        player.beginPlayerUpdates();

        onStateChanged.call(player, e, state);
    }

    function showNowPlayingBar() {

        getNowPlayingBar().then(slideUp);
    }

    function hideNowPlayingBar() {

        // Use a timeout to prevent the bar from hiding and showing quickly
        // in the event of a stop->play command

        // Don't call getNowPlayingBar here because we don't want to end up creating it just to hide it
        var elem = document.getElementsByClassName('nowPlayingBar')[0];
        if (elem) {
            slideDown(elem);
        }
    }

    function onPlaybackStopped(e, state) {

        console.log('nowplaying event: ' + e.type);
        var player = this;

        player.endPlayerUpdates();

        hideNowPlayingBar();
    }

    function onStateChanged(e, state) {

        //console.log('nowplaying event: ' + e.type);
        var player = this;

        if (player.isDefaultPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
            return;
        }

        updatePlayerState(e, state);
    }

    function releaseCurrentPlayer() {

        if (currentPlayer) {

            events.off(currentPlayer, 'playbackstart', onPlaybackStart);
            events.off(currentPlayer, 'playbackstop', onPlaybackStopped);
            events.off(currentPlayer, 'volumechange', onVolumeChanged);
            events.off(currentPlayer, 'playstatechange', onStateChanged);
            events.off(currentPlayer, 'positionchange', onStateChanged);

            currentPlayer.endPlayerUpdates();
            currentPlayer = null;

            hideNowPlayingBar();
        }
    }

    function onVolumeChanged(e) {

        var player = this;

        Promise.all([player.getPlayerState(), getNowPlayingBar()]).then(function (responses) {

            var state = responses[0];

            if (player.isDefaultPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
                return;
            }

            updatePlayerVolumeState(state);
        });
    }

    function bindToPlayer(player) {

        releaseCurrentPlayer();

        currentPlayer = player;

        player.getPlayerState().then(function (state) {

            if (state.NowPlayingItem) {
                player.beginPlayerUpdates();
            }

            onStateChanged.call(player, { type: 'init' }, state);
        });

        events.on(player, 'playbackstart', onPlaybackStart);
        events.on(player, 'playbackstop', onPlaybackStopped);
        events.on(player, 'volumechange', onVolumeChanged);
        events.on(player, 'playstatechange', onStateChanged);
        events.on(player, 'positionchange', onStateChanged);
    }

    events.on(MediaController, 'playerchange', function () {

        bindToPlayer(MediaController.getCurrentPlayer());
    });

    bindToPlayer(MediaController.getCurrentPlayer());

});