// Copyright (c) 2010 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/autofill/autofill_dialog.h"

#include <gtk/gtk.h>

#include <algorithm>
#include <string>
#include <vector>

#include "app/gtk_signal.h"
#include "app/l10n_util.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/autofill/autofill_manager.h"
#include "chrome/browser/autofill/autofill_profile.h"
#include "chrome/browser/autofill/credit_card.h"
#include "chrome/browser/autofill/form_group.h"
#include "chrome/browser/autofill/personal_data_manager.h"
#include "chrome/browser/autofill/phone_number.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/gtk_chrome_link_button.h"
#include "chrome/browser/gtk/gtk_tree.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/metrics/user_metrics.h"
#include "chrome/browser/prefs/pref_member.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_details.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/pref_names.h"
#include "gfx/gtk_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"

// Shows the editor for adding/editing an AutoFillProfile. If
// |auto_fill_profile| is NULL, a new AutoFillProfile should be created.
void ShowAutoFillProfileEditor(gfx::NativeView parent,
                               AutoFillDialogObserver* observer,
                               Profile* profile,
                               AutoFillProfile* auto_fill_profile);

// Shows the editor for adding/editing a CreditCard. If |credit_card| is NULL, a
// new CreditCard should be created.
void ShowAutoFillCreditCardEditor(gfx::NativeView parent,
                                  AutoFillDialogObserver* observer,
                                  Profile* profile,
                                  CreditCard* credit_card);

namespace {

// The resource id for the 'About Autofill' link button.
const gint kAutoFillDialogAboutLink = 1;

////////////////////////////////////////////////////////////////////////////////
// AutoFillDialog
//
// The contents of the AutoFill dialog.  This dialog allows users to add, edit
// and remove AutoFill profiles.
class AutoFillDialog : public PersonalDataManager::Observer,
                       public NotificationObserver {
 public:
  // Identifiers for columns in the store.
  enum Column {
    COL_TITLE = 0,
    COL_IS_HEADER,
    COL_IS_SEPARATOR,  // Identifies an empty row used to reserve visual space.
    COL_WEIGHT,
    COL_WEIGHT_SET,
    COL_COUNT
  };

  // Used to identify the selection. See GetSelectionType.
  enum SelectionType {
    // Nothing is selected.
    SELECTION_EMPTY  = 0,

    // At least one header/separator row is selected.
    SELECTION_HEADER = 1 << 0,

    // At least one non-header/separator row is selected.
    SELECTION_SINGLE = 1 << 1,

    // Multiple non-header/separator rows are selected.
    SELECTION_MULTI  = 1 << 2,
  };

  AutoFillDialog(Profile* profile, AutoFillDialogObserver* observer);
  ~AutoFillDialog();

  // PersonalDataManager::Observer implementation:
  void OnPersonalDataLoaded();
  void OnPersonalDataChanged();

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

  // Shows the AutoFill dialog.
  void Show();

 private:
  // 'destroy' signal handler.  Calls DeleteSoon on the global singleton dialog
  // object.
  CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnDestroy);

  // 'response' signal handler.  Notifies the AutoFillDialogObserver that new
  // data is available if the response is GTK_RESPONSE_APPLY or GTK_RESPONSE_OK.
  // We close the dialog if the response is GTK_RESPONSE_OK or
  // GTK_RESPONSE_CANCEL.
  CHROMEG_CALLBACK_1(AutoFillDialog, void, OnResponse, GtkDialog*, gint);

  CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAutoFillCheckToggled);
  CHROMEG_CALLBACK_2(AutoFillDialog, void, OnRowActivated, GtkTreeView*,
                     GtkTreePath*, GtkTreeViewColumn*);
  CHROMEG_CALLBACK_0(AutoFillDialog, void, OnSelectionChanged,
                     GtkTreeSelection*);
  CHROMEG_CALLBACK_1(AutoFillDialog, gboolean, OnCheckRowIsSeparator,
                     GtkTreeModel*, GtkTreeIter*);
  CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAddAddress);
  CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnAddCreditCard);
  CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnEdit);
  CHROMEGTK_CALLBACK_0(AutoFillDialog, void, OnRemove);
  CHROMEG_CALLBACK_3(AutoFillDialog, gboolean, OnSelectionFilter,
                     GtkTreeSelection*, GtkTreeModel*, GtkTreePath*, gboolean);

  // Opens the 'Learn more' link in a new foreground tab.
  void OnLinkActivated();

  // Loads AutoFill profiles and credit cards using the PersonalDataManager.
  void LoadAutoFillData();

  // Creates the dialog UI widgets.
  void InitializeWidgets();

  // Updates the state of the various widgets dependant upon the state of the
  // selection, loaded state and whether AutoFill is enabled.
  void UpdateWidgetState();

  // Returns a bitmask of the selection types.
  int GetSelectionType();

  void AddAddressToTree(const AutoFillProfile& profile, GtkTreeIter* iter);

  void AddCreditCardToTree(const CreditCard& credit_card, GtkTreeIter* iter);

  // Returns the set of selected profiles and cards. The values placed in
  // the specified vectors are owned by PersonalDataManager.
  void GetSelectedEntries(std::vector<AutoFillProfile*>* profiles,
                          std::vector<CreditCard*>* cards);

  Profile* profile_;

  // Our observer.  May not be NULL.
  AutoFillDialogObserver* observer_;

  // The personal data manager, used to load AutoFill profiles and credit cards.
  // Unowned pointer, may not be NULL.
  PersonalDataManager* personal_data_;

  // Number of profiles we're displaying.
  int profile_count_;

  // The AutoFill dialog.
  GtkWidget* dialog_;

  BooleanPrefMember enable_form_autofill_;

  GtkWidget* form_autofill_enable_check_;

  // Displays the addresses then credit cards.
  GtkListStore* list_store_;

  // Displays the list_store_.
  GtkWidget* tree_;

  GtkWidget* add_address_button_;
  GtkWidget* add_credit_card_button_;
  GtkWidget* edit_button_;
  GtkWidget* remove_button_;

  DISALLOW_COPY_AND_ASSIGN(AutoFillDialog);
};

// The singleton AutoFill dialog object.
static AutoFillDialog* dialog = NULL;

AutoFillDialog::AutoFillDialog(Profile* profile,
                               AutoFillDialogObserver* observer)
    : profile_(profile),
      observer_(observer),
      personal_data_(profile->GetPersonalDataManager()),
      profile_count_(0) {
  DCHECK(observer_);
  DCHECK(personal_data_);

  enable_form_autofill_.Init(prefs::kAutoFillEnabled, profile->GetPrefs(),
                             this);

  personal_data_->SetObserver(this);

  InitializeWidgets();
  LoadAutoFillData();

  gtk_util::ShowDialogWithLocalizedSize(dialog_,
                                        IDS_AUTOFILL_DIALOG_WIDTH_CHARS,
                                        IDS_AUTOFILL_DIALOG_HEIGHT_LINES,
                                        true);
}

AutoFillDialog::~AutoFillDialog() {
  // Removes observer if we are observing Profile load. Does nothing otherwise.
  personal_data_->RemoveObserver(this);
}

/////////////////////////////////////////////////////////////////////////////
// PersonalDataManager::Observer implementation:
void  AutoFillDialog::OnPersonalDataLoaded() {
  LoadAutoFillData();
}

void AutoFillDialog::OnPersonalDataChanged() {
  LoadAutoFillData();
}

void AutoFillDialog::Observe(NotificationType type,
                             const NotificationSource& source,
                             const NotificationDetails& details) {
  DCHECK_EQ(NotificationType::PREF_CHANGED, type.value);
  const std::string* pref_name = Details<std::string>(details).ptr();
  if (!pref_name || *pref_name == prefs::kAutoFillEnabled) {
    gtk_toggle_button_set_active(
          GTK_TOGGLE_BUTTON(form_autofill_enable_check_),
          enable_form_autofill_.GetValue() ? TRUE : FALSE);
    UpdateWidgetState();
  }
}

void AutoFillDialog::Show() {
  gtk_util::PresentWindow(dialog_, gtk_get_current_event_time());
}

void AutoFillDialog::OnDestroy(GtkWidget* widget) {
  dialog = NULL;
  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void AutoFillDialog::OnResponse(GtkDialog* dialog, gint response_id) {
  if (response_id == GTK_RESPONSE_OK ||
      response_id == GTK_RESPONSE_CANCEL ||
      response_id == GTK_RESPONSE_DELETE_EVENT) {
    gtk_widget_destroy(GTK_WIDGET(dialog));
  }

  if (response_id == kAutoFillDialogAboutLink)
    OnLinkActivated();
}

void AutoFillDialog::OnAutoFillCheckToggled(GtkWidget* widget) {
  bool enabled = gtk_toggle_button_get_active(
      GTK_TOGGLE_BUTTON(form_autofill_enable_check_));
  if (enabled) {
    UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Enable"),
                              profile_);
  } else {
    UserMetrics::RecordAction(UserMetricsAction("Options_FormAutofill_Disable"),
                              profile_);
  }
  enable_form_autofill_.SetValueIfNotManaged(enabled);
  profile_->GetPrefs()->ScheduleSavePersistentPrefs();
  UpdateWidgetState();
}

void AutoFillDialog::OnRowActivated(GtkTreeView* tree_view,
                                    GtkTreePath* path,
                                    GtkTreeViewColumn* column) {
  if (GetSelectionType() == SELECTION_SINGLE)
    OnEdit(NULL);
}

void AutoFillDialog::OnSelectionChanged(GtkTreeSelection* selection) {
  UpdateWidgetState();
}

gboolean AutoFillDialog::OnCheckRowIsSeparator(GtkTreeModel* model,
                                               GtkTreeIter* iter) {
  gboolean is_separator;
  gtk_tree_model_get(model, iter, COL_IS_SEPARATOR, &is_separator, -1);
  return is_separator;
}

void AutoFillDialog::OnAddAddress(GtkWidget* widget) {
  ShowAutoFillProfileEditor(NULL, observer_, profile_, NULL);
}

void AutoFillDialog::OnAddCreditCard(GtkWidget* widget) {
  ShowAutoFillCreditCardEditor(NULL, observer_, profile_, NULL);
}

void AutoFillDialog::OnEdit(GtkWidget* widget) {
  DCHECK_EQ(SELECTION_SINGLE, GetSelectionType());

  std::vector<AutoFillProfile*> profiles;
  std::vector<CreditCard*> cards;

  GetSelectedEntries(&profiles, &cards);

  if (profiles.size() == 1)
    ShowAutoFillProfileEditor(dialog_, observer_, profile_, profiles[0]);
  else if (cards.size() == 1)
    ShowAutoFillCreditCardEditor(dialog_, observer_, profile_, cards[0]);
}

void AutoFillDialog::OnRemove(GtkWidget* widget) {
  PersonalDataManager* data_manager = profile_->GetPersonalDataManager();
  std::vector<AutoFillProfile*> selected_profiles;
  std::vector<CreditCard*> selected_cards;

  GetSelectedEntries(&selected_profiles, &selected_cards);

  std::vector<AutoFillProfile> profiles;
  for (std::vector<AutoFillProfile*>::const_iterator i =
           data_manager->profiles().begin();
       i != data_manager->profiles().end(); ++i) {
    if (std::find(selected_profiles.begin(), selected_profiles.end(), *i) ==
        selected_profiles.end()) {
      profiles.push_back(**i);
    }
  }

  std::vector<CreditCard> cards;
  for (std::vector<CreditCard*>::const_iterator i =
           data_manager->credit_cards().begin();
       i != data_manager->credit_cards().end(); ++i) {
    if (std::find(selected_cards.begin(), selected_cards.end(), *i) ==
        selected_cards.end()) {
      cards.push_back(**i);
    }
  }

  observer_->OnAutoFillDialogApply(&profiles, &cards);
}

gboolean AutoFillDialog::OnSelectionFilter(GtkTreeSelection* selection,
                                           GtkTreeModel* model,
                                           GtkTreePath* path,
                                           gboolean path_currently_selected) {
  GtkTreeIter iter;
  if (!gtk_tree_model_get_iter(model, &iter, path)) {
    NOTREACHED();
    return TRUE;
  }
  gboolean is_header;
  gboolean is_separator;
  gtk_tree_model_get(model, &iter, COL_IS_HEADER, &is_header,
                     COL_IS_SEPARATOR, &is_separator, -1);
  return !is_header && !is_separator;
}

void AutoFillDialog::OnLinkActivated() {
  Browser* browser = BrowserList::GetLastActive();
  if (!browser || !browser->GetSelectedTabContents())
    browser = Browser::Create(profile_);
  browser->OpenAutoFillHelpTabAndActivate();
}

void AutoFillDialog::LoadAutoFillData() {
  if (!personal_data_->IsDataLoaded()) {
    UpdateWidgetState();
    return;
  }

  // Rebuild the underlying store.
  gtk_list_store_clear(list_store_);

  GtkTreeIter iter;
  // Address title.
  gtk_list_store_append(list_store_, &iter);
  gtk_list_store_set(
      list_store_, &iter,
      COL_WEIGHT, PANGO_WEIGHT_BOLD,
      COL_WEIGHT_SET, TRUE,
      COL_TITLE,
          l10n_util::GetStringUTF8(IDS_AUTOFILL_ADDRESSES_GROUP_NAME).c_str(),
      COL_IS_HEADER, TRUE,
      -1);
  // Address separator.
  gtk_list_store_append(list_store_, &iter);
  gtk_list_store_set(
      list_store_, &iter,
      COL_IS_SEPARATOR, TRUE,
      -1);

  // The addresses.
  profile_count_ = 0;
  for (std::vector<AutoFillProfile*>::const_iterator i =
           personal_data_->profiles().begin();
       i != personal_data_->profiles().end(); ++i) {
    AddAddressToTree(*(*i), &iter);
    profile_count_++;
  }

  // Blank row between addresses and credit cards.
  gtk_list_store_append(list_store_, &iter);
  gtk_list_store_set(
      list_store_, &iter,
      COL_IS_HEADER, TRUE,
      -1);

  // Credit card title.
  gtk_list_store_append(list_store_, &iter);
  gtk_list_store_set(
      list_store_, &iter,
      COL_WEIGHT, PANGO_WEIGHT_BOLD,
      COL_WEIGHT_SET, TRUE,
      COL_TITLE,
          l10n_util::GetStringUTF8(IDS_AUTOFILL_CREDITCARDS_GROUP_NAME).c_str(),
      COL_IS_HEADER, TRUE,
      -1);
  // Credit card separator.
  gtk_list_store_append(list_store_, &iter);
  gtk_list_store_set(
      list_store_, &iter,
      COL_IS_SEPARATOR, TRUE,
      -1);

  // The credit cards.
  for (std::vector<CreditCard*>::const_iterator i =
           personal_data_->credit_cards().begin();
       i != personal_data_->credit_cards().end(); ++i) {
    AddCreditCardToTree(*(*i), &iter);
  }

  UpdateWidgetState();
}

void AutoFillDialog::InitializeWidgets() {
  dialog_ = gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_AUTOFILL_OPTIONS_TITLE).c_str(),
      // AutoFill dialog is shared between all browser windows.
      NULL,
      // Non-modal.
      GTK_DIALOG_NO_SEPARATOR,
      GTK_STOCK_OK,
      GTK_RESPONSE_OK,
      NULL);

  GtkBox* vbox = GTK_BOX(GTK_DIALOG(dialog_)->vbox);
  gtk_box_set_spacing(vbox, gtk_util::kControlSpacing);
  g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
  g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroyThunk), this);

  form_autofill_enable_check_ = gtk_check_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_OPTIONS_AUTOFILL_ENABLE).c_str());
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(form_autofill_enable_check_),
                               enable_form_autofill_.GetValue());
  g_signal_connect(G_OBJECT(form_autofill_enable_check_), "toggled",
                   G_CALLBACK(OnAutoFillCheckToggledThunk), this);
  gtk_box_pack_start(vbox, form_autofill_enable_check_, FALSE, FALSE, 0);

  // Allow the contents to be scrolled.
  GtkWidget* scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
                                      GTK_SHADOW_ETCHED_IN);

  list_store_ = gtk_list_store_new(COL_COUNT,
                                   G_TYPE_STRING,
                                   G_TYPE_BOOLEAN,
                                   G_TYPE_BOOLEAN,
                                   G_TYPE_INT,
                                   G_TYPE_BOOLEAN);
  tree_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store_));
  g_object_unref(list_store_);
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_), FALSE);
  gtk_tree_view_set_row_separator_func(GTK_TREE_VIEW(tree_),
                                       OnCheckRowIsSeparatorThunk, this, NULL);
  g_signal_connect(tree_, "row-activated", G_CALLBACK(OnRowActivatedThunk),
                   this);
  gtk_container_add(GTK_CONTAINER(scrolled_window), tree_);

  GtkWidget* h_box1 = gtk_hbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_box_pack_start(vbox, h_box1, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(h_box1), scrolled_window, TRUE, TRUE, 0);

  GtkWidget* controls_box = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_box_pack_start(GTK_BOX(h_box1), controls_box, FALSE, FALSE, 0);

  add_address_button_ = gtk_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_AUTOFILL_ADD_ADDRESS_BUTTON).c_str());
  g_signal_connect(add_address_button_, "clicked",
                   G_CALLBACK(OnAddAddressThunk), this);
  gtk_box_pack_start(GTK_BOX(controls_box), add_address_button_, FALSE, FALSE,
                     0);

  add_credit_card_button_ = gtk_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_AUTOFILL_ADD_CREDITCARD_BUTTON).c_str());
  g_signal_connect(add_credit_card_button_, "clicked",
                   G_CALLBACK(OnAddCreditCardThunk), this);
  gtk_box_pack_start(GTK_BOX(controls_box), add_credit_card_button_, FALSE,
                     FALSE, 0);

  edit_button_ = gtk_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_AUTOFILL_EDIT_BUTTON).c_str());
  g_signal_connect(edit_button_, "clicked", G_CALLBACK(OnEditThunk), this);
  gtk_box_pack_start(GTK_BOX(controls_box), edit_button_, FALSE, FALSE, 0);

  remove_button_ = gtk_button_new_with_label(
      l10n_util::GetStringUTF8(IDS_AUTOFILL_DELETE_BUTTON).c_str());
  g_signal_connect(remove_button_, "clicked", G_CALLBACK(OnRemoveThunk), this);
  gtk_box_pack_start(GTK_BOX(controls_box), remove_button_, FALSE, FALSE, 0);

  GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes(
      "",
      gtk_cell_renderer_text_new(),
      "text", COL_TITLE,
      "weight", COL_WEIGHT,
      "weight-set", COL_WEIGHT_SET,
      NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), column);

  GtkTreeSelection* selection =
      gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_));
  gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
  gtk_tree_selection_set_select_function(selection, OnSelectionFilterThunk,
                                         this, NULL);
  g_signal_connect(selection, "changed", G_CALLBACK(OnSelectionChangedThunk),
                   this);

  GtkWidget* link = gtk_chrome_link_button_new(
      l10n_util::GetStringUTF8(IDS_AUTOFILL_HELP_LABEL).c_str());
  gtk_dialog_add_action_widget(GTK_DIALOG(dialog_), link,
                               kAutoFillDialogAboutLink);

  // Setting the link widget to secondary positions the button on the left side
  // of the action area (vice versa for RTL layout).
  gtk_button_box_set_child_secondary(
      GTK_BUTTON_BOX(GTK_DIALOG(dialog_)->action_area), link, TRUE);
}

void AutoFillDialog::UpdateWidgetState() {
  gtk_widget_set_sensitive(form_autofill_enable_check_,
                           !enable_form_autofill_.IsManaged());
  if (!personal_data_->IsDataLoaded() || !enable_form_autofill_.GetValue()) {
    gtk_widget_set_sensitive(add_address_button_, FALSE);
    gtk_widget_set_sensitive(add_credit_card_button_, FALSE);
    gtk_widget_set_sensitive(edit_button_, FALSE);
    gtk_widget_set_sensitive(remove_button_, FALSE);
    gtk_widget_set_sensitive(tree_, FALSE);
  } else {
    gtk_widget_set_sensitive(add_address_button_, TRUE);
    gtk_widget_set_sensitive(add_credit_card_button_, TRUE);
    int selection_type = GetSelectionType();
    gtk_widget_set_sensitive(edit_button_, selection_type == SELECTION_SINGLE);
    // Enable the remove button if at least one non-header row is selected.
    gtk_widget_set_sensitive(remove_button_,
                             (selection_type & SELECTION_SINGLE) != 0);
    gtk_widget_set_sensitive(tree_, TRUE);
  }
}

static void RowIteratorFunction(GtkTreeModel* model,
                                GtkTreePath* path,
                                GtkTreeIter* iter,
                                gpointer data) {
  int* type = reinterpret_cast<int*>(data);
  bool is_header = false;
  GValue value = { 0 };
  gtk_tree_model_get_value(model, iter, AutoFillDialog::COL_IS_HEADER, &value);
  is_header = g_value_get_boolean(&value);
  g_value_unset(&value);

  if (!is_header) {
    // Is it a separator?
    GValue value = { 0 };
    gtk_tree_model_get_value(model, iter, AutoFillDialog::COL_IS_SEPARATOR,
                             &value);
    is_header = g_value_get_boolean(&value);
    g_value_unset(&value);
  }

  if (is_header) {
    *type |= AutoFillDialog::SELECTION_HEADER;
  } else {
    if ((*type & AutoFillDialog::SELECTION_SINGLE) == 0)
      *type |= AutoFillDialog::SELECTION_SINGLE;
    else
      *type |= AutoFillDialog::SELECTION_MULTI;
  }
}

int AutoFillDialog::GetSelectionType() {
  int state = SELECTION_EMPTY;
  gtk_tree_selection_selected_foreach(
      gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)), RowIteratorFunction,
      &state);
  return state;
}

void AutoFillDialog::AddAddressToTree(const AutoFillProfile& profile,
                                      GtkTreeIter* iter) {
  gtk_list_store_append(list_store_, iter);
  gtk_list_store_set(
      list_store_, iter,
      COL_WEIGHT, PANGO_WEIGHT_NORMAL,
      COL_WEIGHT_SET, TRUE,
      COL_TITLE, UTF16ToUTF8(profile.Label()).c_str(),
      -1);
}

void AutoFillDialog::AddCreditCardToTree(const CreditCard& credit_card,
                                         GtkTreeIter* iter) {
  gtk_list_store_append(list_store_, iter);
  gtk_list_store_set(
      list_store_, iter,
      COL_WEIGHT, PANGO_WEIGHT_NORMAL,
      COL_WEIGHT_SET, TRUE,
      COL_TITLE, UTF16ToUTF8(credit_card.PreviewSummary()).c_str(),
      -1);
}

void AutoFillDialog::GetSelectedEntries(
    std::vector<AutoFillProfile*>* profiles,
    std::vector<CreditCard*>* cards) {
  std::set<int> selection;
  gtk_tree::GetSelectedIndices(
      gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)), &selection);

  for (std::set<int>::const_iterator i = selection.begin();
       i != selection.end(); ++i) {
    // 2 is the number of header rows.
    int index = *i - 2;
    if (index >= 0 &&
        index < static_cast<int>(personal_data_->profiles().size())) {
      profiles->push_back(personal_data_->profiles()[index]);
      continue;
    }

    // Empty row, header and separator are next.
    index -= profile_count_ + 3;
    if (index >= 0 && index <
        static_cast<int>(personal_data_->credit_cards().size())) {
      cards->push_back(personal_data_->credit_cards()[index]);
    }
  }
}

}  // namespace

///////////////////////////////////////////////////////////////////////////////
// Factory/finder method:

void ShowAutoFillDialog(gfx::NativeView parent,
                        AutoFillDialogObserver* observer,
                        Profile* profile) {
  DCHECK(profile);

  if (!dialog)
    dialog = new AutoFillDialog(profile, observer);
  dialog->Show();
}