package org.commcare.adapters;

import androidx.appcompat.app.AppCompatActivity;

import org.commcare.cases.entity.Entity;
import org.commcare.cases.entity.NodeEntityFactory;
import org.javarosa.core.model.instance.TreeReference;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;

/**
 * Filter (and order) entities by those whose 'extra key', most likely case id,
 * is present in the provided ordered key set
 *
 * @author Phillip Mates (pmates@dimagi.com).
 */
public class EntityKeyFilterer extends EntityFiltererBase {
    private final LinkedHashSet<String> orderedKeySet;

    /**
     * @param orderedKeySet Keys that are used to filter and order the Entity
     *                      list based on the entity's 'extra key' field
     */
    public EntityKeyFilterer(EntityListAdapter adapter,
                             NodeEntityFactory nodeFactory,
                             List<Entity<TreeReference>> fullEntityList,
                             AppCompatActivity context, LinkedHashSet<String> orderedKeySet) {
        super(context, nodeFactory, adapter, fullEntityList);

        this.orderedKeySet = orderedKeySet;
    }

    @Override
    protected void filter() {
        if (isCancelled() || orderedKeySet.isEmpty()) {
            return;
        }

        // Add entities whose extra keys are in the key set, preserving key set
        // ordering. Don't assume one-to-one correspondence between entities
        // and keys: depending on the appliciation we might want to attach the
        // same data to multiple entities
        HashMap<String, List<Entity<TreeReference>>> keyToEntitiesMap =
                buildKeyToEntitiesMap(fullEntityList);
        for (String key : orderedKeySet) {
            if (keyToEntitiesMap.containsKey(key)) {
                matchList.addAll(keyToEntitiesMap.get(key));
            }
        }
    }

    /**
     * Group entities by their 'extra key' field
     *
     * @return A map from 'extra key' values to a list of entities that have
     * that 'extra key'
     */
    private static HashMap<String, List<Entity<TreeReference>>> buildKeyToEntitiesMap(List<Entity<TreeReference>> entityList) {
        // NOTE PLM: potentially expensive in presence of large entity set;
        // could build at entity load time or forgoe ordering or constrain the
        // key to entity mapping to be one-to-one
        HashMap<String, List<Entity<TreeReference>>> keyToEntitiesMap = new HashMap<>();
        for (Entity<TreeReference> entity : entityList) {
            if (keyToEntitiesMap.containsKey(entity.extraKey)) {
                keyToEntitiesMap.get(entity.extraKey).add(entity);
            } else {
                ArrayList<Entity<TreeReference>> list = new ArrayList<>();
                list.add(entity);
                keyToEntitiesMap.put(entity.extraKey, list);
            }
        }
        return keyToEntitiesMap;
    }
}
