// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_animation_controller.h"

#include "base/functional/bind.h"
#import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h"
#include "content/public/browser/web_contents.h"

namespace {

// If the fullscreen toolbar is hidden, it is difficult for the user to see
// changes in the tabstrip. As a result, if a tab is inserted or the current
// tab switched to a new one, the toolbar must animate in and out to display
// the tabstrip changes to the user. The animation drops down the toolbar and
// then wait for 0.75 seconds before it hides the toolbar.
const NSTimeInterval kTabStripChangesDelay = 750;

}  // end namespace

//////////////////////////////////////////////////////////////////
// FullscreenToolbarAnimationController, public:

FullscreenToolbarAnimationController::FullscreenToolbarAnimationController(
    FullscreenToolbarController* owner)
    : WebContentsObserver(nullptr),
      owner_(owner),
      animation_(this),
      hide_toolbar_timer_(
          FROM_HERE,
          base::Milliseconds(kTabStripChangesDelay),
          base::BindRepeating(&FullscreenToolbarAnimationController::
                                  AnimateToolbarOutIfPossible,
                              base::Unretained(this))),
      animation_start_value_(0),
      should_hide_toolbar_after_delay_(false) {
  animation_.SetSlideDuration(base::Milliseconds(200));
  animation_.SetTweenType(gfx::Tween::EASE_OUT);
}

FullscreenToolbarAnimationController::~FullscreenToolbarAnimationController() =
    default;

void FullscreenToolbarAnimationController::ToolbarDidUpdate() {
  animation_start_value_ = [owner_ toolbarFraction];
}

void FullscreenToolbarAnimationController::StopAnimationAndTimer() {
  animation_.Stop();
  hide_toolbar_timer_.Stop();
}

void FullscreenToolbarAnimationController::AnimateToolbarForTabstripChanges(
    content::WebContents* contents,
    bool in_foreground) {
  // Don't kickstart the animation if the toolbar is already displayed.
  if ([owner_ mustShowFullscreenToolbar])
    return;

  if (animation_.IsShowing()) {
    hide_toolbar_timer_.Reset();
    Observe(nullptr);
    return;
  }

  should_hide_toolbar_after_delay_ = true;
  if (in_foreground && contents &&
      !contents->CompletedFirstVisuallyNonEmptyPaint()) {
    Observe(contents);
  }

  AnimateToolbarIn();
}

void FullscreenToolbarAnimationController::AnimateToolbarIn() {
  if (![owner_ isInFullscreen])
    return;

  animation_.Reset(animation_start_value_);
  animation_.Show();
}

void FullscreenToolbarAnimationController::AnimateToolbarOutIfPossible() {
  if (![owner_ isInFullscreen] || [owner_ mustShowFullscreenToolbar])
    return;

  if (animation_.IsClosing())
    return;

  animation_.Stop();
  animation_.Hide();
}

CGFloat FullscreenToolbarAnimationController::GetToolbarFractionFromProgress()
    const {
  return animation_.GetCurrentValue();
}

bool FullscreenToolbarAnimationController::IsAnimationRunning() const {
  return animation_.is_animating();
}

//////////////////////////////////////////////////////////////////
// FullscreenToolbarAnimationController::WebContentsObserver:

void FullscreenToolbarAnimationController::DidFirstVisuallyNonEmptyPaint() {
  StartHideTimerIfPossible();
  Observe(nullptr);
}

//////////////////////////////////////////////////////////////////
// FullscreenToolbarAnimationController::AnimationDelegate:

void FullscreenToolbarAnimationController::AnimationProgressed(
    const gfx::Animation* animation) {
  [owner_ layoutToolbar];
}

void FullscreenToolbarAnimationController::AnimationEnded(
    const gfx::Animation* animation) {
  if (!web_contents() && animation_.IsShowing())
    StartHideTimerIfPossible();
}

//////////////////////////////////////////////////////////////////
// FullscreenToolbarAnimationController, private:

void FullscreenToolbarAnimationController::StartHideTimerIfPossible() {
  DCHECK(animation_.IsShowing());
  if (should_hide_toolbar_after_delay_) {
    hide_toolbar_timer_.Reset();
    should_hide_toolbar_after_delay_ = false;
  }
}
