// Copyright 2018 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/password_manager/core/browser/new_password_form_manager.h"

#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/stl_util.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/password_form_generation_data.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/password_form_filling.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_manager_util.h"

using autofill::FormData;
using autofill::FormFieldData;
using autofill::FormSignature;
using autofill::FormStructure;
using autofill::PasswordForm;
using autofill::ValueElementPair;
using base::TimeDelta;
using base::TimeTicks;

using Logger = autofill::SavePasswordProgressLogger;

namespace password_manager {

bool NewPasswordFormManager::wait_for_server_predictions_for_filling_ = true;

namespace {

constexpr TimeDelta kMaxFillingDelayForServerPredictions =
    TimeDelta::FromMilliseconds(500);

// Helper to get the platform specific identifier by which autofill and password
// manager refer to a field. See http://crbug.com/896594
base::string16 GetPlatformSpecificIdentifier(const FormFieldData& field) {
#if defined(OS_IOS)
  return field.unique_id;
#else
  return field.name;
#endif
}

ValueElementPair PasswordToSave(const PasswordForm& form) {
  if (form.new_password_value.empty()) {
    DCHECK(!form.password_value.empty());
    return {form.password_value, form.password_element};
  }
  return {form.new_password_value, form.new_password_element};
}

// Copies field properties masks from the form |from| to the form |to|.
void CopyFieldPropertiesMasks(const FormData& from, FormData* to) {
  // Skip copying if the number of fields is different.
  if (from.fields.size() != to->fields.size())
    return;

  for (size_t i = 0; i < from.fields.size(); ++i) {
    to->fields[i].properties_mask =
        GetPlatformSpecificIdentifier(to->fields[i]) ==
                GetPlatformSpecificIdentifier(from.fields[i])
            ? from.fields[i].properties_mask
            : autofill::FieldPropertiesFlags::ERROR_OCCURRED;
  }
}

// Filter sensitive information, duplicates and |username_value| out from
// |form->other_possible_usernames|.
void SanitizePossibleUsernames(PasswordForm* form) {
  auto& usernames = form->other_possible_usernames;

  // Deduplicate.
  std::sort(usernames.begin(), usernames.end());
  usernames.erase(std::unique(usernames.begin(), usernames.end()),
                  usernames.end());

  // Filter out |form->username_value| and sensitive information.
  const base::string16& username_value = form->username_value;
  base::EraseIf(usernames, [&username_value](const ValueElementPair& pair) {
    return pair.first == username_value ||
           autofill::IsValidCreditCardNumber(pair.first) ||
           autofill::IsSSN(pair.first);
  });
}

// Returns bit masks with differences in forms attributes which are important
// for parsing. Bits are set according to enum FormDataDifferences.
uint32_t FindFormsDifferences(const FormData& lhs, const FormData& rhs) {
  if (lhs.fields.size() != rhs.fields.size())
    return PasswordFormMetricsRecorder::kFieldsNumber;
  size_t differences_bitmask = 0;
  for (size_t i = 0; i < lhs.fields.size(); ++i) {
    const FormFieldData& lhs_field = lhs.fields[i];
    const FormFieldData& rhs_field = rhs.fields[i];

    if (lhs_field.unique_renderer_id != rhs_field.unique_renderer_id)
      differences_bitmask |= PasswordFormMetricsRecorder::kRendererFieldIDs;

    if (lhs_field.form_control_type != rhs_field.form_control_type)
      differences_bitmask |= PasswordFormMetricsRecorder::kFormControlTypes;

    if (lhs_field.autocomplete_attribute != rhs_field.autocomplete_attribute)
      differences_bitmask |=
          PasswordFormMetricsRecorder::kAutocompleteAttributes;
  }
  return differences_bitmask;
}

}  // namespace

NewPasswordFormManager::NewPasswordFormManager(
    PasswordManagerClient* client,
    const base::WeakPtr<PasswordManagerDriver>& driver,
    const FormData& observed_form,
    FormFetcher* form_fetcher,
    std::unique_ptr<FormSaver> form_saver,
    scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder)
    : client_(client),
      driver_(driver),
      observed_form_(observed_form),
      metrics_recorder_(metrics_recorder),
      owned_form_fetcher_(
          form_fetcher ? nullptr
                       : std::make_unique<FormFetcherImpl>(
                             PasswordStore::FormDigest(observed_form),
                             client_,
                             true /* should_migrate_http_passwords */,
                             true /* should_query_suppressed_https_forms */)),
      form_fetcher_(form_fetcher ? form_fetcher : owned_form_fetcher_.get()),
      form_saver_(std::move(form_saver)),
      // TODO(https://crbug.com/831123): set correctly
      // |is_possible_change_password_form| in |votes_uploader_| constructor
      votes_uploader_(client, false /* is_possible_change_password_form */),
      weak_ptr_factory_(this) {
  if (!metrics_recorder_) {
    metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
        client_->IsMainFrameSecure(), client_->GetUkmSourceId());
  }
  metrics_recorder_->RecordFormSignature(CalculateFormSignature(observed_form));

  if (owned_form_fetcher_)
    owned_form_fetcher_->Fetch();
  form_fetcher_->AddConsumer(this);

  // The following code is for development and debugging purposes.
  // TODO(https://crbug.com/831123): remove it when NewPasswordFormManager will
  // be production ready.
  if (password_manager_util::IsLoggingActive(client_))
    ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling);
}
NewPasswordFormManager::~NewPasswordFormManager() = default;

bool NewPasswordFormManager::DoesManage(
    const FormData& form,
    const PasswordManagerDriver* driver) const {
  if (driver != driver_.get())
    return false;

  if (observed_form_.is_form_tag != form.is_form_tag)
    return false;
  // All unowned input elements are considered as one synthetic form.
  if (!observed_form_.is_form_tag && !form.is_form_tag)
    return true;
#if defined(OS_IOS)
  // On iOS form name is used as the form identifier.
  return observed_form_.name == form.name;
#else
  return observed_form_.unique_renderer_id == form.unique_renderer_id;
#endif
}

bool NewPasswordFormManager::DoesManageAccordingToRendererId(
    uint32_t form_renderer_id,
    const PasswordManagerDriver* driver) const {
  if (driver != driver_.get())
    return false;
#if defined(OS_IOS)
  NOTREACHED();
  // On iOS form name is used as the form identifier.
  return false;
#else
  return observed_form_.unique_renderer_id == form_renderer_id;
#endif
}

bool NewPasswordFormManager::IsEqualToSubmittedForm(
    const autofill::FormData& form) const {
  if (!is_submitted_)
    return false;
  if (form.action == submitted_form_.action)
    return true;
  // TODO(https://crbug.com/831123): Implement other checks from a function
  // IsPasswordFormReappeared from password_manager.cc.
  return false;
}

FormFetcher* NewPasswordFormManager::GetFormFetcher() {
  return form_fetcher_;
}

const GURL& NewPasswordFormManager::GetOrigin() const {
  return observed_form_.origin;
}

const std::map<base::string16, const PasswordForm*>&
NewPasswordFormManager::GetBestMatches() const {
  return best_matches_;
}

const PasswordForm& NewPasswordFormManager::GetPendingCredentials() const {
  return pending_credentials_;
}

metrics_util::CredentialSourceType
NewPasswordFormManager::GetCredentialSource() {
  return metrics_util::CredentialSourceType::kPasswordManager;
}

PasswordFormMetricsRecorder* NewPasswordFormManager::GetMetricsRecorder() {
  return metrics_recorder_.get();
}

const std::vector<const PasswordForm*>&
NewPasswordFormManager::GetBlacklistedMatches() const {
  return blacklisted_matches_;
}

bool NewPasswordFormManager::IsBlacklisted() const {
  return !blacklisted_matches_.empty();
}

bool NewPasswordFormManager::IsPasswordOverridden() const {
  return password_overridden_;
}

const PasswordForm* NewPasswordFormManager::GetPreferredMatch() const {
  return preferred_match_;
}

void NewPasswordFormManager::Save() {
  DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
  DCHECK(!client_->IsIncognito());

  // TODO(https://crbug.com/831123): Implement indicator event metrics.
  if (password_overridden_ &&
      pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
      !HasGeneratedPassword()) {
    metrics_util::LogPasswordGenerationSubmissionEvent(
        metrics_util::PASSWORD_OVERRIDDEN);
    pending_credentials_.type = PasswordForm::TYPE_MANUAL;
  }

  if (is_new_login_) {
    SanitizePossibleUsernames(&pending_credentials_);
    pending_credentials_.date_created = base::Time::Now();
    votes_uploader_.SendVotesOnSave(observed_form_, *parsed_submitted_form_,
                                    best_matches_, &pending_credentials_);
    form_saver_->Save(pending_credentials_, best_matches_);
  } else {
    ProcessUpdate();
    std::vector<PasswordForm> credentials_to_update =
        FindOtherCredentialsToUpdate();
    form_saver_->Update(pending_credentials_, best_matches_,
                        &credentials_to_update, nullptr);
  }

  if (pending_credentials_.times_used == 1 &&
      pending_credentials_.type == PasswordForm::TYPE_GENERATED) {
    // This also includes PSL matched credentials.
    metrics_util::LogPasswordGenerationSubmissionEvent(
        metrics_util::PASSWORD_USED);
  }

  client_->UpdateFormManagers();
}

void NewPasswordFormManager::Update(const PasswordForm& credentials_to_update) {
  metrics_util::LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
      parsed_submitted_form_->submission_event);
  metrics_recorder_->SetSubmissionIndicatorEvent(
      parsed_submitted_form_->submission_event);

  std::unique_ptr<PasswordForm> parsed_observed_form =
      parser_.Parse(observed_form_, FormDataParser::Mode::kFilling);

  base::string16 password_to_save = pending_credentials_.password_value;
  bool skip_zero_click = pending_credentials_.skip_zero_click;
  pending_credentials_ = credentials_to_update;
  pending_credentials_.password_value = password_to_save;
  pending_credentials_.skip_zero_click = skip_zero_click;
  pending_credentials_.preferred = true;
  is_new_login_ = false;
  ProcessUpdate();
  std::vector<PasswordForm> more_credentials_to_update =
      FindOtherCredentialsToUpdate();
  form_saver_->Update(pending_credentials_, best_matches_,
                      &more_credentials_to_update, nullptr);

  client_->UpdateFormManagers();
}

void NewPasswordFormManager::UpdateUsername(
    const base::string16& new_username) {
  DCHECK(parsed_submitted_form_);
  parsed_submitted_form_->username_value = new_username;
  parsed_submitted_form_->username_element.clear();

  // |has_username_edited_vote_| is true iff |new_username| was typed in another
  // field. Otherwise, |has_username_edited_vote_| is false and no vote will be
  // uploaded.
  votes_uploader_.set_has_username_edited_vote(false);
  if (!new_username.empty()) {
    // |other_possible_usernames| has all possible usernames.
    // TODO(crbug.com/831123): rename to |all_possible_usernames| when the old
    // parser is gone.
    for (const auto& possible_username :
         parsed_submitted_form_->other_possible_usernames) {
      if (possible_username.first == new_username) {
        parsed_submitted_form_->username_element = possible_username.second;
        votes_uploader_.set_has_username_edited_vote(true);
        break;
      }
    }
  }

  CreatePendingCredentials();
}

void NewPasswordFormManager::UpdatePasswordValue(
    const base::string16& new_password) {
  DCHECK(parsed_submitted_form_);
  parsed_submitted_form_->password_value = new_password;
  parsed_submitted_form_->password_element.clear();

  // The user updated a password from the prompt. It means that heuristics were
  // wrong. So clear new password, since it is likely wrong.
  parsed_submitted_form_->new_password_value.clear();
  parsed_submitted_form_->new_password_element.clear();

  for (const ValueElementPair& pair :
       parsed_submitted_form_->all_possible_passwords) {
    if (pair.first == new_password) {
      parsed_submitted_form_->password_element = pair.second;
      break;
    }
  }

  CreatePendingCredentials();
}

void NewPasswordFormManager::OnNopeUpdateClicked() {
  votes_uploader_.UploadPasswordVote(*parsed_submitted_form_,
                                     *parsed_submitted_form_,
                                     autofill::NOT_NEW_PASSWORD, std::string());
}

void NewPasswordFormManager::OnNeverClicked() {
  // |UNKNOWN_TYPE| is sent in order to record that a generation popup was
  // shown and ignored.
  votes_uploader_.UploadPasswordVote(*parsed_submitted_form_,
                                     *parsed_submitted_form_,
                                     autofill::UNKNOWN_TYPE, std::string());
  PermanentlyBlacklist();
}

void NewPasswordFormManager::OnNoInteraction(bool is_update) {
  // |UNKNOWN_TYPE| is sent in order to record that a generation popup was
  // shown and ignored.
  votes_uploader_.UploadPasswordVote(
      *parsed_submitted_form_, *parsed_submitted_form_,
      is_update ? autofill::PROBABLY_NEW_PASSWORD : autofill::UNKNOWN_TYPE,
      std::string());
}

void NewPasswordFormManager::PermanentlyBlacklist() {
  DCHECK(!client_->IsIncognito());

  if (!new_blacklisted_) {
    new_blacklisted_ = std::make_unique<PasswordForm>();
    new_blacklisted_->origin = observed_form_.origin;
    new_blacklisted_->signon_realm = GetSignonRealm(observed_form_.origin);
    blacklisted_matches_.push_back(new_blacklisted_.get());
  }
  form_saver_->PermanentlyBlacklist(new_blacklisted_.get());
}

void NewPasswordFormManager::OnPasswordsRevealed() {
  votes_uploader_.set_has_passwords_revealed_vote(true);
}

bool NewPasswordFormManager::IsNewLogin() const {
  return is_new_login_;
}

bool NewPasswordFormManager::IsPendingCredentialsPublicSuffixMatch() const {
  return pending_credentials_.is_public_suffix_match;
}

void NewPasswordFormManager::PresaveGeneratedPassword(
    const PasswordForm& form) {
  std::unique_ptr<PasswordForm> parsed_form =
      ParseFormAndMakeLogging(form.form_data, FormDataParser::Mode::kSaving);

  if (!parsed_form) {
    // Use the old parser result if parsing fails.
    // TODO(https://crbug.com/831123). Make it work without the old parser.
    parsed_form.reset(new PasswordForm(form));
  }

  if (!HasGeneratedPassword()) {
    votes_uploader_.set_generated_password_changed(false);
    metrics_recorder_->SetGeneratedPasswordStatus(
        PasswordFormMetricsRecorder::GeneratedPasswordStatus::
            kPasswordAccepted);
  } else {
    // If the password is already generated and new value to presave differs
    // from the presaved one, then mark that the generated password was changed.
    // If a user recovers the original generated password, it will be recorded
    // as a password change.
    if (generated_password_ != form.password_value) {
      votes_uploader_.set_generated_password_changed(true);
      metrics_recorder_->SetGeneratedPasswordStatus(
          PasswordFormMetricsRecorder::GeneratedPasswordStatus::
              kPasswordEdited);
    }
  }
  votes_uploader_.set_has_generated_password(true);

  // TODO(https://crbug.com/831123). Propagate generated password independently
  // of PasswordForm when PasswordForm goes away from the renderer process.
  generated_password_ = form.password_value;

  // Set |password_value| to the generated password in order to ensure that the
  // generated password is saved.
  parsed_form->password_value = generated_password_;

  // Clear the username value if there are already saved credentials with
  // the same username in order to prevent overwriting.
  if (base::ContainsKey(best_matches_, parsed_form->username_value))
    parsed_form->username_value.clear();

  form_saver_->PresaveGeneratedPassword(*parsed_form);
}

void NewPasswordFormManager::PasswordNoLongerGenerated() {
  DCHECK(HasGeneratedPassword());
  form_saver_->RemovePresavedPassword();
  generated_password_.clear();
  votes_uploader_.set_has_generated_password(false);
  votes_uploader_.set_generated_password_changed(false);
  metrics_recorder_->SetGeneratedPasswordStatus(
      PasswordFormMetricsRecorder::GeneratedPasswordStatus::kPasswordDeleted);
}

bool NewPasswordFormManager::HasGeneratedPassword() const {
  return !generated_password_.empty();
}

void NewPasswordFormManager::SetGenerationPopupWasShown(
    bool generation_popup_was_shown,
    bool is_manual_generation) {
  votes_uploader_.set_generation_popup_was_shown(generation_popup_was_shown);
  votes_uploader_.set_is_manual_generation(is_manual_generation);
  metrics_recorder_->SetPasswordGenerationPopupShown(generation_popup_was_shown,
                                                     is_manual_generation);
}

void NewPasswordFormManager::SetGenerationElement(
    const base::string16& generation_element) {
  votes_uploader_.set_generation_element(generation_element);
}

bool NewPasswordFormManager::IsPossibleChangePasswordFormWithoutUsername()
    const {
  return parsed_submitted_form_ &&
         parsed_submitted_form_->IsPossibleChangePasswordFormWithoutUsername();
}

bool NewPasswordFormManager::RetryPasswordFormPasswordUpdate() const {
  return retry_password_form_password_update_;
}

bool NewPasswordFormManager::IsPasswordUpdate() const {
  return (!GetBestMatches().empty() &&
          IsPossibleChangePasswordFormWithoutUsername()) ||
         IsPasswordOverridden() || RetryPasswordFormPasswordUpdate();
}

std::vector<base::WeakPtr<PasswordManagerDriver>>
NewPasswordFormManager::GetDrivers() const {
  return {driver_};
}

const PasswordForm* NewPasswordFormManager::GetSubmittedForm() const {
  return parsed_submitted_form_.get();
}

std::unique_ptr<NewPasswordFormManager> NewPasswordFormManager::Clone() {
  // Fetcher is cloned to avoid re-fetching data from PasswordStore.
  std::unique_ptr<FormFetcher> fetcher = form_fetcher_->Clone();

  // Some data is filled through the constructor. No PasswordManagerDriver is
  // needed, because the UI does not need any functionality related to the
  // renderer process, to which the driver serves as an interface. The full
  // |observed_form_| needs to be copied, because it is used to create the
  // blacklisting entry if needed.
  auto result = std::make_unique<NewPasswordFormManager>(
      client_, base::WeakPtr<PasswordManagerDriver>(), observed_form_,
      fetcher.get(), form_saver_->Clone(), metrics_recorder_);

  // The constructor only can take a weak pointer to the fetcher, so moving the
  // owning one needs to happen explicitly.
  result->owned_form_fetcher_ = std::move(fetcher);

  // These data members all satisfy:
  //   (1) They could have been changed by |*this| between its construction and
  //       calling Clone().
  //   (2) They are potentially used in the clone as the clone is used in the UI
  //       code.
  //   (3) They are not changed during ProcessMatches, triggered at some point
  //       by the cloned FormFetcher.
  result->generated_password_ = generated_password_;
  result->votes_uploader_ = votes_uploader_;
  if (parser_.predictions())
    result->parser_.set_predictions(*parser_.predictions());

  result->pending_credentials_ = pending_credentials_;
  if (parsed_submitted_form_) {
    result->parsed_submitted_form_.reset(
        new PasswordForm(*parsed_submitted_form_));
  }
  result->is_new_login_ = is_new_login_;
  result->password_overridden_ = password_overridden_;
  result->retry_password_form_password_update_ =
      retry_password_form_password_update_;
  result->is_submitted_ = is_submitted_;

  return result;
}

void NewPasswordFormManager::ProcessMatches(
    const std::vector<const PasswordForm*>& non_federated,
    size_t filtered_count) {
  received_stored_credentials_time_ = TimeTicks::Now();
  std::vector<const PasswordForm*> matches;
  std::copy_if(non_federated.begin(), non_federated.end(),
               std::back_inserter(matches), [](const PasswordForm* form) {
                 return !form->blacklisted_by_user &&
                        form->scheme == PasswordForm::SCHEME_HTML;
               });

  password_manager_util::FindBestMatches(matches, &best_matches_,
                                         &not_best_matches_, &preferred_match_);

  // Copy out blacklisted matches.
  blacklisted_matches_.clear();
  new_blacklisted_.reset();
  std::copy_if(
      non_federated.begin(), non_federated.end(),
      std::back_inserter(blacklisted_matches_), [](const PasswordForm* form) {
        return form->blacklisted_by_user && !form->is_public_suffix_match;
      });

  autofills_left_ = kMaxTimesAutofill;

  if (parser_.predictions() || !wait_for_server_predictions_for_filling_) {
    ReportTimeBetweenStoreAndServerUMA();
    Fill();
  } else if (!waiting_for_server_predictions_) {
    waiting_for_server_predictions_ = true;
    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&NewPasswordFormManager::Fill,
                       weak_ptr_factory_.GetWeakPtr()),
        kMaxFillingDelayForServerPredictions);
  }
}

bool NewPasswordFormManager::ProvisionallySave(
    const autofill::FormData& submitted_form,
    const PasswordManagerDriver* driver) {
  DCHECK(DoesManage(submitted_form, driver));

  std::unique_ptr<PasswordForm> parsed_submitted_form =
      ParseFormAndMakeLogging(submitted_form, FormDataParser::Mode::kSaving);

  RecordMetricOnReadonly(parser_.readonly_status(), !!parsed_submitted_form,
                         FormDataParser::Mode::kSaving);

  // This function might be called multiple times. Consider as success if the
  // submitted form was successfully parsed on a previous call.
  if (!parsed_submitted_form)
    return is_submitted_;

  parsed_submitted_form_ = std::move(parsed_submitted_form);
  submitted_form_ = submitted_form;
  is_submitted_ = true;
  CalculateFillingAssistanceMetric(submitted_form);

  CreatePendingCredentials();
  return true;
}

void NewPasswordFormManager::ProcessServerPredictions(
    const std::map<FormSignature, FormPredictions>& predictions) {
  FormSignature observed_form_signature =
      CalculateFormSignature(observed_form_);
  auto it = predictions.find(observed_form_signature);
  if (it == predictions.end())
    return;

  ReportTimeBetweenStoreAndServerUMA();
  parser_.set_predictions(it->second);
  Fill();
}

void NewPasswordFormManager::Fill() {
  if (!driver_)
    return;

  waiting_for_server_predictions_ = false;

  if (form_fetcher_->GetState() == FormFetcher::State::WAITING)
    return;

  if (autofills_left_ <= 0)
    return;
  autofills_left_--;

  // There are additional signals (server-side data) and parse results in
  // filling and saving mode might be different so it is better not to cache
  // parse result, but to parse each time again.
  std::unique_ptr<PasswordForm> observed_password_form =
      ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling);
  RecordMetricOnReadonly(parser_.readonly_status(), !!observed_password_form,
                         FormDataParser::Mode::kFilling);
  if (!observed_password_form)
    return;

  RecordMetricOnCompareParsingResult(*observed_password_form);

  if (observed_password_form->is_new_password_reliable && !IsBlacklisted()) {
#if defined(OS_IOS)
    driver_->FormEligibleForGenerationFound(
        {.form_name = observed_password_form->form_data.name,
         .new_password_element = observed_password_form->new_password_element,
         .confirmation_password_element =
             observed_password_form->confirmation_password_element});
#else
    driver_->FormEligibleForGenerationFound(
        {.new_password_renderer_id =
             observed_password_form->new_password_element_renderer_id,
         .confirmation_password_renderer_id =
             observed_password_form
                 ->confirmation_password_element_renderer_id});
#endif
  }

  // TODO(https://crbug.com/831123). Implement correct treating of federated
  // matches.
  std::vector<const PasswordForm*> federated_matches;
  SendFillInformationToRenderer(*client_, driver_.get(), IsBlacklisted(),
                                *observed_password_form.get(), best_matches_,
                                federated_matches, preferred_match_,
                                metrics_recorder_.get());
}

void NewPasswordFormManager::FillForm(const FormData& observed_form) {
  uint32_t differences_bitmask =
      FindFormsDifferences(observed_form_, observed_form);
  metrics_recorder_->RecordFormChangeBitmask(differences_bitmask);

  if (differences_bitmask)
    observed_form_ = observed_form;

  if (!waiting_for_server_predictions_)
    Fill();
}

void NewPasswordFormManager::RecordMetricOnCompareParsingResult(
    const PasswordForm& parsed_form) {
  bool same =
      parsed_form.username_element == old_parsing_result_.username_element &&
      parsed_form.password_element == old_parsing_result_.password_element &&
      parsed_form.new_password_element ==
          old_parsing_result_.new_password_element &&
      parsed_form.confirmation_password_element ==
          old_parsing_result_.confirmation_password_element;
  if (same) {
    metrics_recorder_->RecordParsingsComparisonResult(
        PasswordFormMetricsRecorder::ParsingComparisonResult::kSame);
    return;
  }

  // In the old parsing for fields with empty name, placeholders are used. The
  // reason for this is that an empty "..._element" attribute in a PasswordForm
  // means that no corresponding input element exists. The new form parsing sets
  // empty string in that case because renderer ids are used instead of element
  // names for fields identification. Hence in case of anonymous fields, the
  // results will be different for sure. Compare to placeholders and record this
  // case.
  if (old_parsing_result_.username_element ==
          base::ASCIIToUTF16("anonymous_username") ||
      old_parsing_result_.password_element ==
          base::ASCIIToUTF16("anonymous_password") ||
      old_parsing_result_.new_password_element ==
          base::ASCIIToUTF16("anonymous_new_password") ||
      old_parsing_result_.confirmation_password_element ==
          base::ASCIIToUTF16("anonymous_confirmation_password")) {
    metrics_recorder_->RecordParsingsComparisonResult(
        PasswordFormMetricsRecorder::ParsingComparisonResult::kAnonymousFields);
  } else {
    metrics_recorder_->RecordParsingsComparisonResult(
        PasswordFormMetricsRecorder::ParsingComparisonResult::kDifferent);
  }
}

void NewPasswordFormManager::RecordMetricOnReadonly(
    FormDataParser::ReadonlyPasswordFields readonly_status,
    bool parsing_successful,
    FormDataParser::Mode mode) {
  // The reported value is combined of the |readonly_status| shifted by one bit
  // to the left, and the success bit put in the least significant bit. Note:
  // C++ guarantees that bool->int conversions map false to 0 and true to 1.
  uint64_t value = static_cast<uint64_t>(parsing_successful) +
                   (static_cast<uint64_t>(readonly_status) << 1);
  switch (mode) {
    case FormDataParser::Mode::kSaving:
      metrics_recorder_->RecordReadonlyWhenSaving(value);
      break;
    case FormDataParser::Mode::kFilling:
      metrics_recorder_->RecordReadonlyWhenFilling(value);
      break;
  }
}

void NewPasswordFormManager::ReportTimeBetweenStoreAndServerUMA() {
  if (!received_stored_credentials_time_.is_null()) {
    UMA_HISTOGRAM_TIMES("PasswordManager.TimeBetweenStoreAndServer",
                        TimeTicks::Now() - received_stored_credentials_time_);
  }
}

void NewPasswordFormManager::CreatePendingCredentials() {
  DCHECK(is_submitted_);
  // TODO(https://crbug.com/831123): Process correctly the case when saved
  // credentials are not received from the store yet.
  if (!parsed_submitted_form_)
    return;

  // Calculate the user's action based on existing matches and the submitted
  // form.
  metrics_recorder_->CalculateUserAction(best_matches_,
                                         *parsed_submitted_form_);

  // This function might be called multiple times so set variables that are
  // changed in this function to initial states.
  is_new_login_ = true;
  SetPasswordOverridden(false);
  retry_password_form_password_update_ = false;

  ValueElementPair password_to_save(PasswordToSave(*parsed_submitted_form_));

  // Look for the actually submitted credentials in the list of previously saved
  // credentials that were available to autofilling.
  const PasswordForm* saved_form =
      FindBestSavedMatch(parsed_submitted_form_.get());
  if (saved_form) {
    // The user signed in with a login we autofilled.
    pending_credentials_ = *saved_form;
    SetPasswordOverridden(pending_credentials_.password_value !=
                          password_to_save.first);

    if (pending_credentials_.is_public_suffix_match) {
      // If the autofilled credentials were a PSL match or credentials stored
      // from Android apps, store a copy with the current origin and signon
      // realm. This ensures that on the next visit, a precise match is found.
      is_new_login_ = true;

      // Update credential to reflect that it has been used for submission.
      // If this isn't updated, then password generation uploads are off for
      // sites where PSL matching is required to fill the login form, as two
      // PASSWORD votes are uploaded per saved password instead of one.
      password_manager_util::UpdateMetadataForUsage(&pending_credentials_);

      // Update |pending_credentials_| in order to be able correctly save it.
      pending_credentials_.origin = submitted_form_.origin;
      pending_credentials_.signon_realm = parsed_submitted_form_->signon_realm;

      // Normally, the copy of the PSL matched credentials, adapted for the
      // current domain, is saved automatically without asking the user, because
      // the copy likely represents the same account, i.e., the one for which
      // the user already agreed to store a password.
      //
      // However, if the user changes the suggested password, it might indicate
      // that the autofilled credentials and |submitted_password_form|
      // actually correspond to two different accounts (see
      // http://crbug.com/385619). In that case the user should be asked again
      // before saving the password. This is ensured by setting
      // |password_overriden_| on |pending_credentials_| to false.
      //
      // There is still the edge case when the autofilled credentials represent
      // the same account as |submitted_password_form| but the stored password
      // was out of date. In that case, the user just had to manually enter the
      // new password, which is now in |submitted_password_form|. The best
      // thing would be to save automatically, and also update the original
      // credentials. However, we have no way to tell if this is the case.
      // This will likely happen infrequently, and the inconvenience put on the
      // user by asking them is not significant, so we are fine with asking
      // here again.
      if (password_overridden_) {
        pending_credentials_.is_public_suffix_match = false;
        SetPasswordOverridden(false);
      }
    } else {  // Not a PSL match but a match of an already stored credential.
      is_new_login_ = false;
    }
  } else if (!best_matches_.empty() &&
             parsed_submitted_form_->type != PasswordForm::TYPE_API &&
             parsed_submitted_form_->username_value.empty()) {
    // This branch deals with the case that the submitted form has no username
    // element and needs to decide whether to offer to update any credentials.
    // In that case, the user can select any previously stored credential as
    // the one to update, but we still try to find the best candidate.

    // Find the best candidate to select by default in the password update
    // bubble. If no best candidate is found, any one can be offered.
    const PasswordForm* best_update_match =
        FindBestMatchForUpdatePassword(parsed_submitted_form_->password_value);

    // A retry password form is one that consists of only an "old password"
    // field, i.e. one that is not a "new password".
    retry_password_form_password_update_ =
        parsed_submitted_form_->username_value.empty() &&
        parsed_submitted_form_->new_password_value.empty();

    is_new_login_ = false;
    if (best_update_match) {
      // Chose |best_update_match| to be updated.
      pending_credentials_ = *best_update_match;
    } else if (HasGeneratedPassword()) {
      // If a password was generated and we didn't find a match, we have to save
      // it in a separate entry since we have to store it but we don't know
      // where.
      CreatePendingCredentialsForNewCredentials(*parsed_submitted_form_,
                                                password_to_save.second);
      is_new_login_ = true;
    } else {
      // We don't have a good candidate to choose as the default credential for
      // the update bubble and the user has to pick one.
      // We set |pending_credentials_| to the bare minimum, which is the correct
      // origin.
      pending_credentials_.origin = submitted_form_.origin;
    }
  } else {
    is_new_login_ = true;
    // No stored credentials can be matched to the submitted form. Offer to
    // save new credentials.
    CreatePendingCredentialsForNewCredentials(*parsed_submitted_form_,
                                              password_to_save.second);
    // Generate username correction votes.
    bool username_correction_found =
        votes_uploader_.FindCorrectedUsernameElement(
            best_matches_, not_best_matches_,
            parsed_submitted_form_->username_value,
            parsed_submitted_form_->password_value);
    UMA_HISTOGRAM_BOOLEAN("PasswordManager.UsernameCorrectionFound",
                          username_correction_found);
    if (username_correction_found) {
      metrics_recorder_->RecordDetailedUserAction(
          password_manager::PasswordFormMetricsRecorder::DetailedUserAction::
              kCorrectedUsernameInForm);
    }
  }

  if (!IsValidAndroidFacetURI(pending_credentials_.signon_realm))
    pending_credentials_.action = submitted_form_.action;

  pending_credentials_.password_value = generated_password_.empty()
                                            ? password_to_save.first
                                            : generated_password_;
  pending_credentials_.preferred = true;
  pending_credentials_.form_has_autofilled_value =
      parsed_submitted_form_->form_has_autofilled_value;
  pending_credentials_.all_possible_passwords =
      parsed_submitted_form_->all_possible_passwords;
  CopyFieldPropertiesMasks(submitted_form_, &pending_credentials_.form_data);

  // If we're dealing with an API-driven provisionally saved form, then take
  // the server provided values. We don't do this for non-API forms, as
  // those will never have those members set.
  if (parsed_submitted_form_->type == PasswordForm::TYPE_API) {
    pending_credentials_.skip_zero_click =
        parsed_submitted_form_->skip_zero_click;
    pending_credentials_.display_name = parsed_submitted_form_->display_name;
    pending_credentials_.federation_origin =
        parsed_submitted_form_->federation_origin;
    pending_credentials_.icon_url = parsed_submitted_form_->icon_url;
    // It's important to override |signon_realm| for federated credentials
    // because it has format "federation://" + origin_host + "/" +
    // federation_host
    pending_credentials_.signon_realm = parsed_submitted_form_->signon_realm;
  }

  if (HasGeneratedPassword())
    pending_credentials_.type = PasswordForm::TYPE_GENERATED;
}

const PasswordForm* NewPasswordFormManager::FindBestMatchForUpdatePassword(
    const base::string16& password) const {
  // This function is called for forms that do not contain a username field.
  // This means that we cannot update credentials based on a matching username
  // and that we may need to show an update prompt.
  if (best_matches_.size() == 1 && !HasGeneratedPassword()) {
    // In case the submitted form contained no username but a password, and if
    // the user has only one credential stored, return it as the one that should
    // be updated.
    return best_matches_.begin()->second;
  }
  if (password.empty())
    return nullptr;

  // Return any existing credential that has the same |password| saved already.
  for (const auto& key_value : best_matches_) {
    if (key_value.second->password_value == password)
      return key_value.second;
  }
  return nullptr;
}

const PasswordForm* NewPasswordFormManager::FindBestSavedMatch(
    const PasswordForm* submitted_form) const {
  if (!submitted_form->federation_origin.opaque())
    return nullptr;

  // Return form with matching |username_value|.
  auto it = best_matches_.find(submitted_form->username_value);
  if (it != best_matches_.end())
    return it->second;

  // Match Credential API forms only by username. Stop here if nothing was found
  // above.
  if (submitted_form->type == PasswordForm::TYPE_API)
    return nullptr;

  // Verify that the submitted form has no username and no "new password"
  // and bail out with a nullptr otherwise.
  bool submitted_form_has_username = !submitted_form->username_value.empty();
  bool submitted_form_has_new_password_element =
      !submitted_form->new_password_value.empty();
  if (submitted_form_has_username || submitted_form_has_new_password_element)
    return nullptr;

  // At this line we are certain that the submitted form contains only a
  // password field that is not a "new password". Now we can check whether we
  // have a match by password of an already saved credential.
  for (const auto& stored_match : best_matches_) {
    if (stored_match.second->password_value == submitted_form->password_value)
      return stored_match.second;
  }
  return nullptr;
}

void NewPasswordFormManager::CreatePendingCredentialsForNewCredentials(
    const PasswordForm& submitted_password_form,
    const base::string16& password_element) {
  // TODO(https://crbug.com/831123): Replace parsing of the observed form with
  // usage of already parsed submitted form.
  std::unique_ptr<PasswordForm> parsed_observed_form =
      ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling);
  if (!parsed_observed_form)
    return;
  pending_credentials_ = *parsed_observed_form;
  pending_credentials_.username_element =
      submitted_password_form.username_element;
  pending_credentials_.username_value = submitted_password_form.username_value;
  pending_credentials_.other_possible_usernames =
      submitted_password_form.other_possible_usernames;
  pending_credentials_.all_possible_passwords =
      submitted_password_form.all_possible_passwords;

  // The password value will be filled in later, remove any garbage for now.
  pending_credentials_.password_value.clear();
  // The password element should be determined earlier in |PasswordToSave|.
  pending_credentials_.password_element = password_element;
  // The new password's value and element name should be empty.
  pending_credentials_.new_password_value.clear();
  pending_credentials_.new_password_element.clear();
}

void NewPasswordFormManager::ProcessUpdate() {
  DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
  DCHECK(preferred_match_ || !pending_credentials_.federation_origin.opaque());
  // If we're doing an Update, we either autofilled correctly and need to
  // update the stats, or the user typed in a new password for autofilled
  // username, or the user selected one of the non-preferred matches,
  // thus requiring a swap of preferred bits.
  DCHECK(!is_new_login_ && pending_credentials_.preferred);
  DCHECK(!client_->IsIncognito());
  DCHECK(parsed_submitted_form_);

  password_manager_util::UpdateMetadataForUsage(&pending_credentials_);

  base::RecordAction(
      base::UserMetricsAction("PasswordManager_LoginFollowingAutofill"));

  // Check to see if this form is a candidate for password generation.
  // Do not send votes on change password forms, since they were already sent in
  // Update() method.
  if (!parsed_submitted_form_->IsPossibleChangePasswordForm()) {
    votes_uploader_.SendVoteOnCredentialsReuse(
        observed_form_, *parsed_submitted_form_, &pending_credentials_);
  }
  if (IsPasswordUpdate()) {
    votes_uploader_.UploadPasswordVote(
        *parsed_submitted_form_, *parsed_submitted_form_,
        autofill::NEW_PASSWORD,
        autofill::FormStructure(pending_credentials_.form_data)
            .FormSignatureAsStr());
  }

  if (pending_credentials_.times_used == 1) {
    votes_uploader_.UploadFirstLoginVotes(best_matches_, pending_credentials_,
                                          *parsed_submitted_form_);
  }
}

std::vector<PasswordForm>
NewPasswordFormManager::FindOtherCredentialsToUpdate() {
  std::vector<autofill::PasswordForm> credentials_to_update;
  if (!pending_credentials_.federation_origin.opaque())
    return credentials_to_update;

  auto updated_password_it =
      best_matches_.find(pending_credentials_.username_value);
  DCHECK(best_matches_.end() != updated_password_it);
  const base::string16& old_password =
      updated_password_it->second->password_value;
  for (auto* not_best_match : not_best_matches_) {
    if (not_best_match->username_value == pending_credentials_.username_value &&
        not_best_match->password_value == old_password) {
      credentials_to_update.push_back(*not_best_match);
      credentials_to_update.back().password_value =
          pending_credentials_.password_value;
    }
  }

  return credentials_to_update;
}

std::unique_ptr<PasswordForm> NewPasswordFormManager::ParseFormAndMakeLogging(
    const FormData& form,
    FormDataParser::Mode mode) {
  std::unique_ptr<PasswordForm> password_form = parser_.Parse(form, mode);

  if (password_manager_util::IsLoggingActive(client_)) {
    BrowserSavePasswordProgressLogger logger(client_->GetLogManager());
    logger.LogFormData(Logger::STRING_FORM_PARSING_INPUT, form);
    if (password_form)
      logger.LogPasswordForm(Logger::STRING_FORM_PARSING_OUTPUT,
                             *password_form);
  }
  return password_form;
}

void NewPasswordFormManager::CalculateFillingAssistanceMetric(
    const FormData& submitted_form) {
  // TODO(https://crbug.com/918846): implement collecting all necessary data on
  // iOS.
#if not defined(OS_IOS)
  std::set<base::string16> saved_usernames;
  std::set<base::string16> saved_passwords;

  const std::vector<const PasswordForm*>& saved_forms =
      form_fetcher_->GetNonFederatedMatches();

  for (auto* saved_form : saved_forms) {
    saved_usernames.insert(saved_form->username_value);
    saved_passwords.insert(saved_form->password_value);
  }

  // Saved credentials might have empty usernames which are not interesting for
  // filling assistance metric.
  saved_usernames.erase(base::string16());

  metrics_recorder_->CalculateFillingAssistanceMetric(
      submitted_form, saved_usernames, saved_passwords,
      form_fetcher_->GetInteractionsStats());
#endif
}

}  // namespace password_manager
