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

syntax = "proto2";

option optimize_for = LITE_RUNTIME;
option java_package = "org.chromium.chrome.browser.autofill_assistant.proto";
option java_multiple_files = true;

package autofill_assistant;

// A field trial containing the name of the trial and the name of the
// randomly selected trial group.
message FieldTrialProto {
  optional string trial_name = 1;
  optional string group_name = 2;
}

// Context contains client environment details.
message ClientContextProto {
  message Chrome {
    optional string chrome_version = 1;
    repeated FieldTrialProto active_field_trials = 2;
  }
  oneof client { Chrome chrome = 1; }

  // locale should be a comma separated list of language tags. Each tag should
  // be a well-formed IETF BCP 47 language tag with language and country code
  // (e.g., "en-US").
  // The intent is to communicate the client language preferences to the server.
  optional string locale = 5;

  // country should be a country code as defined by ISO 3166-1-alpha-2.
  // The intent is to communicate the client's location to the server.
  optional string country = 6;
}

// Get the list of scripts that can potentially be run on a url.
message SupportsScriptRequestProto {
  optional string url = 1;

  // Parameters that can be used to filter the scripts suitable for execution.
  repeated ScriptParameterProto script_parameters = 2;

  optional ClientContextProto client_context = 3;
}

message ScriptParameterProto {
  // Parameter name, as found in the Intent, without prefix.
  optional string name = 3;
  optional string value = 2;
}

// Response of the list of supported scripts.
message SupportsScriptResponseProto {
  repeated SupportedScriptProto scripts = 1;
}

// Supported script.
message SupportedScriptProto {
  // This is the internal name of the script.
  optional string path = 1;

  message PresentationProto {
    // Script name.
    optional string name = 1;

    // Precondition contains a set of conditions that must hold for a script to
    // be executed. No precondition means that a script can run in any case.
    optional ScriptPreconditionProto precondition = 3;

    // Text display at the same time as the script is proposed. If more than one
    // script has an initial prompt, the prompt of the highest-priority script
    // wins.
    optional string initial_prompt = 4;

    // Display priority of the script. Lowest number has highest priority, which
    // means a script with priority 0 should be displayed before a script with
    // priority 1.
    optional int32 priority = 5;

    // Whether the script should be highlighted.
    optional bool highlight = 7;

    // When set to true this script can be run in 'autostart mode'. Script won't
    // be shown.
    optional bool autostart = 8;

    // When set to true this script will be run from WaitForDom actions with
    // allow_interrupt=true.
    optional bool interrupt = 9;
  }
  optional PresentationProto presentation = 2;
}

enum ScriptStatusProto {
  // Never explicitly set. Reading this value means the enum field is either
  // not set or set to a value not listed here.
  UNKNOWN_SCRIPT_STATUS = 0;
  // The script finished successfully.
  SCRIPT_STATUS_SUCCESS = 1;
  // The script failed.
  SCRIPT_STATUS_FAILURE = 2;
  // The user cancelled the script.
  SCRIPT_STATUS_CANCELLED = 3;
  // The script is currently running.
  SCRIPT_STATUS_RUNNING = 4;
  // The script was not run.
  SCRIPT_STATUS_NOT_RUN = 5;
}

// Condition on the status of a previous script run.
message ScriptStatusMatchProto {
  enum Comparator {
    UNSPECIFIED = 0;
    EQUAL = 1;
    DIFFERENT = 2;
  }

  // Required. Path of the script whose status should be checked.
  optional string script = 1;

  // Required. The status the script should have for the condition to hold.
  optional ScriptStatusProto status = 2;

  // Optional. The comparison performed when checking the status. It will be
  // interpreted as EQUAL if not set.
  optional Comparator comparator = 3;
}

message ScriptPreconditionProto {
  // Combined with AND: the elements referenced here must be present.
  repeated ElementReferenceProto elements_exist = 3;
  // Pattern of the path parts of the URL, including query and '#''.
  repeated string path_pattern = 5;
  // Domain (exact match) excluding the last '/' character.
  repeated string domain = 6;
  // Combined with AND: all matches must be true for precondition to hold.
  repeated ScriptParameterMatchProto script_parameter_match = 7;
  repeated ScriptStatusMatchProto script_status_match = 8;
  repeated FormValueMatchProto form_value_match = 9;
}

message ScriptParameterMatchProto {
  // Parameter name, as found in the Intent, without prefix.
  optional string name = 4;

  // Checks whether the script parameter is present.
  optional bool exists = 2 [default = true];

  // Checks whether the script parameter has exact value. Empty or missing value
  // is treated as wildcard - any value will pass.
  optional string value_equals = 3;
}

message FormValueMatchProto {
  // Required. The selector associated to the form element whose value should be
  // checked.
  optional ElementReferenceProto element = 1;

  // Optional value. If specified, the element value must match the given value,
  // even if it's empty. If not specified, we just check that the element value
  // is non empty.
  optional string value = 2;
}

enum PolicyType {
  UNKNOWN_POLICY = 0;
  SCRIPT = 1;
}

message ScriptActionRequestProto {
  optional ClientContextProto client_context = 7;

  // Global payload from the previous response, possibly for another script.
  optional bytes global_payload = 8;

  // Script payload from the previous response, for the same script.
  //
  // For backward compatibility, for initial requests, forward the last returned
  // script_payload.
  optional bytes script_payload = 2;

  oneof request {
    InitialScriptActionsRequestProto initial_request = 4;
    NextScriptActionsRequestProto next_request = 5;
  }
}

// Initial request to get a script's actions.
message InitialScriptActionsRequestProto {
  message QueryProto {
    // The backend expects the |script_path| to be a repeated field. This field
    // is expected to contain only one element.
    repeated string script_path = 1;
    // The exact URL on which the script is triggered.
    optional string url = 2;
    optional PolicyType policy = 3;
  }
  optional QueryProto query = 3;

  repeated ScriptParameterProto script_parameters = 2;
}

// Next request to get a script's actions.
message NextScriptActionsRequestProto {
  // The result of processing each ActionProto from the previous response. This
  // field must be in the same order as the actions in the original response.
  // It may have less actions in case of failure.
  repeated ProcessedActionProto processed_actions = 1;
}

// Response of a script's actions.
message ActionsResponseProto {
  // Opaque data to send to the next ScriptActionRequestProto.
  optional bytes global_payload = 4;

  // Opaque data to send to the next ScriptActionRequestProto for the same
  // script.
  optional bytes script_payload = 2;

  // Actions to be performed in order.
  // Should stop processing as soon as an action fails.
  repeated ActionProto actions = 3;

  // List of scripts to update.
  //
  // The client is expected to update the cache of scripts with this new
  // information. No action is needed when this field is not set. If the field
  // is set with an empty list of scripts, then no script is eligible to run
  // anymore.
  //
  // Note: This is an intermediate solution and the logic associated with this
  // field will eventually be absorbed into the supports script response from
  // the backend.
  message UpdateScriptListProto { repeated SupportedScriptProto scripts = 1; }
  optional UpdateScriptListProto update_script_list = 5;
}

// An action could be performed.
message ActionProto {
  // Wait these many milliseconds before executing the action, if set.
  optional int32 action_delay_ms = 3;

  // Opaque data that should not be interpreted by the client. The client must
  // pass this back unchanged in the next request
  optional bytes server_payload = 4;

  oneof action_info {
    ClickProto click = 5;
    SetFormFieldValueProto set_form_value = 6;
    SelectOptionProto select_option = 7;
    NavigateProto navigate = 9;
    PromptProto prompt = 10;
    TellProto tell = 11;
    FocusElementProto focus_element = 12;
    WaitForDomProto wait_for_dom = 19;
    UseCreditCardProto use_card = 28;
    UseAddressProto use_address = 29;
    UploadDomProto upload_dom = 18;
    ShowProgressBarProto show_progress_bar = 24;
    HighlightElementProto highlight_element = 31;
    ShowDetailsProto show_details = 32;
    ResetProto reset = 34;
    StopProto stop = 35;
    GetPaymentInformationProto get_payment_information = 36;
    SetAttributeProto set_attribute = 37;
  }

  // Set to true to make the client remove any contextual information if the
  // script finishes with this action. It has no effect if there is any other
  // action sent to the client after this one. Default is false.
  optional bool clean_contextual_ui = 33;
}

// Result message used to send payment request related data to the server.
message PaymentDetails {
  optional string card_issuer_network = 1;
  // Whether the integrated terms and conditions approval checkbox was checked.
  optional bool is_terms_and_conditions_accepted = 2;
  // The email address of the payer.
  optional string payer_email = 3;
}

message ProcessedActionProto {
  // The action that was processed.
  optional ActionProto action = 1;

  optional ProcessedActionStatusProto status = 2;

  oneof result_data {
    PromptProto.Choice prompt_choice = 5;
    string html_source = 12;
    // Should be set as a result of GetPaymentInformationAction.
    PaymentDetails payment_details = 15;
  }
}

enum ProcessedActionStatusProto {
  UNKNOWN_ACTION_STATUS = 0;

  // Element could not be found.
  ELEMENT_RESOLUTION_FAILED = 1;

  // The action was applied successfully.
  ACTION_APPLIED = 2;

  // The action failed (generic error).
  OTHER_ACTION_STATUS = 3;

  // The action failed to get payment information.
  PAYMENT_REQUEST_ERROR = 4;

  // Server asked the client to execute an unknown or unsupported action.
  UNSUPPORTED_ACTION = 5;

  // The action decided to fallback to manual mode, stopping the script.
  //
  // This can happen:
  // - if an autofill action or an update details action cancels the script,
  //   possibly, not necessarily, as a result of a user action.
  // - if an interrupt explicitly stops the main script, for wait for dom
  MANUAL_FALLBACK = 6;

  // The WaitForDom action failed because an interrupt that ran during
  // that action failed.
  INTERRUPT_FAILED = 7;

  // The script was canceled by the user, while it was running.
  //
  // This only report such events that happen while a script is running. It can
  // affect any action. It is a signal that the action or script ran in an
  // abnormal situation and its outcome cannot be trusted.
  USER_ABORTED_ACTION = 8;
}

// The pseudo type values come from
// https://chromedevtools.github.io/devtools-protocol/tot/DOM#type-PseudoType.
enum PseudoType {
  UNDEFINED = 0;
  FIRST_LINE = 1;
  FIRST_LETTER = 2;
  BEFORE = 3;
  AFTER = 4;
  BACKDROP = 5;
  SELECTION = 6;
  FIRST_LINE_INHERITED = 7;
  SCROLLBAR = 8;
  SCROLLBAR_THUMB = 9;
  SCROLLBAR_BUTTON = 10;
  SCROLLBAR_TRACK = 11;
  SCROLLBAR_TRACK_PIECE = 12;
  SCROLLBAR_CORNER = 13;
  RESIZER = 14;
  INPUT_LIST_BUTTON = 15;
}

// A reference to an unique element on the page, possibly nested in frames.
message ElementReferenceProto {
  // A sequence of CSS selectors. Any non-final CSS selector is expected to
  // arrive at a frame or an iframe, i.e. an element that contains another
  // document.
  // APIs are free to reject element references that do not refer to unique
  // elements (i.e. resolve to more than one element on the page).
  repeated string selectors = 2;

  // An optional pseudo type. This pseudo type is associated to the final
  // element matched by |selector|, which means that we currently don't handle
  // matching an element inside a pseudo element.
  optional PseudoType pseudo_type = 3;
}

// Contain all arguments to perform a click.
message ClickProto {
  optional ElementReferenceProto element_to_click = 1;
}

// Contain all arguments to perform a select option action.
message SelectOptionProto {
  // The drop down element on which to select an option.
  optional ElementReferenceProto element = 2;
  // Value of the option to use.
  optional string selected_option = 3;
}

// Contain a localized text message from the server.
message TellProto {
  optional string message = 1;
}

// Contain all arguments to focus on an element.
message FocusElementProto {
  // Element to focus on.
  optional ElementReferenceProto element = 1;

  // Optional title to show in the status bar.
  optional string title = 2;

  // Restrict interaction to the area spanned by the given elements.
  //
  // Deprecated: use touchable_element_area instead. Ignored if
  // touchable_element_area is non-empty.
  repeated ElementReferenceProto deprecated_touchable_elements = 5;

  // Restrict interaction to a series of rectangular areas.
  optional ElementAreaProto touchable_element_area = 6;
}

// An area made up of rectangles whole border are made defined by the position
// of a given set of elements.
message ElementAreaProto {
  // A rectangle, drawn by one or more elements.
  //
  // The rectangle is the smallest rectangle that includes all listed elements.
  message Rectangle {
    repeated ElementReferenceProto elements = 1;

    // If true, the width of the rectangle always corresponds to the width of
    // the screen.
    optional bool full_width = 2;
  }
  repeated Rectangle rectangles = 1;
}

message AutofillStrings {
  optional string fill_manually = 1;

  optional string fill_form = 2;

  optional string check_form = 3;
}

// Fill a form with an address if there is, otherwise fail this action.
message UseAddressProto {
  // Message used to indicate what form fields should be filled with what
  // information coming from the address.
  message RequiredField {
    enum AddressField {
      UNDEFINED = 0;
      FIRST_NAME = 1;
      LAST_NAME = 2;
      FULL_NAME = 3;
      PHONE_NUMBER = 4;
      EMAIL = 5;
      ORGANIZATION = 6;
      COUNTRY_CODE = 7;
      REGION = 8;  // e.g. state
      STREET_ADDRESS = 9;
      LOCALITY = 10;  // e.g. city
      DEPENDANT_LOCALITY = 11;
      POSTAL_CODE = 12;
    }

    optional AddressField address_field = 1;

    optional ElementReferenceProto element = 2;

    // Whether we should simulate actual key presses when filling |element| with
    // its corresponding value.
    optional bool simulate_key_presses = 3;
  }

  // An optional name to allow to handle multiple addresses selection (for
  // instance a billing and a delivery address).
  optional string name = 1;

  // An optional message to show to the user when asking to select an address.
  // TODO(crbug.com/806868): Make the prompt a required field.
  optional string prompt = 2;

  // Reference to an element in the form that should be filled.
  optional ElementReferenceProto form_field_element = 4;

  // An optional list of fields that should be filled by this action.
  repeated RequiredField required_fields = 6;

  optional AutofillStrings strings = 8;
}

// Fill a form with a credit card if there is, otherwise fail this action.
message UseCreditCardProto {
  // An optional message to show to the user when asking to select a card.
  // TODO(crbug.com/806868): Make the prompt a required field.
  optional string prompt = 1;

  // A reference to the card number field in the form that should be filled.
  optional ElementReferenceProto form_field_element = 3;

  optional AutofillStrings strings = 8;
}

// Ask Chrome to wait for an element in the DOM. This can be used to only
// proceed to the next action once the page is ready.
message WaitForDomProto {
  // Fail after waiting this amount of time.
  optional int32 timeout_ms = 1;

  // The element to wait for.
  // TODO(crbug.com/806868): Use ElementReferenceProto instead.
  repeated string selectors = 2;

  // If true, run scripts flagged with 'interrupt=true' as soon as their
  // preconditions match.
  optional bool allow_interrupt = 3;
}

// Volatile upload of a portion of the dom for backend analysis, does not store
// anything.
message UploadDomProto {
  // The element that should be a root of uploaded DOM. If empty then the whole
  // page is returned.
  optional ElementReferenceProto tree_root = 1;
}

// Shows the progress bar.
message ShowProgressBarProto {
  // Specifies whether the progress is done and should be removed.
  optional bool done = 2;

  // Message to show on the progress bar while loading.
  optional string message = 3;

  // Value between 0 and 100 indicating the current progress. Values above 100
  // will be capped to 100, values below 0 will be capped to 0 by the client.
  // NOTE: Setting |progress| to 100 is an equivalent of setting |done| to true.
  optional int32 progress = 6;
}

// Contain all arguments to perform a highlight element action.
message HighlightElementProto {
  // The element to highlight.
  optional ElementReferenceProto element = 1;
}

// Load the given URL in the current tab.
message NavigateProto {
  optional string url = 1;
}

// Allow choosing one or more possibility. If FocusElement was called just
// before, allow interaction with the touchable element area, otherwise don't
// allow any interactions.
message PromptProto {
  // Display this message to the user.
  optional string message = 1;

  // A choice that is made either directly by clicking on a chip or button, or
  // implicitly by making a change on the website that is then detected by
  // looking for the existence of an element.
  //
  // One of these protos must is transmitted as-is back to the server as part of
  // ProcessedActionProto.
  message Choice {
    // Localized text message to display. Not required if element_exists is set.
    optional string name = 2;

    // If set, the choice should be highlighted. Ignored unless name is set.
    optional bool highlight = 3;

    // Optionally auto-select this choice if the given element exist.
    optional ElementReferenceProto element_exists = 4;

    // Server payload originally sent by the server. This should
    // be transmitted as-is by the client without interpreting.
    optional bytes server_payload = 5;

    // The chip is only visible if the given element exists.
    optional ElementReferenceProto show_only_if_element_exists = 6;
  }
  repeated Choice choices = 4;
}

message ContactDetailsProto {
  // Data saved under this name can be reused by UseAddressAction.
  optional string contact_details_name = 1;
  // If true asks user for full name.
  optional bool request_payer_name = 2;
  // If true asks user for email.
  optional bool request_payer_email = 3;
  // If true asks user for phone.
  optional bool request_payer_phone = 4;
}

// Asks to provide the data used by UseAddressAction and
// UseCreditCardAction.
message GetPaymentInformationProto {
  optional string prompt = 1;
  // NOTE: Payment request does not ask separately for billing address.
  // The billing address is associated with the credit card that was picked.
  optional string billing_address_name = 2;
  // If present will save the shipping address inside the memory under the
  // specified name. If empty we won't ask for the shipping address. Data saved
  // under this name can be reused by UseAddressAction.
  optional string shipping_address_name = 3;
  // When 'true' will ask for the credit card.
  optional bool ask_for_payment = 4;
  // If non-empty, the UI will filter the available basic-card networks
  // accordingly (e.g., only `visa' and `mastercard').
  repeated string supported_basic_card_networks = 6;
  // Contact details that should be gathered.
  optional ContactDetailsProto contact_details = 5;
}

// Resets Autofill Assistant: clears any state and server payload.
message ResetProto {}

// Stop Autofill Assistant.
message StopProto {}

message DateProto {
  optional int64 year = 1;

  // Month of the year in the range [1-12].
  optional int32 month = 2;

  // Day of the month in the range [1-31].
  optional int32 day = 3;
}

message TimeProto {
  // Hour in the range [0-23].
  optional int32 hour = 1;

  // Minute in the range [0-59].
  optional int32 minute = 2;

  // Second in the range [0-59].
  optional int32 second = 3;
}

message DateTimeProto {
  optional DateProto date = 1;
  optional TimeProto time = 2;
}

message DetailsChanges {
  // Whether the changes require user approval.
  optional bool user_approval_required = 1;

  // Whether the title should be highlighted.
  optional bool highlight_title = 2;

  // Whether the date should be highlighted.
  optional bool highlight_date = 3;
}

message DetailsProto {
  optional string title = 1;

  optional string url = 2;

  optional DateTimeProto datetime = 3;

  optional string description = 4;

  // Mid that comes from Knowledge Graph. Uniquely identify the object that this
  // proto describes.
  optional string m_id = 5;

  // Price label containing the total amount and the currency to pay, formatted
  // in the client's locale (e.g., $123.00).
  optional string total_price = 6;
}

// Show contextual information.
message ShowDetailsProto {
  optional DetailsProto details = 1;

  // Flags indicating which parts of the details (if any) have changed.
  optional DetailsChanges change_flags = 2;
}

// Set the value of an form element.
message SetFormFieldValueProto {
  message KeyPress {
    oneof keypress {
      // Text to insert as-is into a form field.
      string text = 1;
      // DEPRECATED: A single US-ASCII character (e.g., 13 for carriage return).
      int32 keycode = 2;
      // Text as generated by processing a virtual key code with a keyboard
      // layout. This can also be used for keyboard control sequences such
      // as "\r" or "\t".
      string keyboard_input = 3;
    }
  }

  // A reference to the form element whose value should be set.
  optional ElementReferenceProto element = 1;

  // The value to set.
  repeated KeyPress value = 2;
}

// Set an element attribute to a specific value.
message SetAttributeProto {
  // A reference to the form element whose attribute should be set.
  optional ElementReferenceProto element = 1;

  // The attribute to set, e.g. ["style", "position"] to change
  // element.style.position.
  repeated string attribute = 2;

  // The value to set.
  optional string value = 3;
}
