package org.mercury_im.messenger.ui.util;

import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;

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

public abstract class AbstractRecyclerViewAdapter<M, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {

    private final List<M> models = new ArrayList<>();
    private final AbstractDiffCallback<M> diffCallback;

    public AbstractRecyclerViewAdapter(AbstractDiffCallback<M> diffCallback) {
        this.diffCallback = diffCallback;
    }

    public void setModels(List<M> newModels) {
        diffCallback.setData(this.models, newModels);
        DiffUtil.DiffResult delta = DiffUtil.calculateDiff(diffCallback, diffCallback.detectMoves);
        this.models.clear();
        this.models.addAll(newModels);
        delta.dispatchUpdatesTo(this);
    }

    public List<M> getModels() {
        return models;
    }

    public M getItemAt(int position) {
        return getModels().get(position);
    }

    @Override
    public int getItemCount() {
        return models.size();
    }

    public abstract static class AbstractDiffCallback<I> extends DiffUtil.Callback {

        private List<I> oldData;
        private List<I> newData;
        private boolean detectMoves;

        public AbstractDiffCallback(boolean detectMoves) {
            this.detectMoves = detectMoves;
        }

        public void setData(List<I> oldData, List<I> newData) {
            this.oldData = oldData;
            this.newData = newData;
        }

        public I oldItemAt(int index) {
            return oldData.get(index);
        }

        public I newItemAt(int index) {
            return newData.get(index);
        }

        @Override
        public int getOldListSize() {
            return oldData.size();
        }

        @Override
        public int getNewListSize() {
            return newData.size();
        }

        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            return areItemsTheSame(oldItemAt(oldItemPosition), newItemAt(newItemPosition));
        }

        public abstract boolean areItemsTheSame(I oldItem, I newItem);

        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            return areContentsTheSame(oldItemAt(oldItemPosition), newItemAt(newItemPosition));
        }

        public abstract boolean areContentsTheSame(I oldItem, I newItem);
    }
}
