// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//     You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//     See the License for the specific language governing permissions and
// limitations under the License.
(function(shared, scope, testing) {

  var nullTarget = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');

  var sequenceNumber = 0;
  scope.bindAnimationForCustomEffect = function(animation) {
    var target = animation.effect.target;
    var effectFunction;
    var isKeyframeEffect = typeof animation.effect.getFrames() == 'function';
    if (isKeyframeEffect) {
      effectFunction = animation.effect.getFrames();
    } else {
      effectFunction = animation.effect._onsample;
    }
    var timing = animation.effect.timing;
    var last = null;
    timing = shared.normalizeTimingInput(timing);
    var callback = function() {
      var t = callback._animation ? callback._animation.currentTime : null;
      if (t !== null) {
        t = shared.calculateIterationProgress(shared.calculateActiveDuration(timing), t, timing);
        if (isNaN(t))
          t = null;
      }
      // FIXME: There are actually more conditions under which the effectFunction
      // should be called.
      if (t !== last) {
        if (isKeyframeEffect) {
          effectFunction(t, target, animation.effect);
        } else {
          effectFunction(t, animation.effect, animation.effect._animation);
        }
      }
      last = t;
    };

    callback._animation = animation;
    callback._registered = false;
    callback._sequenceNumber = sequenceNumber++;
    animation._callback = callback;
    register(callback);
  };

  var callbacks = [];
  var ticking = false;
  function register(callback) {
    if (callback._registered)
      return;
    callback._registered = true;
    callbacks.push(callback);
    if (!ticking) {
      ticking = true;
      requestAnimationFrame(tick);
    }
  }

  function tick(t) {
    var updating = callbacks;
    callbacks = [];
    updating.sort(function(left, right) {
      return left._sequenceNumber - right._sequenceNumber;
    });
    updating = updating.filter(function(callback) {
      callback();
      var playState = callback._animation ? callback._animation.playState : 'idle';
      if (playState != 'running' && playState != 'pending')
        callback._registered = false;
      return callback._registered;
    });
    callbacks.push.apply(callbacks, updating);

    if (callbacks.length) {
      ticking = true;
      requestAnimationFrame(tick);
    } else {
      ticking = false;
    }
  }

  scope.Animation.prototype._register = function() {
    if (this._callback)
      register(this._callback);
  };

})(webAnimationsShared, webAnimationsNext, webAnimationsTesting);
