package com.braunster.androidchatsdk.firebaseplugin.firebase;
import com.braunster.androidchatsdk.firebaseplugin.firebase.wrappers.BThreadWrapper;
import com.braunster.androidchatsdk.firebaseplugin.firebase.wrappers.BUserWrapper;
import com.braunster.chatsdk.dao.BThread;
import com.braunster.chatsdk.dao.BUser;
import com.braunster.chatsdk.network.BFirebaseDefines;
import com.braunster.chatsdk.object.BError;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.ValueEventListener;
import org.jdeferred.Deferred;
import org.jdeferred.DoneCallback;
import org.jdeferred.FailCallback;
import org.jdeferred.Promise;
import org.jdeferred.impl.DeferredObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Created by kykrueger on 2016-09-04.
*/
public class ThreadRecovery {
public static Promise<BThread, BError, Void> checkForAndRecoverThreadWithUsers(List<BUser> users){
final Deferred<BThread, BError, Void> deferred = new DeferredObject<>();
checkForRemoteThreadWithUsers(users).done(new DoneCallback<String>() {
@Override
public void onDone(String foundRemoteThread) {
BThreadWrapper threadWrapper = new BThreadWrapper(foundRemoteThread);
threadWrapper.recoverPrivateThread().done(new DoneCallback<BThread>() {
@Override
public void onDone(BThread bThread) {
deferred.resolve(bThread);
}
}).fail(new FailCallback<BError>() {
@Override
public void onFail(BError bError) {
deferred.reject(bError);
}
});
}
}).fail(new FailCallback<BError>() {
@Override
public void onFail(BError bError) {
deferred.reject(bError);
}
});
return deferred.promise();
}
public static Promise<String, BError, Void> checkForRemoteThreadWithUsers(List<BUser> users){
final Deferred<String, BError, Void> deferred = new DeferredObject<>();
final List<String> userEntityIds = new ArrayList<>();
DatabaseReference currentUsersDatabasePath = null;
// Get current user's firebase reference
for ( BUser user : users){
userEntityIds.add(user.getEntityID());
if(user.isMe()){
currentUsersDatabasePath = BUserWrapper.initWithModel(user).ref();
}
}
// Look through all of their associated threads for an existing one with the listed users
// We don't need to worry about this linking to a public thread because the current
// user cannot be in a public thread while trying to create a private one.
currentUsersDatabasePath.
child(BFirebaseDefines.Path.BThreadPath).
addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot allThreadsForUser) {
// Check all of the user's threads (only the threadIds are here)
Boolean lastThread = false;
int threadNumber = 0;
if (allThreadsForUser.getChildrenCount() == 0) {
deferred.reject(new BError(404, "Could not find existing Thread"));
}
for(DataSnapshot threadOfUser : allThreadsForUser.getChildren()){
threadNumber = threadNumber + 1;
// Stop searching if the thread has already been found
if (deferred.isResolved()) break;
if(allThreadsForUser.getChildrenCount() == threadNumber) lastThread = true;
final Boolean lastThreadFinal = lastThread;
DatabaseReference threadRef = FirebasePaths.threadRef(threadOfUser.getKey());
// Make a call to retrieve details for each thread
threadRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot thread) {
Integer numberOfUsers = 0;
Boolean threadFound = true;
DataSnapshot threadUsersPath = thread
.child(BFirebaseDefines.Path.BUsersPath);
for (DataSnapshot user : threadUsersPath.getChildren()){
numberOfUsers = numberOfUsers + 1;
if(!userEntityIds.contains(user.getKey())) threadFound = false;
}
// If there are no other users, and the number of users are the same
// This is an existing thread between the specified users
// Return if this is not true
if(numberOfUsers != userEntityIds.size() || !threadFound){
if(lastThreadFinal && deferred.isPending()){
deferred.reject(new BError(404, "Could not find existing Thread"));
}
return;
}
// Return thread's entityId
deferred.resolve(thread.getKey());
}
@Override
public void onCancelled(DatabaseError databaseError) {
if (deferred.isPending()){
deferred.reject(new BError(404, "Could not find existing Thread"));
}
}
});
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
if (deferred.isPending()){
deferred.reject(new BError(404, "Could not find existing Thread"));
}
}
});
return deferred.promise();
}
}