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

#include "ui/views/bubble/tooltip_icon.h"

#include "base/timer/timer.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/bubble/info_bubble.h"
#include "ui/views/mouse_watcher_view_host.h"

namespace views {

TooltipIcon::TooltipIcon(const base::string16& tooltip, int tooltip_icon_size)
    : tooltip_(tooltip),
      tooltip_icon_size_(tooltip_icon_size),
      mouse_inside_(false),
      bubble_(nullptr),
      preferred_width_(0),
      observer_(this) {
  SetDrawAsHovered(false);
}

TooltipIcon::~TooltipIcon() {
  HideBubble();
}

const char* TooltipIcon::GetClassName() const {
  return "TooltipIcon";
}

void TooltipIcon::OnMouseEntered(const ui::MouseEvent& event) {
  mouse_inside_ = true;
  show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150), this,
                    &TooltipIcon::ShowBubble);
}

void TooltipIcon::OnMouseExited(const ui::MouseEvent& event) {
  show_timer_.Stop();
}

bool TooltipIcon::OnMousePressed(const ui::MouseEvent& event) {
  // Swallow the click so that the parent doesn't process it.
  return true;
}

void TooltipIcon::OnGestureEvent(ui::GestureEvent* event) {
  if (event->type() == ui::ET_GESTURE_TAP) {
    ShowBubble();
    event->SetHandled();
  }
}

void TooltipIcon::GetAccessibleNodeData(ui::AXNodeData* node_data) {
  node_data->role = ax::mojom::Role::kTooltip;
  node_data->SetName(tooltip_);
}

void TooltipIcon::MouseMovedOutOfHost() {
  if (IsMouseHovered()) {
    mouse_watcher_->Start(GetWidget()->GetNativeWindow());
    return;
  }

  mouse_inside_ = false;
  HideBubble();
}

void TooltipIcon::SetDrawAsHovered(bool hovered) {
  SetImage(
      gfx::CreateVectorIcon(vector_icons::kInfoOutlineIcon, tooltip_icon_size_,
                            hovered ? SkColorSetARGB(0xBD, 0, 0, 0)
                                    : SkColorSetARGB(0xBD, 0x44, 0x44, 0x44)));
}

void TooltipIcon::ShowBubble() {
  if (bubble_)
    return;

  SetDrawAsHovered(true);

  bubble_ = new InfoBubble(this, tooltip_);
  bubble_->set_preferred_width(preferred_width_);
  bubble_->SetArrow(anchor_point_arrow_);
  // When shown due to a gesture event, close on deactivate (i.e. don't use
  // "focusless").
  bubble_->set_can_activate(!mouse_inside_);

  bubble_->Show();
  observer_.Add(bubble_->GetWidget());

  if (mouse_inside_) {
    View* frame = bubble_->GetWidget()->non_client_view()->frame_view();
    mouse_watcher_ = std::make_unique<MouseWatcher>(
        std::make_unique<MouseWatcherViewHost>(frame, gfx::Insets()), this);
    mouse_watcher_->Start(GetWidget()->GetNativeWindow());
  }
}

void TooltipIcon::HideBubble() {
  if (bubble_)
    bubble_->Hide();
}

void TooltipIcon::OnWidgetDestroyed(Widget* widget) {
  observer_.Remove(widget);

  SetDrawAsHovered(false);
  mouse_watcher_.reset();
  bubble_ = nullptr;
}

}  // namespace views
