package com.quickblox.sample.chat.utils.chat;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import com.quickblox.auth.session.QBSettings;
import com.quickblox.chat.QBChatService;
import com.quickblox.chat.QBRestChatService;
import com.quickblox.chat.model.QBAttachment;
import com.quickblox.chat.model.QBChatDialog;
import com.quickblox.chat.model.QBChatMessage;
import com.quickblox.chat.model.QBDialogType;
import com.quickblox.chat.request.QBDialogRequestBuilder;
import com.quickblox.chat.utils.DialogUtils;
import com.quickblox.content.QBContent;
import com.quickblox.content.model.QBFile;
import com.quickblox.core.LogLevel;
import com.quickblox.core.QBEntityCallback;
import com.quickblox.core.QBProgressCallback;
import com.quickblox.core.exception.QBResponseException;
import com.quickblox.core.helper.StringifyArrayList;
import com.quickblox.core.request.QBPagedRequestBuilder;
import com.quickblox.core.request.QBRequestGetBuilder;
import com.quickblox.messages.services.SubscribeService;
import com.quickblox.sample.chat.App;
import com.quickblox.sample.chat.R;
import com.quickblox.sample.chat.models.SampleConfigs;
import com.quickblox.sample.chat.ui.activity.DialogsActivity;
import com.quickblox.sample.chat.utils.qb.QbDialogHolder;
import com.quickblox.sample.chat.utils.qb.QbDialogUtils;
import com.quickblox.sample.chat.utils.qb.QbUsersHolder;
import com.quickblox.sample.chat.utils.qb.callback.QbEntityCallbackTwoTypeWrapper;
import com.quickblox.sample.chat.utils.qb.callback.QbEntityCallbackWrapper;
import com.quickblox.sample.core.utils.Toaster;
import com.quickblox.users.QBUsers;
import com.quickblox.users.model.QBUser;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.muc.DiscussionHistory;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class ChatHelper {
private static final String TAG = ChatHelper.class.getSimpleName();
public static final int DIALOG_ITEMS_PER_PAGE = 100;
public static final int CHAT_HISTORY_ITEMS_PER_PAGE = 50;
private static final String CHAT_HISTORY_ITEMS_SORT_FIELD = "date_sent";
private static ChatHelper instance;
private QBChatService qbChatService;
public static synchronized ChatHelper getInstance() {
if (instance == null) {
QBSettings.getInstance().setLogLevel(LogLevel.DEBUG);
QBChatService.setDebugEnabled(true);
QBChatService.setConfigurationBuilder(buildChatConfigs());
instance = new ChatHelper();
}
return instance;
}
public boolean isLogged() {
return QBChatService.getInstance().isLoggedIn();
}
public static QBUser getCurrentUser() {
return QBChatService.getInstance().getUser();
}
private ChatHelper() {
qbChatService = QBChatService.getInstance();
qbChatService.setUseStreamManagement(true);
}
private static QBChatService.ConfigurationBuilder buildChatConfigs() {
QBChatService.ConfigurationBuilder configurationBuilder = new QBChatService.ConfigurationBuilder();
SampleConfigs sampleConfigs = App.getSampleConfigs();
if (sampleConfigs != null) {
int port = sampleConfigs.getChatPort();
int socketTimeout = sampleConfigs.getChatSocketTimeout();
boolean useTls = sampleConfigs.isUseTls();
boolean keepAlive = sampleConfigs.isKeepAlive();
boolean autoJoinEnabled = sampleConfigs.isAutoJoinEnabled();
boolean autoMarkDelivered = sampleConfigs.isAutoMarkDelivered();
boolean reconnectionAllowed = sampleConfigs.isReconnectionAllowed();
boolean allowListenNetwork = sampleConfigs.isAllowListenNetwork();
if (port != 0) {
configurationBuilder.setPort(port);
}
configurationBuilder.setSocketTimeout(socketTimeout);
configurationBuilder.setUseTls(useTls);
configurationBuilder.setKeepAlive(keepAlive);
configurationBuilder.setAutojoinEnabled(autoJoinEnabled);
configurationBuilder.setAutoMarkDelivered(autoMarkDelivered);
configurationBuilder.setReconnectionAllowed(reconnectionAllowed);
configurationBuilder.setAllowListenNetwork(allowListenNetwork);
}
return configurationBuilder;
}
public void addConnectionListener(ConnectionListener listener) {
qbChatService.addConnectionListener(listener);
}
public void removeConnectionListener(ConnectionListener listener) {
qbChatService.removeConnectionListener(listener);
}
public void login(final QBUser user, final QBEntityCallback<Void> callback) {
// Create REST API session on QuickBlox
QBUsers.signIn(user).performAsync(new QbEntityCallbackTwoTypeWrapper<QBUser, Void>(callback) {
@Override
public void onSuccess(QBUser qbUser, Bundle args) {
user.setId(qbUser.getId());
loginToChat(user, new QbEntityCallbackWrapper<>(callback));
}
});
}
public void loginToChat(final QBUser user, final QBEntityCallback<Void> callback) {
if (qbChatService.isLoggedIn()) {
callback.onSuccess(null, null);
return;
}
qbChatService.login(user, callback);
}
public void join(QBChatDialog chatDialog, final QBEntityCallback<Void> callback) {
DiscussionHistory history = new DiscussionHistory();
history.setMaxStanzas(0);
chatDialog.join(history, callback);
}
public void leaveChatDialog(QBChatDialog chatDialog) throws XMPPException, SmackException.NotConnectedException {
chatDialog.leave();
}
public void destroy() {
qbChatService.destroy();
}
public void createDialogWithSelectedUsers(final List<QBUser> users,
final QBEntityCallback<QBChatDialog> callback) {
QBRestChatService.createChatDialog(QbDialogUtils.createDialog(users)).performAsync(
new QbEntityCallbackWrapper<QBChatDialog>(callback) {
@Override
public void onSuccess(QBChatDialog dialog, Bundle args) {
QbDialogHolder.getInstance().addDialog(dialog);
QbUsersHolder.getInstance().putUsers(users);
super.onSuccess(dialog, args);
}
});
}
public void deleteDialogs(Collection<QBChatDialog> dialogs, final QBEntityCallback<ArrayList<String>> callback) {
StringifyArrayList<String> dialogsIds = new StringifyArrayList<>();
for (QBChatDialog dialog : dialogs) {
dialogsIds.add(dialog.getDialogId());
}
QBRestChatService.deleteDialogs(dialogsIds, false, null).performAsync(callback);
}
public void deleteDialog(QBChatDialog qbDialog, QBEntityCallback<Void> callback) {
if (qbDialog.getType() == QBDialogType.PUBLIC_GROUP) {
Toaster.shortToast(R.string.public_group_chat_cannot_be_deleted);
} else {
QBRestChatService.deleteDialog(qbDialog.getDialogId(), false)
.performAsync(new QbEntityCallbackWrapper<Void>(callback));
}
}
public void exitFromDialog(QBChatDialog qbDialog, QBEntityCallback<QBChatDialog> callback) {
try {
leaveChatDialog(qbDialog);
} catch (XMPPException | SmackException.NotConnectedException e) {
callback.onError(new QBResponseException(e.getMessage()));
}
QBDialogRequestBuilder qbRequestBuilder = new QBDialogRequestBuilder();
qbRequestBuilder.removeUsers(QBChatService.getInstance().getUser().getId());
QBRestChatService.updateGroupChatDialog(qbDialog, qbRequestBuilder).performAsync(callback);
}
public void updateDialogUsers(QBChatDialog qbDialog,
final List<QBUser> newQbDialogUsersList,
QBEntityCallback<QBChatDialog> callback) {
List<QBUser> addedUsers = QbDialogUtils.getAddedUsers(qbDialog, newQbDialogUsersList);
List<QBUser> removedUsers = QbDialogUtils.getRemovedUsers(qbDialog, newQbDialogUsersList);
QbDialogUtils.logDialogUsers(qbDialog);
QbDialogUtils.logUsers(addedUsers);
Log.w(TAG, "=======================");
QbDialogUtils.logUsers(removedUsers);
QBDialogRequestBuilder qbRequestBuilder = new QBDialogRequestBuilder();
if (!addedUsers.isEmpty()) {
qbRequestBuilder.addUsers(addedUsers.toArray(new QBUser[addedUsers.size()]));
}
if (!removedUsers.isEmpty()) {
qbRequestBuilder.removeUsers(removedUsers.toArray(new QBUser[removedUsers.size()]));
}
qbDialog.setName(DialogUtils.createChatNameFromUserList(
newQbDialogUsersList.toArray(new QBUser[newQbDialogUsersList.size()])));
QBRestChatService.updateGroupChatDialog(qbDialog, qbRequestBuilder).performAsync(
new QbEntityCallbackWrapper<QBChatDialog>(callback) {
@Override
public void onSuccess(QBChatDialog qbDialog, Bundle bundle) {
QbUsersHolder.getInstance().putUsers(newQbDialogUsersList);
QbDialogUtils.logDialogUsers(qbDialog);
super.onSuccess(qbDialog, bundle);
}
});
}
public void loadChatHistory(QBChatDialog dialog, int skipPagination,
final QBEntityCallback<ArrayList<QBChatMessage>> callback) {
QBRequestGetBuilder customObjectRequestBuilder = new QBRequestGetBuilder();
customObjectRequestBuilder.setSkip(skipPagination);
customObjectRequestBuilder.setLimit(CHAT_HISTORY_ITEMS_PER_PAGE);
customObjectRequestBuilder.sortDesc(CHAT_HISTORY_ITEMS_SORT_FIELD);
QBRestChatService.getDialogMessages(dialog, customObjectRequestBuilder).performAsync(
new QbEntityCallbackWrapper<ArrayList<QBChatMessage>>(callback) {
@Override
public void onSuccess(ArrayList<QBChatMessage> qbChatMessages, Bundle bundle) {
Set<Integer> userIds = new HashSet<>();
for (QBChatMessage message : qbChatMessages) {
userIds.add(message.getSenderId());
}
if (!userIds.isEmpty()) {
getUsersFromMessages(qbChatMessages, userIds, callback);
} else {
callback.onSuccess(qbChatMessages, bundle);
}
// Not calling super.onSuccess() because
// we're want to load chat users before triggering the callback
}
});
}
public void getDialogs(QBRequestGetBuilder customObjectRequestBuilder, final QBEntityCallback<ArrayList<QBChatDialog>> callback) {
customObjectRequestBuilder.setLimit(DIALOG_ITEMS_PER_PAGE);
QBRestChatService.getChatDialogs(null, customObjectRequestBuilder).performAsync(
new QbEntityCallbackWrapper<ArrayList<QBChatDialog>>(callback) {
@Override
public void onSuccess(ArrayList<QBChatDialog> dialogs, Bundle args) {
Iterator<QBChatDialog> dialogIterator = dialogs.iterator();
while (dialogIterator.hasNext()) {
QBChatDialog dialog = dialogIterator.next();
if (dialog.getType() == QBDialogType.PUBLIC_GROUP) {
dialogIterator.remove();
}
}
getUsersFromDialogs(dialogs, callback);
// Not calling super.onSuccess() because
// we want to load chat users before triggering callback
}
});
}
public void getDialogById(String dialogId, final QBEntityCallback<QBChatDialog> callback) {
QBRestChatService.getChatDialogById(dialogId).performAsync(callback);
}
public void getUsersFromDialog(QBChatDialog dialog,
final QBEntityCallback<ArrayList<QBUser>> callback) {
List<Integer> userIds = dialog.getOccupants();
final ArrayList<QBUser> users = new ArrayList<>(userIds.size());
for (Integer id : userIds) {
users.add(QbUsersHolder.getInstance().getUserById(id));
}
// If we already have all users in memory
// there is no need to make REST requests to QB
if (userIds.size() == users.size()) {
callback.onSuccess(users, null);
return;
}
QBPagedRequestBuilder requestBuilder = new QBPagedRequestBuilder(userIds.size(), 1);
QBUsers.getUsersByIDs(userIds, requestBuilder).performAsync(
new QbEntityCallbackWrapper<ArrayList<QBUser>>(callback) {
@Override
public void onSuccess(ArrayList<QBUser> qbUsers, Bundle bundle) {
QbUsersHolder.getInstance().putUsers(qbUsers);
callback.onSuccess(qbUsers, bundle);
}
});
}
public void loadFileAsAttachment(File file, QBEntityCallback<QBAttachment> callback) {
loadFileAsAttachment(file, callback, null);
}
public void loadFileAsAttachment(File file, QBEntityCallback<QBAttachment> callback,
QBProgressCallback progressCallback) {
QBContent.uploadFileTask(file, true, null, progressCallback).performAsync(
new QbEntityCallbackTwoTypeWrapper<QBFile, QBAttachment>(callback) {
@Override
public void onSuccess(QBFile qbFile, Bundle bundle) {
QBAttachment attachment = new QBAttachment(QBAttachment.PHOTO_TYPE);
attachment.setId(qbFile.getId().toString());
attachment.setUrl(qbFile.getPublicUrl());
callback.onSuccess(attachment, bundle);
}
});
}
private void getUsersFromDialogs(final ArrayList<QBChatDialog> dialogs,
final QBEntityCallback<ArrayList<QBChatDialog>> callback) {
List<Integer> userIds = new ArrayList<>();
for (QBChatDialog dialog : dialogs) {
userIds.addAll(dialog.getOccupants());
userIds.add(dialog.getLastMessageUserId());
}
QBPagedRequestBuilder requestBuilder = new QBPagedRequestBuilder(userIds.size(), 1);
QBUsers.getUsersByIDs(userIds, requestBuilder).performAsync(
new QbEntityCallbackTwoTypeWrapper<ArrayList<QBUser>, ArrayList<QBChatDialog>>(callback) {
@Override
public void onSuccess(ArrayList<QBUser> users, Bundle params) {
QbUsersHolder.getInstance().putUsers(users);
callback.onSuccess(dialogs, params);
}
});
}
private void getUsersFromMessages(final ArrayList<QBChatMessage> messages,
final Set<Integer> userIds,
final QBEntityCallback<ArrayList<QBChatMessage>> callback) {
QBPagedRequestBuilder requestBuilder = new QBPagedRequestBuilder(userIds.size(), 1);
QBUsers.getUsersByIDs(userIds, requestBuilder).performAsync(
new QbEntityCallbackTwoTypeWrapper<ArrayList<QBUser>, ArrayList<QBChatMessage>>(callback) {
@Override
public void onSuccess(ArrayList<QBUser> users, Bundle params) {
QbUsersHolder.getInstance().putUsers(users);
callback.onSuccess(messages, params);
}
});
}
}