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

#ifndef CHROME_BROWSER_UI_SEARCH_INSTANT_NTP_PRERENDERER_H_
#define CHROME_BROWSER_UI_SEARCH_INSTANT_NTP_PRERENDERER_H_

#include <string>

#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_change_registrar.h"
#include "chrome/browser/search/instant_service_observer.h"
#include "chrome/browser/ui/search/instant_page.h"
#include "content/public/browser/web_contents.h"
#include "net/base/network_change_notifier.h"

class InstantNTP;
class InstantService;
class PrefService;
class Profile;

// InstantNTPPrerenderer maintains a prerendered instance of InstantNTP.
//
// An InstantNTP instance is a preloaded search page that will be swapped-in the
// next time when the user navigates to the New Tab Page. It is never shown to
// the user in an uncommitted state. It is backed by a WebContents and that is
// owned by InstantNTP.
//
// InstantNTPPrerenderer is owned by InstantService.
class InstantNTPPrerenderer
    : public InstantPage::Delegate,
      public net::NetworkChangeNotifier::NetworkChangeObserver,
      public InstantServiceObserver {
 public:
  InstantNTPPrerenderer(Profile* profile, InstantService* instant_service,
      PrefService* prefs);
  virtual ~InstantNTPPrerenderer();

  // Preloads |ntp_| with a new InstantNTP.
  void ReloadInstantNTP();

  // Releases and returns the InstantNTP WebContents. May be NULL. Loads a new
  // WebContents for the InstantNTP.
  scoped_ptr<content::WebContents> ReleaseNTPContents() WARN_UNUSED_RESULT;

  // The NTP WebContents. May be NULL. InstantNTPPrerenderer retains ownership.
  content::WebContents* GetNTPContents() const;

  // Invoked to null out |ntp_|.
  void DeleteNTPContents();

  // Invoked when the InstantNTP renderer process crashes.
  void RenderProcessGone();

  // Invoked when the |ntp_| main frame load completes.
  void LoadCompletedMainFrame();

 protected:
  // Returns the local Instant URL. (Just a convenience wrapper to get the local
  // Instant URL from InstantService.)
  virtual std::string GetLocalInstantURL() const;

  // Returns the correct Instant URL to use from the following possibilities:
  //     o The default search engine's Instant URL.
  //     o The local page (see GetLocalInstantURL())
  // Returns an empty string if no valid Instant URL is available (this is only
  // possible in non-extended mode where we don't have a local page fall-back).
  virtual std::string GetInstantURL() const;

  // Returns true if Javascript is enabled and false otherwise.
  virtual bool IsJavascriptEnabled() const;

  // Returns true if the browser is in startup.
  virtual bool InStartup() const;

  // Accessors are made protected for testing purposes.
  virtual InstantNTP* ntp() const;

  Profile* profile() const {
    return profile_;
  }

 private:
  friend class InstantExtendedTest;
  friend class InstantNTPPrerendererTest;
  friend class InstantTestBase;

  FRIEND_TEST_ALL_PREFIXES(InstantExtendedNetworkTest,
                           NTPReactsToNetworkChanges);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           PrefersRemoteNTPOnStartup);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           SwitchesToLocalNTPIfNoInstantSupport);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           SwitchesToLocalNTPIfPathBad);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           DoesNotSwitchToLocalNTPIfOnCurrentNTP);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           DoesNotSwitchToLocalNTPIfOnLocalNTP);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           SwitchesToLocalNTPIfJSDisabled);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           SwitchesToLocalNTPIfNoNTPReady);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           IsJavascriptEnabled);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           IsJavascriptEnabledChecksContentSettings);
  FRIEND_TEST_ALL_PREFIXES(InstantNTPPrerendererTest,
                           IsJavascriptEnabledChecksPrefs);
  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest, MANUAL_ShowsGoogleNTP);
  FRIEND_TEST_ALL_PREFIXES(InstantExtendedManualTest,
                           MANUAL_SearchesFromFakebox);
  FRIEND_TEST_ALL_PREFIXES(InstantExtendedTest, ProcessIsolation);

  // Overridden from net::NetworkChangeNotifier::NetworkChangeObserver:
  // If the network status changes, resets InstantNTP.
  virtual void OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type)
      OVERRIDE;

  // Overridden from InstantPage::Delegate:
  virtual void InstantSupportDetermined(const content::WebContents* contents,
                                        bool supports_instant) OVERRIDE;
  virtual void InstantPageAboutToNavigateMainFrame(
      const content::WebContents* contents,
      const GURL& url) OVERRIDE;
  virtual void NavigateToURL(const content::WebContents* contents,
                             const GURL& url,
                             content::PageTransition transition,
                             WindowOpenDisposition disposition,
                             bool is_search_type) OVERRIDE;
  virtual void PasteIntoOmnibox(const content::WebContents* contents,
                                const string16& text) OVERRIDE;
  virtual void InstantPageLoadFailed(content::WebContents* contents) OVERRIDE;

  // Overridden from InstantServiceObserver:
  virtual void DefaultSearchProviderChanged() OVERRIDE;
  virtual void GoogleURLUpdated() OVERRIDE;

  // Recreates |ntp_| using |instant_url|.
  void ResetNTP(const std::string& instant_url);

  // Returns true if |ntp_| has an up-to-date Instant URL and supports Instant.
  // Note that local URLs will not pass this check.
  bool PageIsCurrent() const;

  // Returns true if we should switch to using the local NTP.
  bool ShouldSwitchToLocalNTP() const;

  Profile* profile_;

  // Preloaded InstantNTP.
  scoped_ptr<InstantNTP> ntp_;

  PrefChangeRegistrar profile_pref_registrar_;

  DISALLOW_COPY_AND_ASSIGN(InstantNTPPrerenderer);
};

#endif  // CHROME_BROWSER_UI_SEARCH_INSTANT_NTP_PRERENDERER_H_