/* automatically pause videos that are playing off screen, then automatically
 * play them when they come back on screen */

(function() {
  'use strict';

  // discover what this browser uses for visibility
  // https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API
  var hidden_property;
  var visibility_change_event;
  var visibility_api_available = true;
  if (document.hidden !== undefined) {
    hidden_property = 'hidden';
    visibility_change_event = 'visibilitychange';
  } else if (document.mozHidden !== undefined) {
    hidden_property = 'mozHidden';
    visibility_change_event = 'mozvisibilitychange';
  } else if (document.msHidden !== undefined) {
    hidden_property = 'msHidden';
    visibility_change_event = 'msvisibilitychange';
  } else if (document.webkitHidden !== undefined) {
    hidden_property = 'webkitHidden';
    visibility_change_event = 'webkitvisibilitychange';
  } else {
    visibility_api_available = false;
  }

  function is_element_on_screen(elem) {
    // based on http://stackoverflow.com/a/7557433

    // if window is not visible, count as everything being off screen
    if (visibility_api_available && document[hidden_property]) { return false; }
    else if (elem.getBoundingClientRect === undefined) { return false; }

    var rect = elem.getBoundingClientRect();
    return (
      rect.right >= 0 &&
      rect.bottom >= 0 &&
      rect.left <= (window.innerWidth || document.documentElement.clientWidth) &&
      rect.top <= (window.innerHeight || document.documentElement.clientHeight)
    );
  }

  function is_muted(video) {
    // if video lacks audio, it is muted
    if (!(video.classList.contains('has_audio'))) {
      return true;
    }
    return video.muted;
  }

  function toggle_auto_pause() {
    /* go through all videos pausing and playing according to their current state
     * (whether off screen and playing or on screen and auto paused) */
    var videos = document.getElementsByTagName('video');
    var i;
    for (i=0; i < videos.length; i++) {
      // if off screen and playing, pause it (unless it's unmuted)
      if (!is_element_on_screen(videos[i])) {
        if ((!videos[i].paused) && (is_muted(videos[i]))) {
          videos[i].classList.add('autopaused');
          videos[i].pause();
        }
      }
      // on screen and auto paused, play it
      else if (videos[i].classList.contains('autopaused')) {
        videos[i].classList.remove('autopaused');
        // don't actually play if the video hasn't loaded yet
        if (videos[i].readyState >= 3) {
          videos[i].play();
        }
      }
      // on screen but hasn't finished loading
      else if (videos[i].readyState < 3) {
          videos[i].autoplay = 'autoplay';
      }
    }
  }

  // whether or not we're waiting before going through the videos
  var waiting_to_toggle = false;
  var wait_during_scroll_delay = 50; // milliseconds

  function check_videos_visibility() {
    /* check and toggle appropriate videos after possible a change to their
     * visibility */

    // make sure at least one video exists
    if (document.getElementsByTagName('video').length == 0) {
      return;
    }

    // we'll set a delay so we don't go through the whole process after every
    // pixel the user scrolls
    if (waiting_to_toggle) { return; }
    else {
      waiting_to_toggle = true;
      // wait for the delay
      window.setTimeout(function () {
        toggle_auto_pause();
        waiting_to_toggle = false;
      }, wait_during_scroll_delay);
    }
  }

  function check_on_play() {
    /* check once if video is offscreen on play */
    /* jshint validthis:true */
    this.removeEventListener('play', check_on_play);
    if (!is_element_on_screen(this) && is_muted(this)) {
      this.pause();
      this.classList.add('autopaused');
    }
  }

  function setup_videos() {
    /* go through all videos pausing those offscreen and setting up a listener
     * for those on screen to check them again when they start playing for the
     * first time */
    var videos = document.getElementsByTagName('video');
    var i;
    for (i=0; i < videos.length; i++) {
      if (videos[i].dataset.checkingVisibility !== 'true') {
        /* add event to check whether the video is on screen when it starts
         * playing for the first time */
        videos[i].addEventListener('play', check_on_play);
        videos[i].dataset.checkingVisibility = 'true';
      }
    }
  }

  function setup_auto_pause() {
    window.addEventListener('scroll', check_videos_visibility);
    window.addEventListener('resize', check_videos_visibility);
    if (visibility_api_available) {
      document.addEventListener(visibility_change_event, check_videos_visibility);
    }

    setup_videos();
  }

  window.addEventListener('DOMContentLoaded', setup_auto_pause);
  window.addEventListener('newVideoCreated', setup_videos);
}());
