// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.require('base.event_target');
base.require('base.raf');
base.require('ui.animation');

base.exportTo('ui', function() {
  /**
   * Manages execution, queueing and blending of ui.Animations against
   * a single target.
   *
   * Targets must have a cloneAnimationState() method that returns all the
   * animatable states of that target.
   *
   * @constructor
   * @extends {base.EventTarget}
   */
  function AnimationController() {
    base.EventTarget.call(this);

    this.target_ = undefined;

    this.activeAnimation_ = undefined;

    this.tickScheduled_ = false;
  }

  AnimationController.prototype = {
    __proto__: base.EventTarget.prototype,

    get target() {
      return this.target_;
    },

    set target(target) {
      if (this.activeAnimation_)
        throw new Error('Cannot change target while animation is running.');
      if (target.cloneAnimationState === undefined ||
          typeof target.cloneAnimationState !== 'function')
        throw new Error('target must have a cloneAnimationState function');

      this.target_ = target;
    },

    get activeAnimation() {
      return this.activeAnimation;
    },

    get hasActiveAnimation() {
      return !!this.activeAnimation_;
    },

    queueAnimation: function(animation, opt_now) {
      if (this.target_ === undefined)
        throw new Error('Cannot queue animations without a target');

      var now;
      if (opt_now !== undefined)
        now = opt_now;
      else
        now = window.performance.now();

      if (this.activeAnimation_) {
        // Must tick the animation before stopping it case its about to stop,
        // and to update the target with its final sets of edits up to this
        // point.
        var done = this.activeAnimation_.tick(now, this.target_);
        if (done)
          this.activeAnimation_ = undefined;
      }

      if (this.activeAnimation_) {
        if (animation.canTakeOverFor(this.activeAnimation_)) {
          this.activeAnimation_.didStopEarly(now, this.target_, true);
          animation.takeOverFor(this.activeAnimation_, now, this.target_);
        } else {
          this.activeAnimation_.didStopEarly(now, this.target_, false);
        }
      }
      this.activeAnimation_ = animation;
      this.activeAnimation_.start(now, this.target_);

      if (this.tickScheduled_)
        return;
      this.tickScheduled_ = true;
      base.requestAnimationFrame(this.tickActiveAnimation_, this);
    },

    cancelActiveAnimation: function(opt_now) {
      if (!this.activeAnimation_)
        return;
      var now;
      if (opt_now !== undefined)
        now = opt_now;
      else
        now = window.performance.now();
      this.activeAnimation_.didStopEarly(now, this.target_, false);
      this.activeAnimation_ = undefined;
    },

    tickActiveAnimation_: function(frameBeginTime) {
      this.tickScheduled_ = false;
      if (!this.activeAnimation_)
        return;

      if (this.target_ === undefined) {
        this.activeAnimation_.didStopEarly(frameBeginTime, this.target_, false);
        return;
      }

      var oldTargetState = this.target_.cloneAnimationState();

      var done = this.activeAnimation_.tick(frameBeginTime, this.target_);
      if (done)
        this.activeAnimation_ = undefined;

      if (this.activeAnimation_) {
        this.tickScheduled_ = true;
        base.requestAnimationFrame(this.tickActiveAnimation_, this);
      }

      if (oldTargetState) {
        var e = new Event('didtick');
        e.oldTargetState = oldTargetState;
        this.dispatchEvent(e, false, false);
      }
    }
  };

  return {
    AnimationController: AnimationController
  };
});

@@ -1315,24 +1315,25 @@
 iveAnimation
+_
 ;%0A    %7D,%0A%0A  

Fix AnimationController.activeAnimation getter