// Copyright (c) 2011 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 CHROME_BROWSER_UI_BROWSER_LIST_H_
#define CHROME_BROWSER_UI_BROWSER_LIST_H_
#pragma once

#include <vector>

#include "base/observer_list.h"
#include "chrome/browser/ui/browser.h"

// Stores a list of all Browser objects.
class BrowserList {
 public:
  typedef std::vector<Browser*> BrowserVector;
  typedef BrowserVector::iterator iterator;
  typedef BrowserVector::const_iterator const_iterator;
  typedef BrowserVector::const_reverse_iterator const_reverse_iterator;

  // It is not allowed to change the global window list (add or remove any
  // browser windows while handling observer callbacks.
  class Observer {
   public:
    // Called immediately after a browser is added to the list
    virtual void OnBrowserAdded(const Browser* browser) = 0;

    // Called immediately after a browser is removed from the list
    virtual void OnBrowserRemoved(const Browser* browser) = 0;

    // Called immediately after a browser is set active (SetLastActive)
    virtual void OnBrowserSetLastActive(const Browser* browser) {}

   protected:
    virtual ~Observer() {}
  };

  // Adds and removes browsers from the global list. The browser object should
  // be valid BEFORE these calls (for the benefit of observers), so notify and
  // THEN delete the object.
  static void AddBrowser(Browser* browser);
  static void RemoveBrowser(Browser* browser);

  static void AddObserver(Observer* observer);
  static void RemoveObserver(Observer* observer);

  // Called by Browser objects when their window is activated (focused).  This
  // allows us to determine what the last active Browser was.
  static void SetLastActive(Browser* browser);

  // Returns the Browser object whose window was most recently active.  If the
  // most recently open Browser's window was closed, returns the first Browser
  // in the list.  If no Browsers exist, returns NULL.
  //
  // WARNING: this is NULL until a browser becomes active. If during startup
  // a browser does not become active (perhaps the user launches Chrome, then
  // clicks on another app before the first browser window appears) then this
  // returns NULL.
  // WARNING #2: this will always be NULL in unit tests run on the bots.
  static Browser* GetLastActive();

  // Identical in behavior to GetLastActive(), except that the most recently
  // open browser owned by |profile| is returned. If none exist, returns NULL.
  // WARNING: see warnings in GetLastActive().
  static Browser* GetLastActiveWithProfile(Profile *profile);

  // Find an existing browser window with the provided type. Searches in the
  // order of last activation. Only browsers that have been active can be
  // returned. If |match_incognito| is true, will match a browser with either
  // a regular or incognito profile that matches the given one. Returns NULL if
  // no such browser currently exists.
  static Browser* FindBrowserWithType(Profile* p, Browser::Type t,
                                      bool match_incognito);

  // Find an existing browser window that can provide the specified type (this
  // uses Browser::CanSupportsWindowFeature, not
  // Browser::SupportsWindowFeature). This searches in the order of last
  // activation. Only browsers that have been active can be returned. Returns
  // NULL if no such browser currently exists.
  static Browser* FindBrowserWithFeature(Profile* p,
                                         Browser::WindowFeature feature);

  // Find an existing browser window with the provided profile. Searches in the
  // order of last activation. Only browsers that have been active can be
  // returned. Returns NULL if no such browser currently exists.
  static Browser* FindBrowserWithProfile(Profile* p);

  // Find an existing browser with the provided ID. Returns NULL if no such
  // browser currently exists.
  static Browser* FindBrowserWithID(SessionID::id_type desired_id);

  // Checks if the browser can be automatically restarted to install upgrades
  // The browser can be automatically restarted when:
  // 1. It's in the background mode (no visible windows).
  // 2. An update exe is present in the install folder.
  static bool CanRestartForUpdate();

  // Called from Browser::Exit.
  static void Exit();

  // Closes all browsers and exits.  This is equivalent to
  // CloseAllBrowsers(true) on platforms where the application exits when no
  // more windows are remaining.  On other platforms (the Mac), this will
  // additionally exit the application.
  static void CloseAllBrowsersAndExit();

  // Closes all browsers. If the session is ending the windows are closed
  // directly. Otherwise the windows are closed by way of posting a WM_CLOSE
  // message.
  static void CloseAllBrowsers();

  // Begins shutdown of the application when the desktop session is ending.
  static void SessionEnding();

  // Returns true if there is at least one Browser with the specified profile.
  static bool HasBrowserWithProfile(Profile* profile);

  // Tells the BrowserList to keep the application alive after the last Browser
  // closes. This is implemented as a count, so callers should pair their calls
  // to StartKeepAlive() with matching calls to EndKeepAlive() when they no
  // longer need to keep the application running.
  static void StartKeepAlive();

  // Stops keeping the application alive after the last Browser is closed.
  // Should match a previous call to StartKeepAlive().
  static void EndKeepAlive();

  // Returns true if application will continue running after the last Browser
  // closes.
  static bool WillKeepAlive();

  // Browsers are added to |browsers_| before they have constructed windows,
  // so the |window()| member function may return NULL.
  static const_iterator begin() { return browsers_.begin(); }
  static const_iterator end() { return browsers_.end(); }

  static bool empty() { return browsers_.empty(); }
  static size_t size() { return browsers_.size(); }

  // Returns iterated access to list of open browsers ordered by when
  // they were last active. The underlying data structure is a vector
  // and we push_back on recent access so a reverse iterator gives the
  // latest accessed browser first.
  static const_reverse_iterator begin_last_active() {
    return last_active_browsers_.rbegin();
  }

  static const_reverse_iterator end_last_active() {
    return last_active_browsers_.rend();
  }

  // Return the number of browsers with the following profile which are
  // currently open.
  static size_t GetBrowserCount(Profile* p);

  // Return the number of browsers with the following profile and type which are
  // currently open.
  static size_t GetBrowserCountForType(Profile* p, Browser::Type type);

  // Returns true if at least one incognito session is active.
  static bool IsOffTheRecordSessionActive();

  // Send out notifications.
  // For ChromeOS, also request session manager to end the session.
  static void NotifyAndTerminate(bool fast_path);

  // Called once there are no more browsers open and the application is exiting.
  static void AllBrowsersClosedAndAppExiting();

 private:
  // Helper method to remove a browser instance from a list of browsers
  static void RemoveBrowserFrom(Browser* browser, BrowserVector* browser_list);
  static void MarkAsCleanShutdown();
#if defined(OS_CHROMEOS)
  static bool NeedBeforeUnloadFired();
  static bool PendingDownloads();
  static void NotifyWindowManagerAboutSignout();

  static bool signout_;
#endif

  static BrowserVector browsers_;
  static BrowserVector last_active_browsers_;
  static ObserverList<Observer> observers_;

  // Counter of calls to StartKeepAlive(). If non-zero, the application will
  // continue running after the last browser has exited.
  static int keep_alive_count_;
};

class TabContentsWrapper;

// Iterates through all web view hosts in all browser windows. Because the
// renderers act asynchronously, getting a host through this interface does
// not guarantee that the renderer is ready to go. Doing anything to affect
// browser windows or tabs while iterating may cause incorrect behavior.
//
// Example:
//   for (TabContentsIterator iterator; !iterator.done(); ++iterator) {
//     TabContents* cur = *iterator;
//     -or-
//     iterator->operationOnTabContents();
//     ...
//   }
class TabContentsIterator {
 public:
  TabContentsIterator();

  // Returns true if we are past the last Browser.
  bool done() const {
    return cur_ == NULL;
  }

  // Returns the Browser instance associated with the current TabContents.
  // Valid as long as !Done()
  Browser* browser() const {
    return *browser_iterator_;
  }

  // Returns the current TabContents, valid as long as !Done()
  TabContentsWrapper* operator->() const {
    return cur_;
  }
  TabContentsWrapper* operator*() const {
    return cur_;
  }

  // Incrementing operators, valid as long as !Done()
  TabContentsWrapper* operator++() {  // ++preincrement
    Advance();
    return cur_;
  }
  TabContentsWrapper* operator++(int) {  // postincrement++
    TabContentsWrapper* tmp = cur_;
    Advance();
    return tmp;
  }

 private:
  // Loads the next host into Cur. This is designed so that for the initial
  // call when browser_iterator_ points to the first browser and
  // web_view_index_ is -1, it will fill the first host.
  void Advance();

  // iterator over all the Browser objects
  BrowserList::const_iterator browser_iterator_;

  // tab index into the current Browser of the current web view
  int web_view_index_;

  // Current TabContents, or NULL if we're at the end of the list. This can
  // be extracted given the browser iterator and index, but it's nice to cache
  // this since the caller may access the current host many times.
  TabContentsWrapper* cur_;
};

#endif  // CHROME_BROWSER_UI_BROWSER_LIST_H_