/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.service.autofill;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;

import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Describes what happened after the last
 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
 * call.
 *
 * <p>This history is typically used to keep track of previous user actions to optimize further
 * requests. For example, the service might return email addresses in alphabetical order by
 * default, but change that order based on the address the user picked on previous requests.
 *
 * <p>The history is not persisted over reboots, and it's cleared every time the service
 * replies to a
 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
 * by calling {@link FillCallback#onSuccess(FillResponse)} or
 * {@link FillCallback#onFailure(CharSequence)} (if the service doesn't call any of these methods,
 * the history will clear out after some pre-defined time).
 */
public final class FillEventHistory implements Parcelable {
    /**
     * Not in parcel. The UID of the {@link AutofillService} that created the {@link FillResponse}.
     */
    private final int mServiceUid;

    /**
     * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
     */
    private final int mSessionId;

    @Nullable private final Bundle mClientState;
    @Nullable List<Event> mEvents;

    /**
     * Gets the UID of the {@link AutofillService} that created the {@link FillResponse}.
     *
     * @return The UID of the {@link AutofillService}
     *
     * @hide
     */
    public int getServiceUid() {
        return mServiceUid;
    }

    /** @hide */
    public int getSessionId() {
        return mSessionId;
    }

    /**
     * Returns the client state set in the previous {@link FillResponse}.
     *
     * <p><b>Note: </b>the state is associated with the app that was autofilled in the previous
     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
     * , which is not necessary the same app being autofilled now.
     *
     * @deprecated use {@link #getEvents()} then {@link Event#getClientState()} instead.
     */
    @Deprecated
    @Nullable public Bundle getClientState() {
        return mClientState;
    }

    /**
     * Returns the events occurred after the latest call to
     * {@link FillCallback#onSuccess(FillResponse)}.
     *
     * @return The list of events or {@code null} if non occurred.
     */
    @Nullable public List<Event> getEvents() {
        return mEvents;
    }

    /**
     * @hide
     */
    public void addEvent(Event event) {
        if (mEvents == null) {
            mEvents = new ArrayList<>(1);
        }
        mEvents.add(event);
    }

    /**
     * @hide
     */
    public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
        mClientState = clientState;
        mServiceUid = serviceUid;
        mSessionId = sessionId;
    }

    @Override
    public String toString() {
        return mEvents == null ? "no events" : mEvents.toString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeBundle(mClientState);
        if (mEvents == null) {
            dest.writeInt(0);
        } else {
            dest.writeInt(mEvents.size());

            int numEvents = mEvents.size();
            for (int i = 0; i < numEvents; i++) {
                Event event = mEvents.get(i);
                dest.writeInt(event.mEventType);
                dest.writeString(event.mDatasetId);
                dest.writeBundle(event.mClientState);
                dest.writeStringList(event.mSelectedDatasetIds);
                dest.writeArraySet(event.mIgnoredDatasetIds);
                dest.writeTypedList(event.mChangedFieldIds);
                dest.writeStringList(event.mChangedDatasetIds);

                dest.writeTypedList(event.mManuallyFilledFieldIds);
                if (event.mManuallyFilledFieldIds != null) {
                    final int size = event.mManuallyFilledFieldIds.size();
                    for (int j = 0; j < size; j++) {
                        dest.writeStringList(event.mManuallyFilledDatasetIds.get(j));
                    }
                }
                dest.writeString(event.mDetectedRemoteId);
                if (event.mDetectedRemoteId != null) {
                    dest.writeInt(event.mDetectedFieldScore);
                }
            }
        }
    }

    /**
     * Description of an event that occured after the latest call to
     * {@link FillCallback#onSuccess(FillResponse)}.
     */
    public static final class Event {
        /**
         * A dataset was selected. The dataset selected can be read from {@link #getDatasetId()}.
         *
         * <p><b>Note: </b>on Android {@link android.os.Build.VERSION_CODES#O}, this event was also
         * incorrectly reported after a
         * {@link Dataset.Builder#setAuthentication(IntentSender) dataset authentication} was
         * selected and the service returned a dataset in the
         * {@link AutofillManager#EXTRA_AUTHENTICATION_RESULT} of the activity launched from that
         * {@link IntentSender}. This behavior was fixed on Android
         * {@link android.os.Build.VERSION_CODES#O_MR1}.
         */
        public static final int TYPE_DATASET_SELECTED = 0;

        /**
         * A {@link Dataset.Builder#setAuthentication(IntentSender) dataset authentication} was
         * selected. The dataset authenticated can be read from {@link #getDatasetId()}.
         */
        public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1;

        /**
         * A {@link FillResponse.Builder#setAuthentication(android.view.autofill.AutofillId[],
         * IntentSender, android.widget.RemoteViews) fill response authentication} was selected.
         */
        public static final int TYPE_AUTHENTICATION_SELECTED = 2;

        /** A save UI was shown. */
        public static final int TYPE_SAVE_SHOWN = 3;

        /**
         * A committed autofill context for which the autofill service provided datasets.
         *
         * <p>This event is useful to track:
         * <ul>
         *   <li>Which datasets (if any) were selected by the user
         *       ({@link #getSelectedDatasetIds()}).
         *   <li>Which datasets (if any) were NOT selected by the user
         *       ({@link #getIgnoredDatasetIds()}).
         *   <li>Which fields in the selected datasets were changed by the user after the dataset
         *       was selected ({@link #getChangedFields()}.
         * </ul>
         *
         * <p><b>Note: </b>This event is only generated when:
         * <ul>
         *   <li>The autofill context is committed.
         *   <li>The service provides at least one dataset in the
         *       {@link FillResponse fill responses} associated with the context.
         *   <li>The last {@link FillResponse fill responses} associated with the context has the
         *       {@link FillResponse#FLAG_TRACK_CONTEXT_COMMITED} flag.
         * </ul>
         *
         * <p>See {@link android.view.autofill.AutofillManager} for more information about autofill
         * contexts.
         */
        // TODO(b/67867469): update with field detection behavior
        public static final int TYPE_CONTEXT_COMMITTED = 4;

        /** @hide */
        @IntDef(
                value = {TYPE_DATASET_SELECTED,
                        TYPE_DATASET_AUTHENTICATION_SELECTED,
                        TYPE_AUTHENTICATION_SELECTED,
                        TYPE_SAVE_SHOWN,
                        TYPE_CONTEXT_COMMITTED})
        @Retention(RetentionPolicy.SOURCE)
        @interface EventIds{}

        @EventIds private final int mEventType;
        @Nullable private final String mDatasetId;
        @Nullable private final Bundle mClientState;

        // Note: mSelectedDatasetIds is stored as List<> instead of Set because Session already
        // stores it as List
        @Nullable private final List<String> mSelectedDatasetIds;
        @Nullable private final ArraySet<String> mIgnoredDatasetIds;

        @Nullable private final ArrayList<AutofillId> mChangedFieldIds;
        @Nullable private final ArrayList<String> mChangedDatasetIds;

        @Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds;
        @Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;

        @Nullable private final String mDetectedRemoteId;
        private final int mDetectedFieldScore;

        /**
         * Returns the type of the event.
         *
         * @return The type of the event
         */
        public int getType() {
            return mEventType;
        }

        /**
         * Returns the id of dataset the id was on.
         *
         * @return The id of dataset, or {@code null} the event is not associated with a dataset.
         */
        @Nullable public String getDatasetId() {
            return mDatasetId;
        }

        /**
         * Returns the client state from the {@link FillResponse} used to generate this event.
         *
         * <p><b>Note: </b>the state is associated with the app that was autofilled in the previous
         * {@link
         * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)},
         * which is not necessary the same app being autofilled now.
         */
        @Nullable public Bundle getClientState() {
            return mClientState;
        }

        /**
         * Returns which datasets were selected by the user.
         *
         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
         */
        @NonNull public Set<String> getSelectedDatasetIds() {
            return mSelectedDatasetIds == null ? Collections.emptySet()
                    : new ArraySet<>(mSelectedDatasetIds);
        }

        /**
         * Returns which datasets were NOT selected by the user.
         *
         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
         */
        @NonNull public Set<String> getIgnoredDatasetIds() {
            return mIgnoredDatasetIds == null ? Collections.emptySet() : mIgnoredDatasetIds;
        }

        /**
         * Returns which fields in the selected datasets were changed by the user after the dataset
         * was selected.
         *
         * <p>For example, server provides:
         *
         * <pre class="prettyprint">
         *  FillResponse response = new FillResponse.Builder()
         *      .addDataset(new Dataset.Builder(presentation1)
         *          .setId("4815")
         *          .setValue(usernameId, AutofillValue.forText("MrPlow"))
         *          .build())
         *      .addDataset(new Dataset.Builder(presentation2)
         *          .setId("162342")
         *          .setValue(passwordId, AutofillValue.forText("D'OH"))
         *          .build())
         *      .build();
         * </pre>
         *
         * <p>User select both datasets (for username and password) but after the fields are
         * autofilled, user changes them to:
         *
         * <pre class="prettyprint">
         *   username = "ElBarto";
         *   password = "AyCaramba";
         * </pre>
         *
         * <p>Then the result is the following map:
         *
         * <pre class="prettyprint">
         *   usernameId => "4815"
         *   passwordId => "162342"
         * </pre>
         *
         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
         *
         * @return map map whose key is the id of the change fields, and value is the id of
         * dataset that has that field and was selected by the user.
         */
        @NonNull public Map<AutofillId, String> getChangedFields() {
            if (mChangedFieldIds == null || mChangedDatasetIds == null) {
                return Collections.emptyMap();
            }

            final int size = mChangedFieldIds.size();
            final ArrayMap<AutofillId, String> changedFields = new ArrayMap<>(size);
            for (int i = 0; i < size; i++) {
                changedFields.put(mChangedFieldIds.get(i), mChangedDatasetIds.get(i));
            }
            return changedFields;
        }

        /**
         * Gets the results of the last {@link FieldsDetection} request.
         *
         * @return map of edit-distance match ({@code 0} means full match,
         * {@code 1} means 1 character different, etc...) by remote id (as set in the
         * {@link FieldsDetection} constructor), or {@code null} if none of the user-input values
         * matched the requested detection.
         *
         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}, when the
         * service requested {@link FillResponse.Builder#setFieldsDetection(FieldsDetection) fields
         * detection}.
         *
         * TODO(b/67867469):
         *  - improve javadoc
         *  - refine score meaning (for example, should 1 be different of -1?)
         *  - mention when it's set
         *  - unhide
         *  - unhide / remove testApi
         *  - add @NonNull / check it / add unit tests
         *
         * @hide
         */
        @TestApi
        @NonNull public Map<String, Integer> getDetectedFields() {
            if (mDetectedRemoteId == null || mDetectedFieldScore == -1) {
                return Collections.emptyMap();
            }

            final ArrayMap<String, Integer> map = new ArrayMap<>(1);
            map.put(mDetectedRemoteId, mDetectedFieldScore);
            return map;
        }

        /**
         * Returns which fields were available on datasets provided by the service but manually
         * entered by the user.
         *
         * <p>For example, server provides:
         *
         * <pre class="prettyprint">
         *  FillResponse response = new FillResponse.Builder()
         *      .addDataset(new Dataset.Builder(presentation1)
         *          .setId("4815")
         *          .setValue(usernameId, AutofillValue.forText("MrPlow"))
         *          .setValue(passwordId, AutofillValue.forText("AyCaramba"))
         *          .build())
         *      .addDataset(new Dataset.Builder(presentation2)
         *          .setId("162342")
         *          .setValue(usernameId, AutofillValue.forText("ElBarto"))
         *          .setValue(passwordId, AutofillValue.forText("D'OH"))
         *          .build())
         *      .addDataset(new Dataset.Builder(presentation3)
         *          .setId("108")
         *          .setValue(usernameId, AutofillValue.forText("MrPlow"))
         *          .setValue(passwordId, AutofillValue.forText("D'OH"))
         *          .build())
         *      .build();
         * </pre>
         *
         * <p>User doesn't select a dataset but manually enters:
         *
         * <pre class="prettyprint">
         *   username = "MrPlow";
         *   password = "D'OH";
         * </pre>
         *
         * <p>Then the result is the following map:
         *
         * <pre class="prettyprint">
         *   usernameId => { "4815", "108"}
         *   passwordId => { "162342", "108" }
         * </pre>
         *
         * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}.
         *
         * @return map map whose key is the id of the manually-entered field, and value is the
         * ids of the datasets that have that value but were not selected by the user.
         */
        @Nullable public Map<AutofillId, Set<String>> getManuallyEnteredField() {
            if (mManuallyFilledFieldIds == null || mManuallyFilledDatasetIds == null) {
                return Collections.emptyMap();
            }

            final int size = mManuallyFilledFieldIds.size();
            final Map<AutofillId, Set<String>> manuallyFilledFields = new ArrayMap<>(size);
            for (int i = 0; i < size; i++) {
                final AutofillId fieldId = mManuallyFilledFieldIds.get(i);
                final ArrayList<String> datasetIds = mManuallyFilledDatasetIds.get(i);
                manuallyFilledFields.put(fieldId, new ArraySet<>(datasetIds));
            }
            return manuallyFilledFields;
        }

        /**
         * Creates a new event.
         *
         * @param eventType The type of the event
         * @param datasetId The dataset the event was on, or {@code null} if the event was on the
         *                  whole response.
         * @param clientState The client state associated with the event.
         * @param selectedDatasetIds The ids of datasets selected by the user.
         * @param ignoredDatasetIds The ids of datasets NOT select by the user.
         * @param changedFieldIds The ids of fields changed by the user.
         * @param changedDatasetIds The ids of the datasets that havd values matching the
         * respective entry on {@code changedFieldIds}.
         * @param manuallyFilledFieldIds The ids of fields that were manually entered by the user
         * and belonged to datasets.
         * @param manuallyFilledDatasetIds The ids of datasets that had values matching the
         * respective entry on {@code manuallyFilledFieldIds}.
         * @throws IllegalArgumentException If the length of {@code changedFieldIds} and
         * {@code changedDatasetIds} doesn't match.
         * @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
         * {@code manuallyFilledDatasetIds} doesn't match.
         *
         * @hide
         */
        // TODO(b/67867469): document detection field parameters once stable
        public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
                @Nullable List<String> selectedDatasetIds,
                @Nullable ArraySet<String> ignoredDatasetIds,
                @Nullable ArrayList<AutofillId> changedFieldIds,
                @Nullable ArrayList<String> changedDatasetIds,
                @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
                @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
                @Nullable String detectedRemoteId, int detectedFieldScore) {
            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
                    "eventType");
            mDatasetId = datasetId;
            mClientState = clientState;
            mSelectedDatasetIds = selectedDatasetIds;
            mIgnoredDatasetIds = ignoredDatasetIds;
            if (changedFieldIds != null) {
                Preconditions.checkArgument(!ArrayUtils.isEmpty(changedFieldIds)
                        && changedDatasetIds != null
                        && changedFieldIds.size() == changedDatasetIds.size(),
                        "changed ids must have same length and not be empty");
            }
            mChangedFieldIds = changedFieldIds;
            mChangedDatasetIds = changedDatasetIds;
            if (manuallyFilledFieldIds != null) {
                Preconditions.checkArgument(!ArrayUtils.isEmpty(manuallyFilledFieldIds)
                        && manuallyFilledDatasetIds != null
                        && manuallyFilledFieldIds.size() == manuallyFilledDatasetIds.size(),
                        "manually filled ids must have same length and not be empty");
            }
            mManuallyFilledFieldIds = manuallyFilledFieldIds;
            mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
            mDetectedRemoteId = detectedRemoteId;
            mDetectedFieldScore = detectedFieldScore;
        }

        @Override
        public String toString() {
            return "FillEvent [datasetId=" + mDatasetId
                    + ", type=" + mEventType
                    + ", selectedDatasets=" + mSelectedDatasetIds
                    + ", ignoredDatasetIds=" + mIgnoredDatasetIds
                    + ", changedFieldIds=" + mChangedFieldIds
                    + ", changedDatasetsIds=" + mChangedDatasetIds
                    + ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
                    + ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
                    + ", detectedRemoteId=" + mDetectedRemoteId
                    + ", detectedFieldScore=" + mDetectedFieldScore
                    + "]";
        }
    }

    public static final Parcelable.Creator<FillEventHistory> CREATOR =
            new Parcelable.Creator<FillEventHistory>() {
                @Override
                public FillEventHistory createFromParcel(Parcel parcel) {
                    FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());

                    final int numEvents = parcel.readInt();
                    for (int i = 0; i < numEvents; i++) {
                        final int eventType = parcel.readInt();
                        final String datasetId = parcel.readString();
                        final Bundle clientState = parcel.readBundle();
                        final ArrayList<String> selectedDatasetIds = parcel.createStringArrayList();
                        @SuppressWarnings("unchecked")
                        final ArraySet<String> ignoredDatasets =
                                (ArraySet<String>) parcel.readArraySet(null);
                        final ArrayList<AutofillId> changedFieldIds =
                                parcel.createTypedArrayList(AutofillId.CREATOR);
                        final ArrayList<String> changedDatasetIds = parcel.createStringArrayList();

                        final ArrayList<AutofillId> manuallyFilledFieldIds =
                                parcel.createTypedArrayList(AutofillId.CREATOR);
                        final ArrayList<ArrayList<String>> manuallyFilledDatasetIds;
                        if (manuallyFilledFieldIds != null) {
                            final int size = manuallyFilledFieldIds.size();
                            manuallyFilledDatasetIds = new ArrayList<>(size);
                            for (int j = 0; j < size; j++) {
                                manuallyFilledDatasetIds.add(parcel.createStringArrayList());
                            }
                        } else {
                            manuallyFilledDatasetIds = null;
                        }
                        final String detectedRemoteId = parcel.readString();
                        final int detectedFieldScore = detectedRemoteId == null ? -1
                                : parcel.readInt();

                        selection.addEvent(new Event(eventType, datasetId, clientState,
                                selectedDatasetIds, ignoredDatasets,
                                changedFieldIds, changedDatasetIds,
                                manuallyFilledFieldIds, manuallyFilledDatasetIds,
                                detectedRemoteId, detectedFieldScore));
                    }
                    return selection;
                }

                @Override
                public FillEventHistory[] newArray(int size) {
                    return new FillEventHistory[size];
                }
            };
}
