text: // Copyright 2014 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 "components/infobars/core/infobar_manager.h"
  
  #include "base/command_line.h"
  #include "components/infobars/core/infobar.h"
  #include "components/infobars/core/infobars_switches.h"
  
  namespace infobars {
  
  
  // InfoBarManager::Observer ---------------------------------------------------
  
  void InfoBarManager::Observer::OnInfoBarAdded(InfoBar* infobar) {
  }
  
  void InfoBarManager::Observer::OnInfoBarRemoved(InfoBar* infobar,
                                                  bool animate) {
  }
  
  void InfoBarManager::Observer::OnInfoBarReplaced(InfoBar* old_infobar,
                                                   InfoBar* new_infobar) {
  }
  
  void InfoBarManager::Observer::OnManagerShuttingDown(InfoBarManager* manager) {
  }
  
  
  // InfoBarManager --------------------------------------------------------------
  
  InfoBar* InfoBarManager::AddInfoBar(scoped_ptr<InfoBar> infobar) {
    DCHECK(infobar);
    if (!infobars_enabled_)
      return NULL;
  
    for (InfoBars::const_iterator i(infobars_.begin()); i != infobars_.end();
         ++i) {
      if ((*i)->delegate()->EqualsDelegate(infobar->delegate())) {
        DCHECK_NE((*i)->delegate(), infobar->delegate());
        return NULL;
      }
    }
  
    InfoBar* infobar_ptr = infobar.release();
    infobars_.push_back(infobar_ptr);
    infobar_ptr->SetOwner(this);
  
    NotifyInfoBarAdded(infobar_ptr);
  
    return infobar_ptr;
  }
  
  void InfoBarManager::RemoveInfoBar(InfoBar* infobar) {
    RemoveInfoBarInternal(infobar, true);
  }
  
  void InfoBarManager::RemoveAllInfoBars(bool animate) {
    while (!infobars_.empty())
      RemoveInfoBarInternal(infobars_.back(), animate);
  }
  
  InfoBar* InfoBarManager::ReplaceInfoBar(InfoBar* old_infobar,
                                          scoped_ptr<InfoBar> new_infobar) {
    DCHECK(old_infobar);
    if (!infobars_enabled_)
      return AddInfoBar(new_infobar.Pass());  // Deletes the infobar.
    DCHECK(new_infobar);
  
    InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(),
                                   old_infobar));
    DCHECK(i != infobars_.end());
  
    InfoBar* new_infobar_ptr = new_infobar.release();
    i = infobars_.insert(i, new_infobar_ptr);
    new_infobar_ptr->SetOwner(this);
  
    // Remove the old infobar before notifying, so that if any observers call back
    // to AddInfoBar() or similar, we don't dupe-check against this infobar.
    infobars_.erase(++i);
  
    FOR_EACH_OBSERVER(Observer,
                      observer_list_,
                      OnInfoBarReplaced(old_infobar, new_infobar_ptr));
  
    old_infobar->CloseSoon();
    return new_infobar_ptr;
  }
  
  void InfoBarManager::AddObserver(Observer* obs) {
    observer_list_.AddObserver(obs);
  }
  
  void InfoBarManager::RemoveObserver(Observer* obs) {
    observer_list_.RemoveObserver(obs);
  }
  
  InfoBarManager::InfoBarManager()
      : infobars_enabled_(true) {
    if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableInfoBars))
      infobars_enabled_ = false;
  }
  
  InfoBarManager::~InfoBarManager() {}
  
  void InfoBarManager::ShutDown() {
    // Destroy all remaining InfoBars.  It's important to not animate here so that
    // we guarantee that we'll delete all delegates before we do anything else.
    RemoveAllInfoBars(false);
    FOR_EACH_OBSERVER(Observer, observer_list_, OnManagerShuttingDown(this));
  }
  
  void InfoBarManager::OnNavigation(
      const InfoBarDelegate::NavigationDetails& details) {
    // NOTE: It is not safe to change the following code to count upwards or
    // use iterators, as the RemoveInfoBar() call synchronously modifies our
    // delegate list.
    for (size_t i = infobars_.size(); i > 0; --i) {
      InfoBar* infobar = infobars_[i - 1];
      if (infobar->delegate()->ShouldExpire(details))
        RemoveInfoBar(infobar);
    }
  }
  
  void InfoBarManager::NotifyInfoBarAdded(InfoBar* infobar) {
    FOR_EACH_OBSERVER(Observer, observer_list_, OnInfoBarAdded(infobar));
  }
  
  void InfoBarManager::NotifyInfoBarRemoved(InfoBar* infobar, bool animate) {
    FOR_EACH_OBSERVER(Observer, observer_list_,
                      OnInfoBarRemoved(infobar, animate));
  }
  
  void InfoBarManager::RemoveInfoBarInternal(InfoBar* infobar, bool animate) {
    DCHECK(infobar);
    if (!infobars_enabled_) {
      DCHECK(infobars_.empty());
      return;
    }
  
    InfoBars::iterator i(std::find(infobars_.begin(), infobars_.end(), infobar));
    DCHECK(i != infobars_.end());
  
    // Remove the infobar before notifying, so that if any observers call back to
    // AddInfoBar() or similar, we don't dupe-check against this infobar.
    infobars_.erase(i);
  
    // This notification must happen before the call to CloseSoon() below, since
    // observers may want to access |infobar| and that call can delete it.
    NotifyInfoBarRemoved(infobar, animate);
  
    infobar->CloseSoon();
  }
  
  }  // namespace infobars
  