<commit_before>package com.miguelgaeta.bootstrap.mg_recycler;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import lombok.NonNull;
import rx.functions.Func1;

/**
 * Created by <NAME> on 5/2/15.
 */
public class MGRecyclerAdapterDataList<T> {

    private MGRecyclerAdapterData<List<T>> data;

    /**
     * Convenience class that represents an arbitrary object
     * list that drives an adapter.
     *
     * When new data is provided to this object, the associated
     * adapter (which should be drive by the list) will
     * be updated by this helper class which will compute
     * the minimal notify changed needed.
     *
     * A key generator is provided so that a unique
     * key can be generated for each object in the list.  There
     * should not be any duplicate keys in a given data list.
     */
    public static <T> MGRecyclerAdapterDataList<T> create(@NonNull MGRecyclerAdapter adapter, List<T> initialData, Func1<T, String> keyGenerator) {

        MGRecyclerAdapterDataList<T> dataList = new MGRecyclerAdapterDataList<>();

        dataList.data = MGRecyclerAdapterData.create(initialData, (oldData, newData) -> {

            LinkedHashMap<String, Integer> oldDataIndexes = dataList.generateIndexMap(oldData, keyGenerator);
            LinkedHashMap<String, Integer> newDataIndexes = dataList.generateIndexMap(newData, keyGenerator);

            dataList.changeItems(adapter, oldDataIndexes, newDataIndexes);

            dataList.removeItems(adapter, oldData, newDataIndexes, keyGenerator);
            dataList.insertItems(adapter, newData, oldDataIndexes, keyGenerator);
        });

        return dataList;
    }

    /**
     * Set a new data list.  Computes all the
     * changes and calls the associated
     * adapter functions.
     */
    public void setData(List<T> data) {

        this.data.setData(data);
    }

    /**
     * Grab the current data list.
     */
    public List<T> getData() {

        return data.getData();
    }

    /**
     * Figure out which items were changed in the list.  Potentially
     * someday this function can do a more comprehensive
     * analysis and do actual item moves instead of just
     * notifying that the item at index has changed.
     */
    private void changeItems(MGRecyclerAdapter adapter, LinkedHashMap<String, Integer> oldDataIndexes, LinkedHashMap<String, Integer> newDataIndexes) {

        List<String> keys = new ArrayList<>(oldDataIndexes.keySet());

        for (int i = 0; i < oldDataIndexes.size(); i++) {

            String key = keys.get(i);

            if (newDataIndexes.containsKey(key)) {

                int oldIndex = oldDataIndexes.get(key);
                int newIndex = newDataIndexes.get(key);

                if (oldIndex != newIndex) {

                    adapter.notifyItemChanged(oldIndex);
                }
            }
        }
    }<commit_msg>Updated changed item logic.<commit_after>package com.miguelgaeta.bootstrap.mg_recycler;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import lombok.NonNull;
import lombok.Setter;
import rx.functions.Func1;

/**
 * Created by <NAME> on 5/2/15.
 *
 * TODO: int lastFirstVisiblePosition = ((LinearLayoutManager)getRecycler().getLayoutManager()).findFirstCompletelyVisibleItemPosition();
 */
public class MGRecyclerAdapterDataList<T> {

    private MGRecyclerAdapterData<List<T>> data;

    @Setter
    private MGRecyclerAdapterData.DataUpdated<List<T>> updated;

    /**
     * Convenience class that represents an arbitrary object
     * list that drives an adapter.
     *
     * When new data is provided to this object, the associated
     * adapter (which should be drive by the list) will
     * be updated by this helper class which will compute
     * the minimal notify changed needed.
     *
     * A key generator is provided so that a unique
     * key can be generated for each object in the list.  There
     * should not be any duplicate keys in a given data list.
     */
    public static <T> MGRecyclerAdapterDataList<T> create(@NonNull MGRecyclerAdapter adapter, List<T> initialData, Func1<T, String> keyGenerator) {

        MGRecyclerAdapterDataList<T> dataList = new MGRecyclerAdapterDataList<>();

        dataList.data = MGRecyclerAdapterData.create(initialData, (oldData, newData) -> {

            LinkedHashMap<String, Integer> oldDataIndexes = dataList.generateIndexMap(oldData, keyGenerator);
            LinkedHashMap<String, Integer> newDataIndexes = dataList.generateIndexMap(newData, keyGenerator);

            dataList.changeItems(adapter, oldDataIndexes, newDataIndexes, oldData, newData);

            dataList.removeItems(adapter, oldData, newDataIndexes, keyGenerator);
            dataList.insertItems(adapter, newData, oldDataIndexes, keyGenerator);

            if (dataList.updated != null) {
                dataList.updated.updated(oldData, newData);
            }
        });

        return dataList;
    }

    /**
     * Set a new data list.  Computes all the
     * changes and calls the associated
     * adapter functions.
     */
    public void setData(List<T> data) {

        this.data.setData(data);
    }

    /**
     * Grab the current data list.
     */
    public List<T> getData() {

        return data.getData();
    }

    /**
     * Figure out which items were changed in the list.  Potentially
     * someday this function can do a more comprehensive
     * analysis and do actual item moves instead of just
     * notifying that the item at index has changed.
     */
    private void changeItems(MGRecyclerAdapter adapter, LinkedHashMap<String, Integer> oldDataIndexes, LinkedHashMap<String, Integer> newDataIndexes, List<T> oldData, List<T> newData) {

        List<String> keys = new ArrayList<>(oldDataIndexes.keySet());

        for (int i = 0; i < oldDataIndexes.size(); i++) {

            String key = keys.get(i);

            if (newDataIndexes.containsKey(key)) {

                int oldIndex = oldDataIndexes.get(key);
                int newIndex = newDataIndexes.get(key);

                T oldDataItem = oldData.get(oldIndex);
                T newDataItem = newData.get(newIndex);

                if (oldDataItem == null ? newDataItem != null : !oldDataItem.equals(newDataItem)) {

                    adapter.notifyItemChanged(oldIndex);
                }
            }
        }
    }
{'fraction_non_alphanumeric': 0.09023024268823895, 'fraction_numerical': 0.0021779713752333543, 'mean_word_length': 2.692705341757611, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '988542', 'n_tokens_mistral': 1838, 'n_tokens_neox': 1752, 'n_words': 519}