// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_IOS_FORM_UTIL_FORM_ACTIVITY_PARAMS_H_
#define COMPONENTS_AUTOFILL_IOS_FORM_UTIL_FORM_ACTIVITY_PARAMS_H_

#import <set>
#import <string>
#import <string_view>

#import "base/values.h"
#import "components/autofill/core/common/unique_ids.h"

namespace web {
class ScriptMessage;
}  // namespace web

namespace autofill {

// HTML password field type. The "password" field type does not explicitly mean
// that the field contains a password, it means that the field obfuscates its
// information instead of showing it plainly.
constexpr char kObfuscatedFieldType[] = "password";

// Wraps information about form activity.
struct BaseFormActivityParams {
  BaseFormActivityParams();
  BaseFormActivityParams(const BaseFormActivityParams& other);
  virtual ~BaseFormActivityParams();

  // Comparison operator for the BaseFormActivityParams structure.
  bool operator==(const BaseFormActivityParams&) const;

  // Reads data from a message into a BaseFormActivityParams object.
  // Returns whether reading the information from the message was successful.
  //
  // It is expected that the input message contains the fields:
  // "frameID": ID of the associated WebFrame object (maps to frame_id)
  static bool FromMessage(const web::ScriptMessage& message,
                          const base::DictValue** message_body,
                          BaseFormActivityParams* params);
  std::string frame_id;

  // |is_main_frame| is true when the activity was registered in the main frame.
  bool is_main_frame = false;
};

std::ostream& operator<<(std::ostream& buffer,
                         const BaseFormActivityParams& form);

// Wraps information about event happening on an input field.
// Example HTML
// <form name="np" id="np1" action="https://example.com/" method="post">
// <input type="text" name="name" id="password_name"><br>
// <input type="password" name="password" id="password_field"><br>
// <input type="reset" value="Reset">
// <input type="submit" value="Submit" id="password_submit">
// </form>
// A tap on the password field will produce
// form_name:  "np"
// field_identifier:  "password_field"
// field_renderer_id: will be the numeric ID generated for the field
// field_type:  "password"
// type: "focus"
// value: "LouisLane" (assuming that was the password typed)
// has_user_gesture:  true
// input_missing:  false
struct FormActivityParams : public BaseFormActivityParams {
  enum class ActivityType {
    kUnknown,
    kFocus,
    kBlur,
    kInput,
    kKeyUp,
    kChange,
    kFormChanged,
  };

  enum class FieldType {
    kUnknown,
    kButton,
    kCheckbox,
    kColor,
    kContentEditable,
    kDate,
    kDateTimeLocal,
    kEmail,
    kFile,
    kHidden,
    kImage,
    kMonth,
    kNumber,
    kObfuscated,
    kRadio,
    kRange,
    kReset,
    kSearch,
    kSelectOne,
    kSubmit,
    kTel,
    kText,
    kTime,
    kUrl,
    kWeek,
  };

  FormActivityParams();
  FormActivityParams(const FormActivityParams& other);
  ~FormActivityParams() override;

  // Comparison operator for FormActivityParams structure. Includes
  // BaseFormActivityParams structure comparison.
  bool operator==(const FormActivityParams& params) const;

  // Reads data from a message into a FormActivityParams object.
  // Returns whether reading the information from the message was successful.
  //
  // It is expected that the input message contains the fields:
  // "formName": name of the current form (maps to form_name)
  // "formRendererID": id of the current form (maps to form_renderer_id)
  // "fieldIdentifier" : name of the current field (maps to field_identifier)
  // "field_renderer_id" : id of the current field (maps to field_renderer_id)
  // "fieldType" : type of the field (maps to field_type)
  // "type" : type of the event (maps to type)
  // "value" : value of the field (maps to value)
  // "hasUserGesture": whether the event is trusted (maps to has_user_gesture)
  // + all fields mentioned for BaseFormActivityParams::FromMessage() above.
  static bool FromMessage(const web::ScriptMessage& message,
                          FormActivityParams* params);

 private:
  friend class FormActivityParamsTest;
  static ActivityType StringToActivityType(std::string_view type);
  static const char* ActivityTypeToString(ActivityType type);
  static FieldType StringToFieldType(std::string_view field_type);
  static const char* FieldTypeToString(FieldType field_type);

 public:
  std::string form_name;
  FormRendererId form_renderer_id;
  // Generated by getFieldIdentifier utility function in form.ts.
  std::string field_identifier;
  // Generated by getUniqueID in fill_util.ts.
  FieldRendererId field_renderer_id;
  FieldType field_type = FieldType::kUnknown;
  std::string value;
  ActivityType type = ActivityType::kUnknown;

  // |input_missing| is set to true if at least one of the members above isn't
  // set.
  bool input_missing = false;

  // |has_user_gesture| is true when the activity was registered as a result of
  // a user action, and not by an event created and dispatched by JavaScript.
  bool has_user_gesture = false;
};

std::ostream& operator<<(std::ostream& buffer, const FormActivityParams& form);

// Wraps information about the form removal.
struct FormRemovalParams : public BaseFormActivityParams {
  FormRemovalParams();
  FormRemovalParams(const FormRemovalParams& other);
  ~FormRemovalParams() override;

  // Renderer ids of removed forms;
  std::set<FormRendererId> removed_forms;

  // Renderer ids of removed unowned fields.
  std::set<FieldRendererId> removed_unowned_fields;

  static bool FromMessage(const web::ScriptMessage& message,
                          FormRemovalParams* params);
};

}  // namespace autofill

#endif  // COMPONENTS_AUTOFILL_IOS_FORM_UTIL_FORM_ACTIVITY_PARAMS_H_
