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;
}
}