/**
 * Playback widget  (play, pause ,  etc)
 */



(function (context, $) {


  // this check ensures we attempt to listen if this component is created in a popup
  var reactContext = window.opener ? window.opener : window
  // make sure this is actually us opening the window, not someone else (by checking for MixerStore)
  if (window.opener) {
    try {
      m = window.opener.MixerStore
    }
    catch (e) {
      reactContext = window
    }
  }

  var BrowserMediaStore = reactContext.BrowserMediaStore

  "use strict";

  var PlaybackMode = {
    NoPlayback: 0,
    EveryWhere: 1,
    PrivatePreview: 2,
    PreviewToAll: 3,
    LastPbMode: 4
  };


  context.JK = context.JK || {};
  context.JK.PlaybackControls = function ($parentElement, options) {

    options = $.extend(false, {playmodeControlsVisible: false, mediaActions: null}, options);

    var logger = context.JK.logger;
    if ($parentElement.length == 0) {
      logger.debug("no $parentElement specified in PlaybackControls");
    }

    var PLAYBACK_MONITOR_MODE = context.JK.PLAYBACK_MONITOR_MODE;

    var $playButton = $('.play-button img.playbutton', $parentElement);
    var $pauseButton = $('.play-button img.pausebutton', $parentElement);
    var $stopButton = $('.stop-button img.stopbutton', $parentElement);
    var $currentTime = $('.recording-current', $parentElement);
    var $duration = $('.duration-time', $parentElement);
    var $sliderBar = $('.recording-playback', $parentElement);
    var $slider = $('.recording-slider', $parentElement);
    var $playmodeButton = $('.playback-mode-buttons.icheckbuttons input', $parentElement);
    var $jamTrackGetReady = $('.jam-track-get-ready', $parentElement);

    var $self = $(this);

    var disabled = false;
    var playbackPlaying = false;
    var playbackDurationMs = 0;
    var playbackPositionMs = 0;
    var durationChanged = false;
    var seenActivity = false;

    var endReached = false;
    var dragging = false;
    var playingWhenDragStart = false;
    var draggingUpdateTimer = null;
    var canUpdateBackend = false;
    var playbackMode = PlaybackMode.EveryWhere;
    var monitorPlaybackTimeout = null;
    var playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE;
    var monitoring = false;

    function init() {
      updateSliderPosition(0);
      updateDurationTime(0);
      updateCurrentTime(0);
      seenActivity = false;
    }

    function startPlay() {
      seenActivity = false;
      updateIsPlaying(true);
      if (endReached) {
        update(0, playbackDurationMs, playbackPlaying);
      }

      if (options.mediaActions) {
        options.mediaActions.mediaStartPlay.trigger({playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode})
      }
      else {
        $self.triggerHandler('play', {playbackMode: playbackMode, playbackMonitorMode: playbackMonitorMode});
      }

      if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
        context.JK.GA.trackJamTrackPlaySession(context.SessionStore.id(), true)
      }
    }

    function stopPlay(endReached) {
      logger.debug("STOP PLAY CLICKED")
      updateIsPlaying(false);

      if (options.mediaActions) {
        logger.debug("mediaStopPlay", endReached)
        options.mediaActions.mediaStopPlay({
          playbackMode: playbackMode,
          playbackMonitorMode: playbackMonitorMode,
          endReached: endReached
        })
      }
      else {
        $self.triggerHandler('stop', {
          playbackMode: playbackMode,
          playbackMonitorMode: playbackMonitorMode,
          endReached: endReached
        });
      }
    }

    function pausePlay(endReached) {
      updateIsPlaying(false);

      if (options.mediaActions) {
        options.mediaActions.mediaPausePlay({
          playbackMode: playbackMode,
          playbackMonitorMode: playbackMonitorMode,
          endReached: endReached
        })
      }
      else {
        $self.triggerHandler('pause', {
          playbackMode: playbackMode,
          playbackMonitorMode: playbackMonitorMode,
          endReached: endReached
        });
      }
    }

    function updateOffsetBasedOnPosition(offsetLeft) {
      var sliderBarWidth = $sliderBar.width();

      playbackPositionMs = parseInt((offsetLeft / sliderBarWidth) * playbackDurationMs);
      updateCurrentTimeText(playbackPositionMs);
      if (canUpdateBackend) {
        if (options.mediaActions) {
          options.mediaActions.mediaChangePosition({
            positionMs: playbackPositionMs,
            playbackMonitorMode: playbackMonitorMode
          })
        }
        else {
          $self.triggerHandler('change-position', {
            positionMs: playbackPositionMs,
            playbackMonitorMode: playbackMonitorMode
          });
        }
        canUpdateBackend = false;
      }
    }

    function startDrag(e, ui) {
      dragging = true;
      playingWhenDragStart = playbackPlaying;
      //draggingUpdateTimer = setInterval(function() { canUpdateBackend = true; }, 333); // only call backend up to 3 times a second while dragging
      //if(playingWhenDragStart) {
      //stopPlay();
      //}
    }

    function stopDrag(e, ui) {
      dragging = false;

      clearInterval(draggingUpdateTimer);

      canUpdateBackend = true;
      updateOffsetBasedOnPosition(ui.position.left);
      updateSliderPosition(playbackPositionMs);

      //if(playingWhenDragStart) {
      //    playingWhenDragStart = false;
      //    startPlay();
      //}
    }

    function onDrag(e, ui) {
      updateOffsetBasedOnPosition(ui.position.left);
    }

    $playButton.on('click', function (e) {

      if (disabled) {
        logger.debug("PlaybackControls are disabled; ignoring start button")
        return;
      }
      startPlay();
      return false;
    });

    $pauseButton.on('click', function (e) {
      pausePlay();
      return false;
    });

    $stopButton.on('click', function (e) {
      stopPlay();
      return false;
    });

    $sliderBar.on('click', function (e) {
      var offset = e.pageX - $(this).offset().left;
      canUpdateBackend = true;
      updateOffsetBasedOnPosition(offset);
      updateSliderPosition(playbackPositionMs);
      return false;
    });

    $slider.draggable({
      axis: 'x',
      containment: $sliderBar,
      start: startDrag,
      stop: stopDrag,
      drag: onDrag
    });


    if (options.playmodeControlsVisible) {
      $('.playback-mode-buttons.icheckbuttons', $parentElement).show();
    }

    $playmodeButton.iCheck({
      checkboxClass: 'icheckbox_minimal',
      radioClass: 'iradio_minimal',
      inheritClass: true
    });


    $playmodeButton.on('ifChecked', function (e) {
      var playmode = $(this).val();
      logger.debug("set new playmode", playmode);
      setPlaybackMode(playmode);
    });

    function styleControls() {
      try {
        $jamTrackGetReady.attr('data-mode', playbackMonitorMode);

        $parentElement.removeClass('mediafile-mode jamtrack-mode metronome-mode');
        if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.MEDIA_FILE) {
          $parentElement.addClass('mediafile-mode');
        }
        else if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
          $parentElement.addClass('jamtrack-mode');
        }
        else if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.METRONOME) {
          $parentElement.addClass('metronome-mode');
        }
        else if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.BROWSER_MEDIA) {
          $parentElement.addClass('mediafile-mode');
        }
        else {
          throw "unknown playbackMonitorMode: " + playbackMonitorMode;
        }
      }
      catch (e) {
        logger.error("playbackControls: unable to style controls", e)
      }
    }

    function executeMonitor(positionMs, durationMs, isPlaying) {

      if (positionMs < 0) {
        // bug in backend?
        positionMs = 0;
      }

      if (positionMs > 0) {
        seenActivity = true;
      }

      if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.METRONOME) {
        updateIsPlaying(isPlaying);
      }
      else {
        update(positionMs, durationMs, isPlaying);
      }

      if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {

        if (playbackPlaying) {
          $jamTrackGetReady.attr('data-current-time', positionMs)
        }
        else {
          // this is so the jamtrack 'Get Ready!' stays hidden when it's not playing
          $jamTrackGetReady.attr('data-current-time', -1)
        }
      }

      if (setTimeout) {
        monitorPlaybackTimeout = setTimeout(monitorRecordingPlayback, 500);
      }
    }

    function monitorRecordingPlayback() {
      if (!monitoring) {
        return;
      }
      if (options.mediaActions) {
        options.mediaActions.positionUpdate(playbackMonitorMode)
      }
      else {
        if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
          var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs();
          var duration = context.jamClient.SessionGetJamTracksPlayDurationMs();
          var durationMs = duration.media_len;
          var isPlaying = context.jamClient.isSessionTrackPlaying();
        }
        else if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.BROWSER_MEDIA) {
          var positionMs = BrowserMediaStore.onGetPlayPosition() || 0
          var durationMs = BrowserMediaStore.onGetPlayDuration() || 0;
          var isPlaying = BrowserMediaStore.playing;
        }
        else {
          var positionMs = context.jamClient.SessionCurrrentPlayPosMs();
          var durationMs = context.jamClient.SessionGetTracksPlayDurationMs();
          var isPlaying = context.jamClient.isSessionTrackPlaying();
        }

        executeMonitor(positionMs, durationMs, isPlaying)
      }
    }

    function update(currentTimeMs, durationTimeMs, isPlaying, offsetStart) {

      if (dragging) {
        return;
      }

      // at the end of the play, the duration sets to 0, as does currentTime. but isPlaying does not reset to
      //logger.debug("currentTimeMs, durationTimeMs, mode", currentTimeMs, durationTimeMs, playbackMonitorMode);
      if (currentTimeMs == 0 && seenActivity) {
        if (playbackPlaying) {
          isPlaying = false;
          durationTimeMs = playbackDurationMs;
          currentTimeMs = playbackDurationMs;
          stopPlay(true);
          endReached = true;
          logger.debug("end reached");
        }
        else {
          // make sure slide shows '0'
          updateCurrentTime(currentTimeMs);
          return;
        }
      }


      if (currentTimeMs < offsetStart) {
        currentTimeMs = 0; // this is to squelch movement during tap-in period
      }
      updateDurationTime(durationTimeMs);
      updateCurrentTime(currentTimeMs);
      updateIsPlaying(isPlaying);

      durationChanged = false;
    }

    function updateDurationTime(timeMs) {
      try {
        if (timeMs != playbackDurationMs) {
          $duration.text(context.JK.prettyPrintSeconds(parseInt(timeMs / 1000)));
          playbackDurationMs = timeMs;
          durationChanged = true;
        }
      }
      catch (e) {
        logger.error("playbackControls: updateDurationTime error", e)
      }
    }

    function updateCurrentTimeText(timeMs) {
      try {
        var time = context.JK.prettyPrintSeconds(parseInt(timeMs / 1000))
        $currentTime.text(time);
        if (options.mediaActions) {
          options.mediaActions.currentTimeChanged(time)
        }
      }
      catch (e) {
        logger.error("playbackControls: updateCurrentTimeText error", e)
      }
    }

    function updateSliderPosition(timeMs) {

      try {
        var slideWidthPx = $sliderBar.width();
        var xPos = Math.ceil(timeMs / playbackDurationMs * slideWidthPx);
        $slider.css('left', xPos);
      }
      catch (e) {
        logger.error("playbackControls: updateSliderPosition error", e)
      }
    }

    function updateCurrentTime(timeMs) {
      try {
        if (timeMs != playbackPositionMs || durationChanged) {

          updateCurrentTimeText(timeMs);
          updateSliderPosition(timeMs);

          playbackPositionMs = timeMs;
        }
      }
      catch (e) {
        logger.error("playbackControls: updateCurrentTime err", e)
      }

    }

    function updateIsPlaying(isPlaying) {
      try {
        if (isPlaying != playbackPlaying) {
          if (isPlaying) {
            $playButton.hide();
            $pauseButton.show();
          }
          else {
            $playButton.show();
            $pauseButton.hide();
          }

          logger.debug("updating is playing: " + isPlaying)
          playbackPlaying = isPlaying;
        }
      }
      catch (e) {
        logger.error("playbackControls: updateIsPlaying error", e)
      }
    }

    function setPlaybackMode(mode) {
      if (mode == 'preview-to-all') {
        playbackMode = PlaybackMode.PreviewToAll;
      }
      else if (mode == 'preview-to-me') {
        playbackMode = PlaybackMode.PrivatePreview;
      }
      else if (mode == 'eveywhere') {
        playbackMode = PlaybackMode.EveryWhere;
      }
      else {
        logger.error("unable to set playback mode", mode);
      }

      // let the mode change immediately affect the behavior of the stream
      if (playbackPlaying) {
        stopPlay();
        startPlay();
      }
    }

    function startMonitor(_playbackMonitorMode) {
      logger.debug("startMonitor: " + _playbackMonitorMode)

      if (monitoring && _playbackMonitorMode == playbackMonitorMode) {
        return;
      }

      monitoring = true;
      // resets everything to zero
      init();

      if (_playbackMonitorMode === undefined || _playbackMonitorMode === null) {
        playbackMonitorMode = PLAYBACK_MONITOR_MODE.MEDIA_FILE;
      }
      else {
        playbackMonitorMode = _playbackMonitorMode;
      }

      logger.debug("playbackControl.startMonitor " + playbackMonitorMode + "")

      styleControls();

      if (monitorPlaybackTimeout != null) {
        clearTimeout(monitorPlaybackTimeout);
        monitorPlaybackTimeout = null;
      }
      monitorRecordingPlayback();
    }

    function stopMonitor() {
      monitoring = false;
      logger.debug("playbackControl.stopMonitor")
      if (monitorPlaybackTimeout != null) {
        if(clearTimeout) {
          clearTimeout(monitorPlaybackTimeout);
        }

        monitorPlaybackTimeout = null;
      }
    }

    function onPlayStartEvent() {
      updateIsPlaying(true);
      playbackPlaying = true;
      seenActivity = false;
    }

    function onPlayStopEvent() {
      updateIsPlaying(false);
      playbackPlaying = false;
    }

    function onPlayPauseEvent() {
      playbackPlaying = false;
    }

    function setDisabled(_disabled) {
      disabled = _disabled;
    }

    this.update = update;
    this.setPlaybackMode = setPlaybackMode;
    this.startMonitor = startMonitor;
    this.stopMonitor = stopMonitor;
    this.executeMonitor = executeMonitor;
    this.onPlayStopEvent = onPlayStopEvent;
    this.onPlayStartEvent = onPlayStartEvent;
    this.onPlayPauseEvent = onPlayPauseEvent;
    this.setDisabled = setDisabled;

    return this;
  }
})(window, jQuery);