// 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_GOOGLE_GOOGLE_URL_TRACKER_H_
#define CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_H_
#pragma once

#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
#include "chrome/common/net/url_fetcher.h"
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
#include "googleurl/src/gurl.h"
#include "net/base/network_change_notifier.h"

class NavigationController;
class PrefService;
class TabContents;
class TemplateURL;

// This object is responsible for checking the Google URL once per network
// change, and if necessary prompting the user to see if they want to change to
// using it.  The current and last prompted values are saved to prefs.
//
// Most consumers should only call GoogleURL(), which is guaranteed to
// synchronously return a value at all times (even during startup or in unittest
// mode).  Consumers who need to be notified when things change should listen to
// the notification service for NOTIFY_GOOGLE_URL_UPDATED, and call GoogleURL()
// again after receiving it, in order to get the updated value.
//
// To protect users' privacy and reduce server load, no updates will be
// performed (ever) unless at least one consumer registers interest by calling
// RequestServerCheck().
class GoogleURLTracker : public URLFetcher::Delegate,
                         public NotificationObserver,
                         public net::NetworkChangeNotifier::IPAddressObserver {
 public:
  // Only the main browser process loop should call this, when setting up
  // g_browser_process->google_url_tracker_.  No code other than the
  // GoogleURLTracker itself should actually use
  // g_browser_process->google_url_tracker() (which shouldn't be hard, since
  // there aren't useful public functions on this object for consumers to access
  // anyway).
  GoogleURLTracker();

  virtual ~GoogleURLTracker();

  // Returns the current Google URL.  This will return a valid URL even in
  // unittest mode.
  //
  // This is the only function most code should ever call.
  static GURL GoogleURL();

  // Requests that the tracker perform a server check to update the Google URL
  // as necessary.  This will happen at most once per network change, not
  // sooner than five seconds after startup (checks requested before that time
  // will occur then; checks requested afterwards will occur immediately, if
  // no other checks have been made during this run).
  //
  // In unittest mode, this function does nothing.
  static void RequestServerCheck();

  static void RegisterPrefs(PrefService* prefs);

  // Notifies the tracker that the user has started a Google search.
  // If prompting is necessary, we then listen for the subsequent
  // NAV_ENTRY_PENDING notification to get the appropriate NavigationController.
  // When the load commits, we'll show the infobar.
  static void GoogleURLSearchCommitted();

  static const char kDefaultGoogleHomepage[];
  static const char kSearchDomainCheckURL[];

  // Methods called from InfoBar delegate.
  void AcceptGoogleURL(const GURL& google_url);
  void CancelGoogleURL(const GURL& google_url);
  void InfoBarClosed();
  void RedoSearch();

 private:
  friend class GoogleURLTrackerTest;

  typedef InfoBarDelegate* (*InfobarCreator)(TabContents*,
                                             GoogleURLTracker*,
                                             const GURL&);

  // Registers consumer interest in getting an updated URL from the server.
  // It will be notified as NotificationType::GOOGLE_URL_UPDATED, so the
  // consumer should observe this notification before calling this.
  void SetNeedToFetch();

  // Begins the five-second startup sleep period, unless a test has cleared
  // |queue_wakeup_task_|.
  void QueueWakeupTask();

  // Called when the five second startup sleep has finished.  Runs any pending
  // fetch.
  void FinishSleep();

  // Starts the fetch of the up-to-date Google URL if we actually want to fetch
  // it and can currently do so.
  void StartFetchIfDesirable();

  // URLFetcher::Delegate
  virtual void OnURLFetchComplete(const URLFetcher *source,
                                  const GURL& url,
                                  const net::URLRequestStatus& status,
                                  int response_code,
                                  const ResponseCookies& cookies,
                                  const std::string& data);

  // NotificationObserver
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details);

  // NetworkChangeNotifier::IPAddressObserver
  virtual void OnIPAddressChanged();

  void SearchCommitted();
  void OnNavigationPending(const NotificationSource& source,
                           const GURL& pending_url);
  void OnNavigationCommittedOrTabClosed(TabContents* tab_contents,
                                        NotificationType::Type type);
  void ShowGoogleURLInfoBarIfNecessary(TabContents* tab_contents);

  NotificationRegistrar registrar_;
  InfobarCreator infobar_creator_;
  // TODO(ukai): GoogleURLTracker should track google domain (e.g. google.co.uk)
  // rather than URL (e.g. http://www.google.co.uk/), so that user could
  // configure to use https in search engine templates.
  GURL google_url_;
  GURL fetched_google_url_;
  ScopedRunnableMethodFactory<GoogleURLTracker> runnable_method_factory_;
  scoped_ptr<URLFetcher> fetcher_;
  int fetcher_id_;
  bool queue_wakeup_task_;
  bool in_startup_sleep_;  // True if we're in the five-second "no fetching"
                           // period that begins at browser start.
  bool already_fetched_;   // True if we've already fetched a URL once this run;
                           // we won't fetch again until after a restart.
  bool need_to_fetch_;     // True if a consumer actually wants us to fetch an
                           // updated URL.  If this is never set, we won't
                           // bother to fetch anything.
                           // Consumers should observe
                           // NotificationType::GOOGLE_URL_UPDATED.
  bool need_to_prompt_;    // True if the last fetched Google URL is not
                           // matched with current user's default Google URL
                           // nor the last prompted Google URL.
  NavigationController* controller_;
  InfoBarDelegate* infobar_;
  GURL search_url_;

  DISALLOW_COPY_AND_ASSIGN(GoogleURLTracker);
};


// This infobar delegate is declared here (rather than in the .cc file) so test
// code can subclass it.
class GoogleURLTrackerInfoBarDelegate : public ConfirmInfoBarDelegate {
 public:
  GoogleURLTrackerInfoBarDelegate(TabContents* tab_contents,
                                  GoogleURLTracker* google_url_tracker,
                                  const GURL& new_google_url);

  // ConfirmInfoBarDelegate:
  virtual bool Accept();
  virtual bool Cancel();
  virtual void InfoBarClosed();

 protected:
  virtual ~GoogleURLTrackerInfoBarDelegate();

  GoogleURLTracker* google_url_tracker_;
  const GURL new_google_url_;

 private:
  // ConfirmInfoBarDelegate:
  virtual string16 GetMessageText() const;
  virtual string16 GetButtonLabel(InfoBarButton button) const;

  DISALLOW_COPY_AND_ASSIGN(GoogleURLTrackerInfoBarDelegate);
};

#endif  // CHROME_BROWSER_GOOGLE_GOOGLE_URL_TRACKER_H_