App.VideoPlayer = {
  init: function(videoElement) {
    // The source path for the video
    var videoUrl = $(videoElement).attr("src");

    // Replace the standard <video> element with the Clappr player
    $(videoElement).replaceWith($("<div>", { id: "player" }));
    var player = new Clappr.Player({
      <%= "baseUrl: 'http://cdn.clappr.io/latest'," if Rails.env.test? %>
      source: videoUrl, parentId: "#player", width: "100%",
      focusElement: NotTypingSelectiveListenerElement(document), // Allows keyboard shortcuts to work even if the player itself isn't in focus
      plugins: {
        core: [ClapprMarkersPlugin, PlaybackRatePlugin]
      },
      markersPlugin: { markers: [] }
    });

    return player;
  }
}

$(document).on("turbolinks:load", function() {
  $("[data-behavior=video-player]").each(function(index, element) {
    App.VideoPlayer.init(element);
  });
});

// An implementation of SelectiveListenerElement which only listens when text areas are not in focus
var NotTypingSelectiveListenerElement = function(element) {
  var inputInFocus    = function() { return $('input:focus, textarea:focus, video:focus').length > 0; }
  var noInputInFocus  = function() { return !inputInFocus(); }

  return new SelectiveListenerElement(element, noInputInFocus);
}

// A helper class that maintains a collection of handlers for a given event and callback
var HandlerCollection = function() {
  this.handlers = [];

  // Stores a handler for a given event and callback
  this.store = function(eventName, originalCallback, handler) {
    var item = {
      eventName: eventName, 
      callback: originalCallback,
      handler: handler,
    }
    this.handlers.push(item);
  }

  // Finds a handler for a given event and callback
  this.find = function(eventName, callback) {
    var handler = null;
    for (var i = 0; i < this.handlers.length; i++) {
      var item = this.handlers[i];

      if (item.eventName == eventName && item.callback == callback) {
        handler = item.handler;
      }
    }
    return handler;
  }
}

// A helper class to allow a DOM element to be wrapped and selectively ignore events that are triggered on it
var SelectiveListenerElement = function(element, shouldListenFn) {
  // The element we are proxying
  this.element = element;
  // A function that determines if we should run any event callbacks or not
  this.shouldRunCallbacks = shouldListenFn;
  // Stores the functions to be called when an event listener needs to be removed
  this.removeHandlers = new HandlerCollection();

  this.addEventListener = function(eventName, callback, useCapture) {
    // Create a new callback function that conditionally calls the original
    var conditionalCallback = function() {
      if (this.shouldRunCallbacks()) {
        callback();
      }
    }.bind(this);

    // Store the function to be called when removing the event listener
    this.removeHandlers.store(eventName, callback, function() {
      this.element.removeEventListener(eventName, conditionalCallback, useCapture);
    }.bind(this));

    // Attach an event listener to the same event with the conditional callback function
    this.element.addEventListener(eventName, conditionalCallback, useCapture);
  }

  this.removeEventListener = function(eventName, callback, useCapture) {
    var removeHandler = this.removeHandlers.find(eventName, callback);

    if (removeHandler != null) {
      removeHandler();
    }
  }
}
