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

#include "chrome/browser/ui/views/default_search_view.h"

#include <string>

#include "base/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_prepopulate_data.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "ui/base/message_box_flags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
#include "views/controls/button/native_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/layout/grid_layout.h"
#include "views/layout/layout_constants.h"
#include "views/window/dialog_client_view.h"
#include "views/window/window.h"

namespace {

// Returns a short name and logo resource id for the given host.
void GetShortNameAndLogoId(PrefService* prefs,
                           const TemplateURL* turl,
                           std::wstring* short_name,
                           int* logo_id) {
  DCHECK(prefs);
  DCHECK(turl);
  DCHECK(short_name);
  DCHECK(logo_id);

  GURL url = TemplateURLModel::GenerateSearchURL(turl);
  scoped_ptr<TemplateURL> built_in_data(
      TemplateURLPrepopulateData::GetEngineForOrigin(prefs, url));

  // Use the built-in information to generate the short name (to ensure
  // that we don't use a name given by the search engine to itself which
  // in the worst case could be misleading).
  if (built_in_data.get()) {
    *short_name = built_in_data->short_name();
    *logo_id = built_in_data->logo_id();
  } else {
    *short_name = UTF8ToWide(url.host()).c_str();
    *logo_id = kNoSearchEngineLogo;
  }
}

views::Label* CreateProviderLabel(int message_id) {
  views::Label* choice_label =
      new views::Label(UTF16ToWide(l10n_util::GetStringUTF16(message_id)));
  choice_label->SetColor(SK_ColorBLACK);
  choice_label->SetFont(
      choice_label->font().DeriveFont(1, gfx::Font::NORMAL));
  return choice_label;
}

views::View* CreateProviderLogo(
    int logo_id,
    const std::wstring& short_name) {
  views::View* logo_view = NULL;

  // The width for the "logo" element when text is displayed.
  const int kTextLogoWidth = 132;

  bool use_images = false;
#if defined(GOOGLE_CHROME_BUILD)
  use_images = true;
#endif

  if (use_images && logo_id != kNoSearchEngineLogo) {
    views::ImageView* logo_image = new views::ImageView();
    SkBitmap* logo_bmp =
        ResourceBundle::GetSharedInstance().GetBitmapNamed(logo_id);
    logo_image->SetImage(logo_bmp);
    logo_image->SetTooltipText(short_name);
    logo_view = logo_image;
  } else {
    // No logo -- show a text label.
    views::Label* logo_label = new views::Label(short_name);
    logo_label->SetColor(SK_ColorDKGRAY);
    logo_label->SetFont(logo_label->font().DeriveFont(3, gfx::Font::BOLD));
    logo_label->SetHorizontalAlignment(views::Label::ALIGN_CENTER);
    // Tooltip text provides accessibility for low-vision users.
    logo_label->SetTooltipText(short_name);
    logo_view = logo_label;
  }

  return logo_view;
}
views::NativeButton* CreateProviderChoiceButton(
    views::ButtonListener* listener,
    int message_id,
    const std::wstring& short_name) {
  return new views::NativeButton(listener, UTF16ToWide(
      l10n_util::GetStringFUTF16(message_id, WideToUTF16(short_name))));
}

}  // namespace

// static
void DefaultSearchView::Show(TabContents* tab_contents,
                             TemplateURL* default_url,
                             TemplateURLModel* template_url_model) {
  scoped_ptr<TemplateURL> template_url(default_url);
  if (!template_url_model->CanMakeDefault(default_url) ||
      default_url->url()->GetHost().empty())
    return;

  // When the window closes, it will delete itself.
  new DefaultSearchView(tab_contents, template_url.release(),
                        template_url_model);
}

DefaultSearchView::~DefaultSearchView() {
}

void DefaultSearchView::OnPaint(gfx::Canvas* canvas) {
  // Fill in behind the background image with the standard gray toolbar color.
  canvas->FillRectInt(SkColorSetRGB(237, 238, 237), 0, 0, width(),
                      background_image_->height());
  // The rest of the dialog background should be white.
  DCHECK(height() > background_image_->height());
  canvas->FillRectInt(SK_ColorWHITE, 0, background_image_->height(), width(),
                      height() - background_image_->height());
}

void DefaultSearchView::ButtonPressed(views::Button* sender,
                                      const views::Event& event) {
  views::DialogClientView* client = GetDialogClientView();
  if (sender == proposed_provider_button_)
    client->AcceptWindow();
  else
    client->CancelWindow();
}

std::wstring DefaultSearchView::GetWindowTitle() const {
  return UTF16ToWide(l10n_util::GetStringUTF16(IDS_DEFAULT_SEARCH_TITLE));
}

views::View* DefaultSearchView::GetInitiallyFocusedView() {
  return default_provider_button_;
}

views::View* DefaultSearchView::GetContentsView() {
  return this;
}

int DefaultSearchView::GetDialogButtons() const {
  return ui::MessageBoxFlags::DIALOGBUTTON_NONE;
}

bool DefaultSearchView::Accept() {
  // Check this again in case the default became managed while this dialog was
  // displayed.
  TemplateURL* set_as_default = proposed_turl_.get();
  if (!template_url_model_->CanMakeDefault(set_as_default))
    return true;

  template_url_model_->Add(proposed_turl_.release());
  template_url_model_->SetDefaultSearchProvider(set_as_default);
  return true;
}

DefaultSearchView::DefaultSearchView(TabContents* tab_contents,
                                     TemplateURL* proposed_default_turl,
                                     TemplateURLModel* template_url_model)
    : background_image_(NULL),
      default_provider_button_(NULL),
      proposed_provider_button_(NULL),
      proposed_turl_(proposed_default_turl),
      template_url_model_(template_url_model) {
  PrefService* prefs = tab_contents->profile()->GetPrefs();
  SetupControls(prefs);

  // Show the dialog.
  tab_contents->CreateConstrainedDialog(this);
}

void DefaultSearchView::SetupControls(PrefService* prefs) {
  using views::ColumnSet;
  using views::GridLayout;
  using views::ImageView;
  using views::Label;

  // Column set id's.
  const int kWholeDialogViewSetId = 0;
  const int kPaddedWholeDialogViewSetId = 1;
  const int kChoicesViewSetId = 2;

  // Set up the information for the proposed default.
  std::wstring proposed_short_name;
  int proposed_logo_id = kNoSearchEngineLogo;
  GetShortNameAndLogoId(prefs,
                        proposed_turl_.get(),
                        &proposed_short_name,
                        &proposed_logo_id);
  if (proposed_logo_id != kNoSearchEngineLogo)
    proposed_turl_->set_logo_id(proposed_logo_id);


  // Set up the information for the current default.
  std::wstring default_short_name;
  int default_logo_id = kNoSearchEngineLogo;
  GetShortNameAndLogoId(prefs,
                        template_url_model_->GetDefaultSearchProvider(),
                        &default_short_name,
                        &default_logo_id);

  // Now set-up the dialog contents.
  GridLayout* layout = new views::GridLayout(this);
  layout->SetInsets(0, 0, views::kPanelVertMargin, 0);
  SetLayoutManager(layout);

  // Add a column set that spans the whole dialog.
  ColumnSet* whole_dialog_column_set =
      layout->AddColumnSet(kWholeDialogViewSetId);
  whole_dialog_column_set->AddColumn(GridLayout::LEADING, GridLayout::LEADING,
                                     1, GridLayout::FIXED,
                                     views::Window::GetLocalizedContentsWidth(
                                         IDS_DEFAULT_SEARCH_WIDTH_CHARS),
                                     0);

  // Add a column set that spans the whole dialog but obeying padding.
  ColumnSet* padded_whole_dialog_column_set =
      layout->AddColumnSet(kPaddedWholeDialogViewSetId);
  padded_whole_dialog_column_set->AddPaddingColumn(1, views::kPanelVertMargin);
  padded_whole_dialog_column_set->AddColumn(
      GridLayout::LEADING, GridLayout::LEADING,
      1, GridLayout::USE_PREF, 0, 0);
  padded_whole_dialog_column_set->AddPaddingColumn(1, views::kPanelVertMargin);

  // Add a column set for the search engine choices.
  ColumnSet* choices_column_set = layout->AddColumnSet(kChoicesViewSetId);
  choices_column_set->AddPaddingColumn(1, views::kPanelVertMargin);
  choices_column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER,
                                1, GridLayout::USE_PREF, 0, 0);
  choices_column_set->AddPaddingColumn(
      1, views::kRelatedControlHorizontalSpacing);
  choices_column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER,
                                1, GridLayout::USE_PREF, 0, 0);
  choices_column_set->LinkColumnSizes(0, 2, -1);
  choices_column_set->AddPaddingColumn(1, views::kPanelVertMargin);

  // Add the "search box" image.
  layout->StartRow(0, kWholeDialogViewSetId);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  background_image_ = new ImageView();
  background_image_->SetImage(rb.GetBitmapNamed(IDR_SEARCH_ENGINE_DIALOG_TOP));
  background_image_->EnableCanvasFlippingForRTLUI(true);
  ImageView::Alignment horizontal_alignment =
      base::i18n::IsRTL() ? ImageView::LEADING : ImageView::TRAILING;
  background_image_->SetHorizontalAlignment(horizontal_alignment);
  layout->AddView(background_image_);

  // Add text informing the user about the requested default change.
  layout->StartRowWithPadding(0, kPaddedWholeDialogViewSetId,
                              1, views::kLabelToControlVerticalSpacing);
  Label* summary_label = new Label(UTF16ToWide(l10n_util::GetStringFUTF16(
      IDS_DEFAULT_SEARCH_SUMMARY,
      WideToUTF16(proposed_short_name))));
  summary_label->SetColor(SK_ColorBLACK);
  summary_label->SetFont(
      summary_label->font().DeriveFont(1, gfx::Font::NORMAL));
  summary_label->SetHorizontalAlignment(Label::ALIGN_LEFT);
  layout->AddView(summary_label);

  // Add the labels for the tops of the choices.
  layout->StartRowWithPadding(0, kChoicesViewSetId,
                              0, views::kRelatedControlVerticalSpacing);
  layout->AddView(CreateProviderLabel(IDS_DEFAULT_SEARCH_LABEL_CURRENT));
  layout->AddView(CreateProviderLabel(IDS_DEFAULT_SEARCH_LABEL_PROPOSED));

  // Add the logos.
  layout->StartRowWithPadding(0, kChoicesViewSetId,
                              0, views::kRelatedControlVerticalSpacing);
  layout->AddView(CreateProviderLogo(default_logo_id, default_short_name));
  layout->AddView(CreateProviderLogo(proposed_logo_id, proposed_short_name));

  // Add the buttons.
  layout->StartRowWithPadding(0, kChoicesViewSetId,
                              0, views::kRelatedControlVerticalSpacing);
  default_provider_button_ = CreateProviderChoiceButton(
      this,
      IDS_DEFAULT_SEARCH_PROMPT_CURRENT,
      default_short_name);
  layout->AddView(default_provider_button_);
  proposed_provider_button_ = CreateProviderChoiceButton(
      this,
      IDS_DEFAULT_SEARCH_PROMPT_PROPOSED,
      proposed_short_name);
  layout->AddView(proposed_provider_button_);
}