// Copyright (c) 2012 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 "chrome/browser/ui/browser_list.h"

#include <algorithm>

#include "base/auto_reset.h"
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/lifetime/termination_notification.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/browser_window.h"
#include "content/public/browser/notification_service.h"

using base::UserMetricsAction;
using content::WebContents;

namespace {

BrowserList::BrowserVector GetBrowsersToClose(Profile* profile) {
  BrowserList::BrowserVector browsers_to_close;
  for (auto* browser : *BrowserList::GetInstance()) {
    if (browser->profile()->GetOriginalProfile() ==
        profile->GetOriginalProfile())
      browsers_to_close.push_back(browser);
  }
  return browsers_to_close;
}

BrowserList::BrowserVector GetIncognitoBrowsersToClose(Profile* profile) {
  BrowserList::BrowserVector browsers_to_close;
  for (auto* browser : *BrowserList::GetInstance()) {
    if (browser->profile() == profile)
      browsers_to_close.push_back(browser);
  }
  return browsers_to_close;
}

}  // namespace

// static
base::LazyInstance<base::ObserverList<BrowserListObserver>::Unchecked>::Leaky
    BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;

// static
BrowserList* BrowserList::instance_ = NULL;

////////////////////////////////////////////////////////////////////////////////
// BrowserList, public:

Browser* BrowserList::GetLastActive() const {
  if (!last_active_browsers_.empty())
    return *(last_active_browsers_.rbegin());
  return NULL;
}

// static
BrowserList* BrowserList::GetInstance() {
  BrowserList** list = &instance_;
  if (!*list)
    *list = new BrowserList;
  return *list;
}

// static
void BrowserList::AddBrowser(Browser* browser) {
  DCHECK(browser);
  DCHECK(browser->window()) << "Browser should not be added to BrowserList "
                               "until it is fully constructed.";
  GetInstance()->browsers_.push_back(browser);

  browser->RegisterKeepAlive();

  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_BROWSER_OPENED,
      content::Source<Browser>(browser),
      content::NotificationService::NoDetails());

  for (BrowserListObserver& observer : observers_.Get())
    observer.OnBrowserAdded(browser);

  if (browser->window()->IsActive())
    SetLastActive(browser);
}

// static
void BrowserList::RemoveBrowser(Browser* browser) {
  // Remove |browser| from the appropriate list instance.
  BrowserList* browser_list = GetInstance();
  RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
  browser_list->currently_closing_browsers_.erase(browser);

  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_BROWSER_CLOSED,
      content::Source<Browser>(browser),
      content::NotificationService::NoDetails());

  RemoveBrowserFrom(browser, &browser_list->browsers_);

  for (BrowserListObserver& observer : observers_.Get())
    observer.OnBrowserRemoved(browser);

  browser->UnregisterKeepAlive();

  // If we're exiting, send out the APP_TERMINATING notification to allow other
  // modules to shut themselves down.
  if (chrome::GetTotalBrowserCount() == 0 &&
      (browser_shutdown::IsTryingToQuit() ||
       g_browser_process->IsShuttingDown())) {
    // Last browser has just closed, and this is a user-initiated quit or there
    // is no module keeping the app alive, so send out our notification. No need
    // to call ProfileManager::ShutdownSessionServices() as part of the
    // shutdown, because Browser::WindowClosing() already makes sure that the
    // SessionService is created and notified.
    browser_shutdown::NotifyAppTerminating();
    chrome::OnAppExiting();
  }
}

// static
void BrowserList::AddObserver(BrowserListObserver* observer) {
  observers_.Get().AddObserver(observer);
}

// static
void BrowserList::RemoveObserver(BrowserListObserver* observer) {
  observers_.Get().RemoveObserver(observer);
}

// static
void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) {
  BrowserVector browsers_to_close;
  for (auto* browser : *BrowserList::GetInstance()) {
    if (browser->profile()->GetOriginalProfile() ==
        profile->GetOriginalProfile())
      browsers_to_close.push_back(browser);
  }

  for (BrowserVector::const_iterator it = browsers_to_close.begin();
       it != browsers_to_close.end(); ++it) {
    (*it)->window()->Close();
  }
}

// static
void BrowserList::CloseAllBrowsersWithProfile(
    Profile* profile,
    const CloseCallback& on_close_success,
    const CloseCallback& on_close_aborted,
    bool skip_beforeunload) {
  TryToCloseBrowserList(GetBrowsersToClose(profile), on_close_success,
                        on_close_aborted, profile->GetPath(),
                        skip_beforeunload);
}

// static
void BrowserList::CloseAllBrowsersWithIncognitoProfile(
    Profile* profile,
    const CloseCallback& on_close_success,
    const CloseCallback& on_close_aborted,
    bool skip_beforeunload) {
  DCHECK(profile->IsOffTheRecord());
  TryToCloseBrowserList(GetIncognitoBrowsersToClose(profile), on_close_success,
                        on_close_aborted, profile->GetPath(),
                        skip_beforeunload);
}

// static
void BrowserList::TryToCloseBrowserList(const BrowserVector& browsers_to_close,
                                        const CloseCallback& on_close_success,
                                        const CloseCallback& on_close_aborted,
                                        const base::FilePath& profile_path,
                                        const bool skip_beforeunload) {
  for (auto it = browsers_to_close.begin(); it != browsers_to_close.end();
       ++it) {
    if ((*it)->TryToCloseWindow(
            skip_beforeunload,
            base::Bind(&BrowserList::PostTryToCloseBrowserWindow,
                       browsers_to_close, on_close_success, on_close_aborted,
                       profile_path, skip_beforeunload))) {
      return;
    }
  }

  if (on_close_success)
    on_close_success.Run(profile_path);

  for (Browser* b : browsers_to_close) {
    // BeforeUnload handlers may close browser windows, so we need to explicitly
    // check whether they still exist.
    if (b->window())
      b->window()->Close();
  }
}

// static
void BrowserList::PostTryToCloseBrowserWindow(
    const BrowserVector& browsers_to_close,
    const CloseCallback& on_close_success,
    const CloseCallback& on_close_aborted,
    const base::FilePath& profile_path,
    const bool skip_beforeunload,
    bool tab_close_confirmed) {
  // We need this bool to avoid infinite recursion when resetting the
  // BeforeUnload handlers, since doing that will trigger calls back to this
  // method for each affected window.
  static bool resetting_handlers = false;

  if (tab_close_confirmed) {
    TryToCloseBrowserList(browsers_to_close, on_close_success, on_close_aborted,
                          profile_path, skip_beforeunload);
  } else if (!resetting_handlers) {
    base::AutoReset<bool> resetting_handlers_scoper(&resetting_handlers, true);
    for (auto it = browsers_to_close.begin(); it != browsers_to_close.end();
         ++it) {
      (*it)->ResetTryToCloseWindow();
    }
    if (on_close_aborted)
      on_close_aborted.Run(profile_path);
  }
}

// static
void BrowserList::MoveBrowsersInWorkspaceToFront(
    const std::string& new_workspace) {
  DCHECK(!new_workspace.empty());

  BrowserList* instance = GetInstance();

  Browser* old_last_active = instance->GetLastActive();
  BrowserVector& last_active_browsers = instance->last_active_browsers_;

  // Perform a stable partition on the browsers in the list so that the browsers
  // in the new workspace appear after the browsers in the other workspaces.
  //
  // For example, if we have a list of browser-workspace pairs
  // [{b1, 0}, {b2, 1}, {b3, 0}, {b4, 1}]
  // and we switch to workspace 1, we want the resulting browser list to look
  // like [{b1, 0}, {b3, 0}, {b2, 1}, {b4, 1}].
  std::stable_partition(
      last_active_browsers.begin(), last_active_browsers.end(),
      [&new_workspace](Browser* browser) {
        return !browser->window()->IsVisibleOnAllWorkspaces() &&
               browser->window()->GetWorkspace() != new_workspace;
      });

  Browser* new_last_active = instance->GetLastActive();
  if (old_last_active != new_last_active) {
    for (BrowserListObserver& observer : observers_.Get())
      observer.OnBrowserSetLastActive(new_last_active);
  }
}

// static
void BrowserList::SetLastActive(Browser* browser) {
  BrowserList* instance = GetInstance();
  DCHECK(std::find(instance->begin(), instance->end(), browser) !=
         instance->end())
      << "SetLastActive called for a browser before the browser was added to "
         "the BrowserList.";
  DCHECK(browser->window() != nullptr)
      << "SetLastActive called for a browser with no window set.";

  base::RecordAction(UserMetricsAction("ActiveBrowserChanged"));

  RemoveBrowserFrom(browser, &instance->last_active_browsers_);
  instance->last_active_browsers_.push_back(browser);

  for (BrowserListObserver& observer : observers_.Get())
    observer.OnBrowserSetLastActive(browser);
}

// static
void BrowserList::NotifyBrowserNoLongerActive(Browser* browser) {
  BrowserList* instance = GetInstance();
  DCHECK(std::find(instance->begin(), instance->end(), browser) !=
         instance->end())
      << "NotifyBrowserNoLongerActive called for a browser before the browser "
         "was added to the BrowserList.";
  DCHECK(browser->window() != nullptr)
      << "NotifyBrowserNoLongerActive called for a browser with no window set.";

  for (BrowserListObserver& observer : observers_.Get())
    observer.OnBrowserNoLongerActive(browser);
}

// static
void BrowserList::NotifyBrowserCloseStarted(Browser* browser) {
  GetInstance()->currently_closing_browsers_.insert(browser);

  for (BrowserListObserver& observer : observers_.Get())
    observer.OnBrowserClosing(browser);
}

// static
bool BrowserList::IsIncognitoSessionActive() {
  for (auto* browser : *BrowserList::GetInstance()) {
    if (browser->profile()->IsOffTheRecord())
      return true;
  }
  return false;
}

// static
int BrowserList::GetIncognitoSessionsActiveForProfile(Profile* profile) {
  BrowserList* list = BrowserList::GetInstance();
  return std::count_if(list->begin(), list->end(), [profile](Browser* browser) {
    return browser->profile()->IsSameProfile(profile) &&
           browser->profile()->IsOffTheRecord();
  });
}
////////////////////////////////////////////////////////////////////////////////
// BrowserList, private:

BrowserList::BrowserList() {
}

BrowserList::~BrowserList() {
}

// static
void BrowserList::RemoveBrowserFrom(Browser* browser,
                                    BrowserVector* browser_list) {
  auto remove_browser =
      std::find(browser_list->begin(), browser_list->end(), browser);
  if (remove_browser != browser_list->end())
    browser_list->erase(remove_browser);
}
