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

#include "ui/message_center/ui_controller.h"

#include <memory>

#include "base/macros.h"
#include "base/observer_list.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_types.h"
#include "ui/message_center/notification_blocker.h"
#include "ui/message_center/ui_delegate.h"
#include "ui/message_center/views/notification_menu_model.h"
#include "ui/strings/grit/ui_strings.h"

namespace message_center {

UiController::UiController(UiDelegate* delegate)
    : message_center_(MessageCenter::Get()),
      message_center_visible_(false),
      popups_visible_(false),
      delegate_(delegate) {
  message_center_->AddObserver(this);
}

UiController::~UiController() {
  message_center_->RemoveObserver(this);
}

bool UiController::ShowMessageCenterBubble(bool show_by_click) {
  if (message_center_visible_)
    return true;

  HidePopupBubbleInternal();

  message_center_visible_ = delegate_->ShowMessageCenter(show_by_click);
  if (message_center_visible_) {
    message_center_->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
    NotifyUiControllerChanged();
  }
  return message_center_visible_;
}

bool UiController::HideMessageCenterBubble() {
#if defined(OS_CHROMEOS)
  // TODO(yoshiki): Move the message center bubble related logic to ash/.
  hide_empty_message_center_callback_.reset();
#endif

  if (!message_center_visible_)
    return false;
  delegate_->HideMessageCenter();
  MarkMessageCenterHidden();

  return true;
}

void UiController::MarkMessageCenterHidden() {
  if (!message_center_visible_)
    return;
  message_center_visible_ = false;
  message_center_->SetVisibility(message_center::VISIBILITY_TRANSIENT);

  // Some notifications (like system ones) should appear as popups again
  // after the message center is closed.
  if (message_center_->HasPopupNotifications()) {
    ShowPopupBubble();
    return;
  }

  NotifyUiControllerChanged();
}

void UiController::ShowPopupBubble() {
  if (message_center_visible_)
    return;

  if (popups_visible_) {
    NotifyUiControllerChanged();
    return;
  }

  if (!message_center_->HasPopupNotifications())
    return;

  popups_visible_ = delegate_->ShowPopups();

  NotifyUiControllerChanged();
}

bool UiController::HidePopupBubble() {
  if (!popups_visible_)
    return false;
  HidePopupBubbleInternal();
  NotifyUiControllerChanged();

  return true;
}

void UiController::HidePopupBubbleInternal() {
  if (!popups_visible_)
    return;

  delegate_->HidePopups();
  popups_visible_ = false;
}

void UiController::ShowNotifierSettingsBubble() {
  if (popups_visible_)
    HidePopupBubbleInternal();

  message_center_visible_ = delegate_->ShowNotifierSettings();
  message_center_->SetVisibility(message_center::VISIBILITY_SETTINGS);

  NotifyUiControllerChanged();
}

void UiController::OnNotificationAdded(const std::string& notification_id) {
  OnMessageCenterChanged();
}

void UiController::OnNotificationRemoved(const std::string& notification_id,
                                         bool by_user) {
  OnMessageCenterChanged();
}

void UiController::OnNotificationUpdated(const std::string& notification_id) {
  OnMessageCenterChanged();
}

void UiController::OnNotificationClicked(const std::string& notification_id) {
  if (popups_visible_)
    OnMessageCenterChanged();
}

void UiController::OnNotificationButtonClicked(
    const std::string& notification_id,
    int button_index) {
  if (popups_visible_)
    OnMessageCenterChanged();
}

void UiController::OnNotificationSettingsClicked(bool handled) {
  if (!handled)
    ShowNotifierSettingsBubble();
}

void UiController::OnNotificationDisplayed(const std::string& notification_id,
                                           const DisplaySource source) {
  NotifyUiControllerChanged();
}

void UiController::OnQuietModeChanged(bool in_quiet_mode) {
  NotifyUiControllerChanged();
}

void UiController::OnBlockingStateChanged(NotificationBlocker* blocker) {
  OnMessageCenterChanged();
}

void UiController::OnMessageCenterChanged() {
#if defined(OS_CHROMEOS)
  // TODO(yoshiki): Move the message center bubble related logic to ash/.
  if (message_center_visible_ && message_center_->NotificationCount() == 0) {
    if (hide_empty_message_center_callback_)
      return;

    hide_empty_message_center_callback_ =
        std::make_unique<base::CancelableClosure>(base::Bind(
            base::IgnoreResult(&UiController::HideMessageCenterBubble),
            base::Unretained(this)));
    base::ThreadTaskRunnerHandle::Get()->PostTask(
        FROM_HERE, hide_empty_message_center_callback_->callback());
    return;
  }

  // Cancel the callback if necessary.
  if (hide_empty_message_center_callback_)
    hide_empty_message_center_callback_.reset();
#endif

  if (popups_visible_ && !message_center_->HasPopupNotifications())
    HidePopupBubbleInternal();
  else if (!popups_visible_ && message_center_->HasPopupNotifications())
    ShowPopupBubble();

  NotifyUiControllerChanged();
}

void UiController::NotifyUiControllerChanged() {
  delegate_->OnMessageCenterContentsChanged();
}

}  // namespace message_center
