// Copyright 2015 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.

#ifndef CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
#define CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_

#include "base/macros.h"
#include "content/browser/renderer_host/overscroll_controller_delegate.h"
#include "content/common/content_export.h"
#include "ui/compositor/layer_animation_observer.h"

namespace aura {
class Window;
}

namespace ui {
class Layer;
class LayerAnimator;
}

namespace content {

class ShadowLayerDelegate;
class WebContentsImpl;

// Manages the animation of a window sliding on top or behind another one. The
// main window, which is the one displayed before the animation starts, is not
// owned by OverscrollWindowAnimation, while the slide window, created at the
// start of the animation, is owned by us for its duration.
class CONTENT_EXPORT OverscrollWindowAnimation
    : public OverscrollControllerDelegate,
      ui::ImplicitAnimationObserver {
 public:
  // The direction of this animation. SLIDE_FRONT indicates that the slide
  // window moves on top of the main window, entering the screen from the right.
  // SLIDE_BACK means that the main window is animated to the right, revealing
  // the slide window in the back. SLIDE_NONE means we are not animating yet.
  // Both windows are animated at the same time but at different speeds,
  // creating a parallax scrolling effect. Left and right are reversed for RTL
  // languages, but stack order remains unchanged.
  enum Direction { SLIDE_FRONT, SLIDE_BACK, SLIDE_NONE };

  // Delegate class that interfaces with the window animation.
  class CONTENT_EXPORT Delegate {
   public:
    virtual ~Delegate() {}

    // Create a slide window with the given |bounds| relative to its parent.
    virtual scoped_ptr<aura::Window> CreateFrontWindow(
        const gfx::Rect& bounds) = 0;
    virtual scoped_ptr<aura::Window> CreateBackWindow(
        const gfx::Rect& bounds) = 0;

    // Returns the main window that participates in the animation. The delegate
    // does not own this window.
    virtual aura::Window* GetMainWindow() const = 0;

    // Called when we know the animation is going to complete successfully, but
    // before it actually completes.
    virtual void OnOverscrollCompleting() = 0;

    // Called when the animation has been completed. The slide window is
    // transferred to the delegate.
    virtual void OnOverscrollCompleted(scoped_ptr<aura::Window> window) = 0;

    // Called when the overscroll gesture has been cancelled, after the cancel
    // animation finishes.
    virtual void OnOverscrollCancelled() = 0;
  };

  explicit OverscrollWindowAnimation(Delegate* delegate);

  ~OverscrollWindowAnimation() override;

  // Returns true if we are currently animating.
  bool is_active() const { return !!slide_window_; }

  // OverscrollControllerDelegate:
  gfx::Rect GetVisibleBounds() const override;
  bool OnOverscrollUpdate(float delta_x, float delta_y) override;
  void OnOverscrollComplete(OverscrollMode overscroll_mode) override;
  void OnOverscrollModeChange(OverscrollMode old_mode,
                              OverscrollMode new_mode) override;

 private:
  // Cancels the slide, animating the front and back window to their original
  // positions.
  void CancelSlide();

  // Returns a translation on the x axis for the given overscroll.
  float GetTranslationForOverscroll(float delta_x);

  // Animates a translation of the given |layer|. If |listen_for_completion| is
  // true, adds |this| as observer of the animation.
  void AnimateTranslation(ui::Layer* layer,
                          float translate_x,
                          bool listen_for_completion);

  // Return the front/back layer that is involved in the animation. The caller
  // does not own it.
  ui::Layer* GetFrontLayer() const;
  ui::Layer* GetBackLayer() const;

  // ui::ImplicitAnimationObserver:
  void OnImplicitAnimationsCompleted() override;

  // We own the window created for the animation.
  scoped_ptr<aura::Window> slide_window_;

  // Shadow shown under the animated layer.
  scoped_ptr<ShadowLayerDelegate> shadow_;

  // Delegate that provides the animation target and is notified of the
  // animation state.
  Delegate* delegate_;

  // The current animation direction.
  Direction direction_;

  // Indicates if the current slide has been cancelled. True while the cancel
  // animation is in progress.
  bool overscroll_cancelled_;

  DISALLOW_COPY_AND_ASSIGN(OverscrollWindowAnimation);
};

}  // namespace content

#endif  // CONTENT_BROWSER_WEB_CONTENTS_AURA_OVERSCROLL_WINDOW_ANIMATION_H_
