package com.buddycloud.fragments.adapter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.Semaphore; import org.json.JSONArray; import org.json.JSONObject; import android.annotation.SuppressLint; import android.content.Context; import android.view.View; import android.widget.ExpandableListView; import android.widget.ProgressBar; import android.widget.Toast; import com.buddycloud.R; import com.buddycloud.fragments.GenericChannelsFragment; import com.buddycloud.model.ChannelMetadataModel; import com.buddycloud.model.ModelCallback; import com.buddycloud.model.SearchChannelsModel; import com.buddycloud.model.SubscribedChannelsModel; import com.buddycloud.preferences.Preferences; public class SearchChannelsAdapter extends GenericChannelAdapter { private static final String PERSONAL = "PERSONAL"; private static final String SUBSCRIBED = "SUBSCRIBED"; private static final String METADATA_SEARCH = "METADATA SEARCH"; private static final String CONTENT_SEARCH = "CONTENT SEARCH"; private static final int SEARCH_THRESHOLD = 5; private final List<String> allSubscribedChannels = new ArrayList<String>(); private final Map<String, String> plainMetadata = new HashMap<String, String>(); private String myChannel; private View view; private boolean remoteSearch = true; private List<String> affiliationsToDisplay = new LinkedList<String>(); private JSONObject allAffiliations; public SearchChannelsAdapter() { setCategoryOrder(PERSONAL, SUBSCRIBED, METADATA_SEARCH, CONTENT_SEARCH); } @Override public void configure(View view) { super.configure(view); } public String getTitle(final Context context) { return (context != null) ? context.getResources().getString(R.string.menu_search) : null; } public void addAffiliationToDisplay(String affiliation) { this.affiliationsToDisplay.add(affiliation); } public void enableRemoteSearch(boolean enabled) { this.remoteSearch = enabled; } @Override public void load(final Context context) { this.myChannel = Preferences.getPreference(context, Preferences.MY_CHANNEL_JID); JSONObject subscriptions = SubscribedChannelsModel.getInstance().getFromCache(context); JSONArray channels = subscriptions.names(); if (channels == null) { return; } for (int i = 0; i < channels.length(); i++) { final String channel = channels.optString(i); allSubscribedChannels.add(channel); JSONObject metadata = ChannelMetadataModel.getInstance().getFromCache(context, channel); plainMetadata.put(channel, getPlainMetadata(context, metadata)); } if (!affiliationsToDisplay.isEmpty()) { this.allAffiliations = SubscribedChannelsModel.getInstance().getFromCache(context); } filter(context, ""); notifyDataSetChanged(); } @SuppressLint("DefaultLocale") public void filter(final Context context, String q) { setLoading(context); clearChannels(); int matchedChannels = 0; for (String channel : allSubscribedChannels) { String channelPlainMetadata = plainMetadata.get(channel); String lowerQ = low(q); if (!low(channel).contains(lowerQ) && !low(channelPlainMetadata).contains(lowerQ)) { continue; } if (!channel.equals(myChannel)) { if (affiliationsToDisplay.isEmpty() || affiliationsToDisplay.contains(getRole(context, channel))) { addChannel(SUBSCRIBED, createChannelItem(channel), context); } } else { addChannel(PERSONAL, createChannelItem(channel), context); } matchedChannels++; } if (matchedChannels <= SEARCH_THRESHOLD && q.length() > 0 && remoteSearch) { setLoading(context); Semaphore s = new Semaphore(1); search(context, q, SearchChannelsModel.METADATA_TYPE, METADATA_SEARCH, s); search(context, q, SearchChannelsModel.POST_TYPE, CONTENT_SEARCH, s); } } private String getRole(Context context, String channelJid) { return allAffiliations.optString(channelJid, ""); } private static String low(String q) { return q.toLowerCase(Locale.US); } @SuppressWarnings("unchecked") private String getPlainMetadata(final Context context, JSONObject metadata) { if (metadata == null) { return ""; } Iterator<String> keys = metadata.keys(); StringBuilder allValues = new StringBuilder(); while (keys.hasNext()) { String key = keys.next(); allValues.append(metadata.optString(key)); } return allValues.toString(); } private void search(final Context context, String q, String type, final String category, final Semaphore s) { SearchChannelsModel.getInstance().getFromServer(context, new ModelCallback<JSONArray>() { @Override public void success(JSONArray response) { for (int i = 0; i < response.length(); i++) { JSONObject channelItem = response.optJSONObject(i); String channelJid = channelItem.optString("jid"); if (!hasChannel(channelJid)) { addChannel(category, channelItem, context); } } if (!s.tryAcquire()) { setLoaded(context, response.length() == 0); } } @Override public void error(Throwable throwable) { Toast.makeText(context, context.getString( R.string.message_search_failed), Toast.LENGTH_LONG).show(); if (!s.tryAcquire()) { setLoaded(context, true); } } }, type, q); } private void setLoading(final Context context) { ProgressBar progressBar = (ProgressBar)view.findViewById(R.id.channelListProgress); ExpandableListView elv = (ExpandableListView)view.findViewById(R.id.channelListView); View noResultsFound = view.findViewById(R.id.channelListEmpty); if (elv != null) { progressBar.setVisibility(View.VISIBLE); elv.setEmptyView(progressBar); if (noResultsFound != null) { noResultsFound.setVisibility(View.GONE); } } } private void setLoaded(final Context context, final boolean isShow) { ProgressBar progressBar = (ProgressBar)view.findViewById(R.id.channelListProgress); progressBar.setVisibility(View.GONE); if (isShow) { showNoResultsFoundView(context.getString(R.string.message_search_no_result)); } } public void configure(GenericChannelsFragment genericChannelFrag, View view) { this.view = view; } }