package com.fsck.k9.activity;

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

import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Filter;

import com.fsck.k9.K9;

/**
 * Filter to search for occurences of the search-expression in any place of the
 * folder-name instead of doing jsut a prefix-search.
 *
 * @author Marcus@Wolschon.biz
 */
public class FolderListFilter<T> extends Filter {
    /**
     * ArrayAdapter that contains the list of folders displayed in the
     * ListView.
     * This object is modified by {@link #publishResults} to reflect the
     * changes due to the filtering performed by {@link #performFiltering}.
     * This in turn will change the folders displayed in the ListView.
     */
    private ArrayAdapter<T> mFolders;

    /**
     * All folders.
     */
    private ArrayList<T> mOriginalValues = null;

    /**
     * Create a filter for a list of folders.
     *
     * @param folderNames
     */
    public FolderListFilter(final ArrayAdapter<T> folderNames) {
        this.mFolders = folderNames;
    }

    /**
     * Do the actual search.
     * {@inheritDoc}
     *
     * @see #publishResults(CharSequence, FilterResults)
     */
    @Override
    protected FilterResults performFiltering(CharSequence searchTerm) {
        FilterResults results = new FilterResults();

        // Copy the values from mFolders to mOriginalValues if this is the
        // first time this method is called.
        if (mOriginalValues == null) {
            int count = mFolders.getCount();
            mOriginalValues = new ArrayList<T>(count);
            for (int i = 0; i < count; i++) {
                mOriginalValues.add(mFolders.getItem(i));
            }
        }

        if ((searchTerm == null) || (searchTerm.length() == 0)) {
            ArrayList<T> list = new ArrayList<T>(mOriginalValues);
            results.values = list;
            results.count = list.size();
        } else {
            final String searchTermString = searchTerm.toString().toLowerCase();
            final String[] words = searchTermString.split(" ");
            final int wordCount = words.length;

            final ArrayList<T> values = mOriginalValues;

            final ArrayList<T> newValues = new ArrayList<T>();

            for (final T value : values) {
                final String valueText = value.toString().toLowerCase();

                for (int k = 0; k < wordCount; k++) {
                    if (valueText.contains(words[k])) {
                        newValues.add(value);
                        break;
                    }
                }
            }

            results.values = newValues;
            results.count = newValues.size();
        }

        return results;
    }

    /**
     * Publish the results to the user-interface.
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        // Don't notify for every change
        mFolders.setNotifyOnChange(false);
        try {

            //noinspection unchecked
            final List<T> folders = (List<T>) results.values;
            mFolders.clear();
            if (folders != null) {
                for (T folder : folders) {
                    if (folder != null) {
                        mFolders.add(folder);
                    }
                }
            } else {
                Log.w(K9.LOG_TAG, "FolderListFilter.publishResults - null search-result ");
            }

            // Send notification that the data set changed now
            mFolders.notifyDataSetChanged();
        } finally {
            // restore notification status
            mFolders.setNotifyOnChange(true);
        }
    }

    public void invalidate() {
        mOriginalValues = null;
    }
}
