// Copyright (c) 2006-2008 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/renderer/localized_error.h"

#include "app/l10n_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/values.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
#include "net/base/net_errors.h"
#include "third_party/WebKit/WebKit/chromium/public/WebURLError.h"
#include "webkit/glue/webkit_glue.h"

using WebKit::WebURLError;

namespace {

static const char* kRedirectLoopLearnMoreUrl =
    "http://www.google.com/support/chrome/bin/answer.py?answer=95626";

enum NAV_SUGGESTIONS {
  SUGGEST_NONE     = 0,
  SUGGEST_RELOAD   = 1 << 0,
  SUGGEST_HOSTNAME = 1 << 1,
  SUGGEST_LEARNMORE = 1 << 2,
};

struct WebErrorNetErrorMap {
  const int error_code;
  const unsigned int title_resource_id;
  const unsigned int heading_resource_id;
  const unsigned int summary_resource_id;
  const unsigned int details_resource_id;
  const int suggestions;  // Bitmap of SUGGEST_* values.
};

WebErrorNetErrorMap net_error_options[] = {
  {net::ERR_TIMED_OUT,
   IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
   IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
   IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
   IDS_ERRORPAGES_DETAILS_TIMED_OUT,
   SUGGEST_RELOAD,
  },
  {net::ERR_CONNECTION_TIMED_OUT,
   IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
   IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
   IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
   IDS_ERRORPAGES_DETAILS_TIMED_OUT,
   SUGGEST_RELOAD,
  },
  {net::ERR_CONNECTION_FAILED,
   IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
   IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
   IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
   IDS_ERRORPAGES_DETAILS_CONNECT_FAILED,
   SUGGEST_RELOAD,
  },
  {net::ERR_NAME_NOT_RESOLVED,
   IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
   IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
   IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
   IDS_ERRORPAGES_DETAILS_NAME_NOT_RESOLVED,
   SUGGEST_RELOAD,
  },
  {net::ERR_INTERNET_DISCONNECTED,
   IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
   IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
   IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
   IDS_ERRORPAGES_DETAILS_DISCONNECTED,
   SUGGEST_RELOAD,
  },
  {net::ERR_FILE_NOT_FOUND,
   IDS_ERRORPAGES_TITLE_NOT_FOUND,
   IDS_ERRORPAGES_HEADING_NOT_FOUND,
   IDS_ERRORPAGES_SUMMARY_NOT_FOUND,
   IDS_ERRORPAGES_DETAILS_FILE_NOT_FOUND,
   SUGGEST_NONE,
  },
  {net::ERR_TOO_MANY_REDIRECTS,
   IDS_ERRORPAGES_TITLE_LOAD_FAILED,
   IDS_ERRORPAGES_HEADING_TOO_MANY_REDIRECTS,
   IDS_ERRORPAGES_SUMMARY_TOO_MANY_REDIRECTS,
   IDS_ERRORPAGES_DETAILS_TOO_MANY_REDIRECTS,
   SUGGEST_RELOAD | SUGGEST_LEARNMORE,
  },
};

bool LocaleIsRTL() {
#if defined(TOOLKIT_GTK)
  // l10n_util::GetTextDirection uses the GTK text direction, which doesn't work
  // within the renderer sandbox.
  return l10n_util::GetICUTextDirection() == l10n_util::RIGHT_TO_LEFT;
#else
  return l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT;
#endif
}

}  // namespace

void GetLocalizedErrorValues(const WebURLError& error,
                             DictionaryValue* error_strings) {
  bool rtl = LocaleIsRTL();
  error_strings->SetString(L"textdirection", rtl ? L"rtl" : L"ltr");

  // Grab strings that are applicable to all error pages
  error_strings->SetString(L"detailsLink",
    l10n_util::GetString(IDS_ERRORPAGES_DETAILS_LINK));
  error_strings->SetString(L"detailsHeading",
    l10n_util::GetString(IDS_ERRORPAGES_DETAILS_HEADING));

  // Grab the strings and settings that depend on the error type.  Init
  // options with default values.
  WebErrorNetErrorMap options = {
    0,
    IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
    IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
    IDS_ERRORPAGES_SUMMARY_NOT_AVAILABLE,
    IDS_ERRORPAGES_DETAILS_UNKNOWN,
    SUGGEST_NONE,
  };
  int error_code = error.reason;
  for (size_t i = 0; i < arraysize(net_error_options); ++i) {
    if (net_error_options[i].error_code == error_code) {
      memcpy(&options, &net_error_options[i], sizeof(WebErrorNetErrorMap));
      break;
    }
  }

  std::wstring suggestions_heading;
  if (options.suggestions != SUGGEST_NONE) {
    suggestions_heading =
        l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_HEADING);
  }
  error_strings->SetString(L"suggestionsHeading", suggestions_heading);

  std::wstring failed_url(
      ASCIIToWide(std::string(error.unreachableURL.spec())));
  // URLs are always LTR.
  if (rtl)
    l10n_util::WrapStringWithLTRFormatting(&failed_url);
  error_strings->SetString(L"title",
                           l10n_util::GetStringF(options.title_resource_id,
                                                 failed_url));
  error_strings->SetString(L"heading",
                           l10n_util::GetString(options.heading_resource_id));

  DictionaryValue* summary = new DictionaryValue;
  summary->SetString(L"msg",
      l10n_util::GetString(options.summary_resource_id));
  // TODO(tc): we want the unicode url here since it's being displayed
  summary->SetString(L"failedUrl", failed_url);
  error_strings->Set(L"summary", summary);

  // Error codes are expected to be negative
  DCHECK(error_code < 0);
  std::wstring details = l10n_util::GetString(options.details_resource_id);
  error_strings->SetString(L"details",
      l10n_util::GetStringF(IDS_ERRORPAGES_DETAILS_TEMPLATE,
                            IntToWString(-error_code),
                            ASCIIToWide(net::ErrorToString(error_code)),
                            details));

  if (options.suggestions & SUGGEST_RELOAD) {
    DictionaryValue* suggest_reload = new DictionaryValue;
    suggest_reload->SetString(L"msg",
        l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_RELOAD));
    suggest_reload->SetString(L"reloadUrl", failed_url);
    error_strings->Set(L"suggestionsReload", suggest_reload);
  }

  if (options.suggestions & SUGGEST_HOSTNAME) {
    // Only show the "Go to hostname" suggestion if the failed_url has a path.
    const GURL& failed_url = error.unreachableURL;
    if (std::string() == failed_url.path()) {
      DictionaryValue* suggest_home_page = new DictionaryValue;
      suggest_home_page->SetString(L"suggestionsHomepageMsg",
          l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_HOMEPAGE));
      std::wstring homepage(ASCIIToWide(failed_url.GetWithEmptyPath().spec()));
      // URLs are always LTR.
      if (rtl)
        l10n_util::WrapStringWithLTRFormatting(&homepage);
      suggest_home_page->SetString(L"homePage", homepage);
      // TODO(tc): we actually want the unicode hostname
      suggest_home_page->SetString(L"hostName",
          ASCIIToWide(failed_url.host()));
      error_strings->Set(L"suggestionsHomepage", suggest_home_page);
    }
  }

  if (options.suggestions & SUGGEST_LEARNMORE) {
    GURL learn_more_url;
    switch (options.error_code) {
      case net::ERR_TOO_MANY_REDIRECTS:
        learn_more_url = GURL(kRedirectLoopLearnMoreUrl);
        break;
      default:
        break;
    }

    if (learn_more_url.is_valid()) {
      // Add the language parameter to the URL.
      std::string query = learn_more_url.query() + "&hl=" +
          WideToASCII(webkit_glue::GetWebKitLocale());
      GURL::Replacements repl;
      repl.SetQueryStr(query);
      learn_more_url = learn_more_url.ReplaceComponents(repl);

      DictionaryValue* suggest_learn_more = new DictionaryValue;
      suggest_learn_more->SetString(L"msg",
          l10n_util::GetString(IDS_ERRORPAGES_SUGGESTION_LEARNMORE));
      suggest_learn_more->SetString(L"learnMoreUrl",
                                    ASCIIToWide(learn_more_url.spec()));
      error_strings->Set(L"suggestionsLearnMore", suggest_learn_more);
    }
  }
}

void GetFormRepostErrorValues(const GURL& display_url,
                              DictionaryValue* error_strings) {
  bool rtl = LocaleIsRTL();
  error_strings->SetString(L"textdirection", rtl ? L"rtl" : L"ltr");

  std::wstring failed_url(ASCIIToWide(display_url.spec()));
  // URLs are always LTR.
  if (rtl)
    l10n_util::WrapStringWithLTRFormatting(&failed_url);
  error_strings->SetString(
      L"title", l10n_util::GetStringF(IDS_ERRORPAGES_TITLE_NOT_AVAILABLE,
                                      failed_url.c_str()));
  error_strings->SetString(L"heading",
                           l10n_util::GetString(IDS_HTTP_POST_WARNING_TITLE));
  error_strings->SetString(L"suggestionsHeading", L"");
  DictionaryValue* summary = new DictionaryValue;
  summary->SetString(L"msg",
                     l10n_util::GetString(IDS_ERRORPAGES_HTTP_POST_WARNING));
  error_strings->Set(L"summary", summary);
}