// Copyright 2017 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 "components/autofill/core/browser/address_combobox_model.h"

#include <memory>

#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/combobox_model_observer.h"
#include "ui/gfx/text_elider.h"

namespace autofill {

namespace {
// There's one header entry to prompt the user to select an address, and a
// separator.
int kNbHeaderEntries = 2;
}  // namespace

AddressComboboxModel::AddressComboboxModel(
    const PersonalDataManager& personal_data_manager,
    const std::string& app_locale,
    const std::string& default_selected_guid)
    : app_locale_(app_locale), default_selected_guid_(default_selected_guid) {
  for (const auto* profile : personal_data_manager.GetProfilesToSuggest()) {
    profiles_cache_.push_back(std::make_unique<AutofillProfile>(*profile));
  }
  UpdateAddresses();
}

AddressComboboxModel::~AddressComboboxModel() {}

int AddressComboboxModel::GetItemCount() const {
  // When there are not addresses, a special entry is shown to prompt the user
  // to add addresses, but nothing else is shown, since there are no address to
  // select from, and no need for a separator.
  if (addresses_.size() == 0)
    return 1;
  // If there are addresses to choose from, but none is selected, add extra
  // items for the "Select" entry and a separator.
  return addresses_.size() + kNbHeaderEntries;
}

base::string16 AddressComboboxModel::GetItemAt(int index) {
  DCHECK_GE(index, 0);
  // A special entry is always added at index 0 and a separator at index 1.
  DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries);

  // Special entry when no profiles have been created yet.
  if (addresses_.empty())
    return l10n_util::GetStringUTF16(IDS_AUTOFILL_NO_SAVED_ADDRESS);

  // Always show the "Select" entry at the top, default selection position.
  if (index == 0)
    return l10n_util::GetStringUTF16(IDS_AUTOFILL_SELECT);

  // Always show the "Select" entry at the top, default selection position.
  if (index == 1)
    return base::ASCIIToUTF16("---");

  return addresses_[index - kNbHeaderEntries].second;
}

bool AddressComboboxModel::IsItemSeparatorAt(int index) {
  // The only separator is between the "Select" entry at 0 and the first address
  // at index 2. So there must be at least one address for a separator to be
  // shown.
  DCHECK(index <= kNbHeaderEntries || !addresses_.empty());
  return index == 1;
}

int AddressComboboxModel::GetDefaultIndex() const {
  if (!default_selected_guid_.empty()) {
    int address_index = GetIndexOfIdentifier(default_selected_guid_);
    if (address_index != -1)
      return address_index;
  }
  return ui::ComboboxModel::GetDefaultIndex();
}

void AddressComboboxModel::AddObserver(ui::ComboboxModelObserver* observer) {
  observers_.AddObserver(observer);
}

void AddressComboboxModel::RemoveObserver(ui::ComboboxModelObserver* observer) {
  observers_.RemoveObserver(observer);
}

int AddressComboboxModel::AddNewProfile(const AutofillProfile& profile) {
  profiles_cache_.push_back(std::make_unique<AutofillProfile>(profile));
  UpdateAddresses();
  DCHECK_GT(addresses_.size(), 0UL);
  return addresses_.size() + kNbHeaderEntries - 1;
}

std::string AddressComboboxModel::GetItemIdentifierAt(int index) {
  // The first two indices are special entries, with no addresses.
  if (index < kNbHeaderEntries)
    return std::string();
  DCHECK_LT(static_cast<size_t>(index), addresses_.size() + kNbHeaderEntries);
  return addresses_[index - kNbHeaderEntries].first;
}

int AddressComboboxModel::GetIndexOfIdentifier(
    const std::string& identifier) const {
  for (size_t i = 0; i < addresses_.size(); ++i) {
    if (addresses_[i].first == identifier)
      return i + kNbHeaderEntries;
  }
  return -1;
}

void AddressComboboxModel::UpdateAddresses() {
  addresses_.clear();
  std::vector<base::string16> labels;
  // CreateDifferentiatingLabels is expecting a pointer vector and we keep
  // profiles as unique_ptr.
  std::vector<AutofillProfile*> profiles;
  for (const auto& profile : profiles_cache_) {
    profiles.push_back(profile.get());
  }
  AutofillProfile::CreateDifferentiatingLabels(profiles, app_locale_, &labels);
  DCHECK_EQ(labels.size(), profiles_cache_.size());

  for (size_t i = 0; i < profiles_cache_.size(); ++i)
    addresses_.emplace_back(profiles_cache_[i]->guid(), labels[i]);

  for (auto& observer : observers_) {
    observer.OnComboboxModelChanged(this);
  }
}
}  // namespace autofill
