// 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/singleton_tabs.h"

#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_url_handler.h"
#include "content/public/browser/web_contents.h"

namespace chrome {
namespace {

// Returns true if two URLs are equal after taking |replacements| into account.
bool CompareURLsWithReplacements(
    const GURL& url,
    const GURL& other,
    const url_canon::Replacements<char>& replacements) {
  if (url == other)
    return true;

  GURL url_replaced = url.ReplaceComponents(replacements);
  GURL other_replaced = other.ReplaceComponents(replacements);
  return url_replaced == other_replaced;
}

}  // namespace

void ShowSingletonTab(Browser* browser, const GURL& url) {
  NavigateParams params(GetSingletonTabNavigateParams(browser, url));
  Navigate(&params);
}

void ShowSingletonTabRespectRef(Browser* browser, const GURL& url) {
  NavigateParams params(GetSingletonTabNavigateParams(browser, url));
  params.ref_behavior = NavigateParams::RESPECT_REF;
  Navigate(&params);
}

void ShowSingletonTabOverwritingNTP(Browser* browser,
                                    const NavigateParams& params) {
  DCHECK(browser);
  NavigateParams local_params(params);
  content::WebContents* contents =
      browser->tab_strip_model()->GetActiveWebContents();
  if (contents) {
    const GURL& contents_url = contents->GetURL();
    if ((contents_url == GURL(kChromeUINewTabURL) || IsInstantNTP(contents) ||
         contents_url == GURL(content::kAboutBlankURL)) &&
        GetIndexOfSingletonTab(&local_params) < 0) {
      local_params.disposition = CURRENT_TAB;
    }
  }

  Navigate(&local_params);
}

NavigateParams GetSingletonTabNavigateParams(Browser* browser,
                                             const GURL& url) {
  NavigateParams params(browser, url, content::PAGE_TRANSITION_AUTO_BOOKMARK);
  params.disposition = SINGLETON_TAB;
  params.window_action = NavigateParams::SHOW_WINDOW;
  params.user_gesture = true;
  params.tabstrip_add_types |= TabStripModel::ADD_INHERIT_OPENER;
  return params;
}

// Returns the index of an existing singleton tab in |params->browser| matching
// the URL specified in |params|.
int GetIndexOfSingletonTab(NavigateParams* params) {
  if (params->disposition != SINGLETON_TAB)
    return -1;

  // In case the URL was rewritten by the BrowserURLHandler we need to ensure
  // that we do not open another URL that will get redirected to the rewritten
  // URL.
  GURL rewritten_url(params->url);
  bool reverse_on_redirect = false;
  content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary(
      &rewritten_url,
      params->browser->profile(),
      &reverse_on_redirect);

  // If there are several matches: prefer the active tab by starting there.
  int start_index =
      std::max(0, params->browser->tab_strip_model()->active_index());
  int tab_count = params->browser->tab_strip_model()->count();
  for (int i = 0; i < tab_count; ++i) {
    int tab_index = (start_index + i) % tab_count;
    content::WebContents* tab =
        params->browser->tab_strip_model()->GetWebContentsAt(tab_index);

    GURL tab_url = tab->GetURL();

    // Skip view-source tabs. This is needed because RewriteURLIfNecessary
    // removes the "view-source:" scheme which leads to incorrect matching.
    if (tab_url.SchemeIs(content::kViewSourceScheme))
      continue;

    GURL rewritten_tab_url = tab_url;
    content::BrowserURLHandler::GetInstance()->RewriteURLIfNecessary(
      &rewritten_tab_url,
      params->browser->profile(),
      &reverse_on_redirect);

    url_canon::Replacements<char> replacements;
    if (params->ref_behavior == NavigateParams::IGNORE_REF)
      replacements.ClearRef();
    if (params->path_behavior == NavigateParams::IGNORE_AND_NAVIGATE ||
        params->path_behavior == NavigateParams::IGNORE_AND_STAY_PUT) {
      replacements.ClearPath();
      replacements.ClearQuery();
    }

    if (CompareURLsWithReplacements(tab_url, params->url, replacements) ||
        CompareURLsWithReplacements(rewritten_tab_url,
                                    rewritten_url,
                                    replacements)) {
      params->target_contents = tab;
      return tab_index;
    }
  }

  return -1;
}

}  // namespace chrome