/*
 * Copyright (C) 2019 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.util;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;

import java.util.function.Consumer;

/**
 * A sparse array of ArrayMaps, which is suitable for holding (userId, packageName)->object
 * associations.
 *
 * @param <K> Any class
 * @param <V> Any class
 * @hide
 */
@TestApi
public class SparseArrayMap<K, V> {
    private final SparseArray<ArrayMap<K, V>> mData = new SparseArray<>();

    /**
     * Add an entry associating obj with the int-K pair.
     *
     * @return the previous value associated with key, or null if there was no mapping for key.
     * (A null return can also indicate that the map previously associated null with key, if the
     * implementation supports null values.)
     */
    public V add(int key, @NonNull K mapKey, @Nullable V obj) {
        ArrayMap<K, V> data = mData.get(key);
        if (data == null) {
            data = new ArrayMap<>();
            mData.put(key, data);
        }
        return data.put(mapKey, obj);
    }

    /** Remove all entries from the map. */
    public void clear() {
        for (int i = 0; i < mData.size(); ++i) {
            mData.valueAt(i).clear();
        }
    }

    /** Return true if the structure contains an explicit entry for the int-K pair. */
    public boolean contains(int key, @NonNull K mapKey) {
        return mData.contains(key) && mData.get(key).containsKey(mapKey);
    }

    /** Removes all the data for the key, if there was any. */
    public void delete(int key) {
        mData.delete(key);
    }

    /**
     * Removes all the data for the keyIndex, if there was any.
     * @hide
     */
    public void deleteAt(int keyIndex) {
        mData.removeAt(keyIndex);
    }

    /**
     * Removes the data for the key and mapKey, if there was any.
     *
     * @return Returns the value that was stored under the keys, or null if there was none.
     */
    @Nullable
    public V delete(int key, @NonNull K mapKey) {
        ArrayMap<K, V> data = mData.get(key);
        if (data != null) {
            return data.remove(mapKey);
        }
        return null;
    }

    /**
     * Removes the data for the keyIndex and mapIndex, if there was any.
     * @hide
     */
    public void deleteAt(int keyIndex, int mapIndex) {
        mData.valueAt(keyIndex).removeAt(mapIndex);
    }

    /**
     * Get the value associated with the int-K pair.
     */
    @Nullable
    public V get(int key, @NonNull K mapKey) {
        ArrayMap<K, V> data = mData.get(key);
        if (data != null) {
            return data.get(mapKey);
        }
        return null;
    }

    /**
     * Returns the value to which the specified key and mapKey are mapped, or defaultValue if this
     * map contains no mapping for them.
     */
    @Nullable
    public V getOrDefault(int key, @NonNull K mapKey, V defaultValue) {
        if (mData.contains(key)) {
            ArrayMap<K, V> data = mData.get(key);
            if (data != null && data.containsKey(mapKey)) {
                return data.get(mapKey);
            }
        }
        return defaultValue;
    }

    /** @see SparseArray#indexOfKey */
    public int indexOfKey(int key) {
        return mData.indexOfKey(key);
    }

    /**
     * Returns the index of the mapKey.
     *
     * @see SparseArray#indexOfKey
     */
    public int indexOfKey(int key, @NonNull K mapKey) {
        ArrayMap<K, V> data = mData.get(key);
        if (data != null) {
            return data.indexOfKey(mapKey);
        }
        return -1;
    }

    /** Returns the key at the given index. */
    public int keyAt(int index) {
        return mData.keyAt(index);
    }

    /** Returns the map's key at the given mapIndex for the given keyIndex. */
    @NonNull
    public K keyAt(int keyIndex, int mapIndex) {
        return mData.valueAt(keyIndex).keyAt(mapIndex);
    }

    /** Returns the size of the outer array. */
    public int numMaps() {
        return mData.size();
    }

    /** Returns the number of elements in the map of the given key. */
    public int numElementsForKey(int key) {
        ArrayMap<K, V> data = mData.get(key);
        return data == null ? 0 : data.size();
    }

    /**
     * Returns the number of elements in the map of the given keyIndex.
     * @hide
     */
    public int numElementsForKeyAt(int keyIndex) {
        ArrayMap<K, V> data = mData.valueAt(keyIndex);
        return data == null ? 0 : data.size();
    }

    /** Returns the value V at the given key and map index. */
    @Nullable
    public V valueAt(int keyIndex, int mapIndex) {
        return mData.valueAt(keyIndex).valueAt(mapIndex);
    }

    /** Iterate through all int-K pairs and operate on all of the values. */
    public void forEach(@NonNull Consumer<V> consumer) {
        for (int i = numMaps() - 1; i >= 0; --i) {
            ArrayMap<K, V> data = mData.valueAt(i);
            for (int j = data.size() - 1; j >= 0; --j) {
                consumer.accept(data.valueAt(j));
            }
        }
    }

    /**
     * @param <K> Any class
     * @param <V> Any class
     * @hide
     */
    public interface TriConsumer<K, V> {
        /** Consume the int-K-V tuple. */
        void accept(int key, K mapKey, V value);
    }

    /**
     * Iterate through all int-K pairs and operate on all of the values.
     * @hide
     */
    public void forEach(@NonNull TriConsumer<K, V> consumer) {
        for (int iIdx = numMaps() - 1; iIdx >= 0; --iIdx) {
            final int i = mData.keyAt(iIdx);
            final ArrayMap<K, V> data = mData.valueAt(iIdx);
            for (int kIdx = data.size() - 1; kIdx >= 0; --kIdx) {
                consumer.accept(i, data.keyAt(kIdx), data.valueAt(kIdx));
            }
        }
    }
}
