package im.actor.core.modules.sequence;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import im.actor.core.api.ApiGroup;
import im.actor.core.api.ApiGroupOutPeer;
import im.actor.core.api.ApiUser;
import im.actor.core.api.ApiUserOutPeer;
import im.actor.core.api.rpc.RequestGetReferencedEntitites;
import im.actor.core.modules.ModuleContext;
import im.actor.core.modules.sequence.internal.HandlerDifferenceUpdates;
import im.actor.core.modules.sequence.internal.HandlerSeqUpdate;
import im.actor.core.modules.sequence.internal.HandlerWeakUpdate;
import im.actor.core.modules.sequence.internal.HandlerRelatedResponse;
import im.actor.core.modules.ModuleActor;
import im.actor.core.modules.sequence.processor.UpdateProcessor;
import im.actor.core.network.parser.Update;
import im.actor.runtime.Log;
import im.actor.runtime.Runtime;
import im.actor.runtime.actors.ActorCreator;
import im.actor.runtime.actors.messages.Void;
import im.actor.runtime.function.Constructor;
import im.actor.runtime.function.Function;
import im.actor.runtime.promise.Promise;
import im.actor.runtime.promise.PromiseFunc;
import im.actor.runtime.promise.Promises;
import im.actor.runtime.promise.PromisesArray;
/*-[
#pragma clang diagnostic ignored "-Wnullability-completeness"
]-*/
public class SequenceHandlerActor extends ModuleActor {
public static ActorCreator CONSTRUCTOR(final ModuleContext context) {
return () -> new SequenceHandlerActor(context);
}
private static final String TAG = "SequenceHandlerActor";
// Do Not Remove! WorkAround for missing j2objc translator include
private static final Void DUMB = null;
private final UpdateProcessor processor;
private boolean isUpdating;
public SequenceHandlerActor(ModuleContext context) {
super(context);
this.processor = new UpdateProcessor(context);
}
//
// Sequenced data
//
private Promise<Void> onSeqUpdate(final Update update,
@Nullable List<ApiUser> users,
@Nullable List<ApiGroup> groups) throws Exception {
Log.d(TAG, "Processing update: " + update);
beginUpdates();
// Related Users
Promise<Void> currentPromise;
if (groups != null && users != null && (users.size() > 0 || groups.size() > 0)) {
currentPromise = updates().applyRelatedData(users, groups);
} else {
currentPromise = Promise.success(null);
}
// Update Application
currentPromise = currentPromise
.chain(v -> processor.processUpdate(update))
.then(v -> {
Log.d(TAG, "Ended processing update: " + update);
});
// Handling update end
currentPromise.then(v -> endUpdates());
// TODO: Wait database flush
return currentPromise;
}
private Promise<Void> onDifferenceUpdate(@NotNull List<ApiUser> users,
@NotNull List<ApiGroup> groups,
@NotNull List<ApiUserOutPeer> userOutPeers,
@NotNull List<ApiGroupOutPeer> groupOutPeers,
@NotNull List<Update> updates) {
if (updates.size() > 0) {
String command = "Difference updates:";
for (Update u : updates) {
command += "\n| " + u;
}
Log.d(TAG, command);
}
beginUpdates();
// Related Users
Promise<Void> currentPromise = updates().applyRelatedData(users, groups);
// Loading missing peers
currentPromise = currentPromise.chain(v -> updates().loadRequiredPeers(userOutPeers, groupOutPeers));
// Apply Diff
long applyStart = im.actor.runtime.Runtime.getCurrentTime();
currentPromise = currentPromise
.chain(v -> processor.applyDifferenceUpdate(updates))
.then(v -> {
Log.d(TAG, "Difference applied in " + (im.actor.runtime.Runtime.getCurrentTime() - applyStart) + " ms");
endUpdates();
});
// TODO: Wait database flush
return currentPromise;
}
//
// Weak Updates
//
private void onWeakUpdateReceived(Update update, long date) {
Log.d(TAG, "Processing weak update: " + update);
this.processor.processWeakUpdate(update, date);
}
//
// Tools
//
private void beginUpdates() {
isUpdating = true;
}
private void endUpdates() {
isUpdating = false;
unstashAll();
}
//
// Message Processing
//
@Override
public void onReceive(Object message) {
if (message instanceof HandlerWeakUpdate) {
HandlerWeakUpdate weakUpdate = (HandlerWeakUpdate) message;
try {
onWeakUpdateReceived(weakUpdate.getUpdate(), weakUpdate.getDate());
} catch (Exception e) {
e.printStackTrace();
}
} else {
super.onReceive(message);
}
}
@Override
public Promise onAsk(Object message) throws Exception {
if (message instanceof HandlerSeqUpdate) {
HandlerSeqUpdate seqUpdate = (HandlerSeqUpdate) message;
if (isUpdating) {
stash();
return null;
}
return onSeqUpdate(seqUpdate.getUpdate(), seqUpdate.getUsers(), seqUpdate.getGroups());
} else if (message instanceof HandlerDifferenceUpdates) {
HandlerDifferenceUpdates differenceUpdate = (HandlerDifferenceUpdates) message;
if (isUpdating) {
stash();
return null;
}
return onDifferenceUpdate(
differenceUpdate.getUsers(),
differenceUpdate.getGroups(),
differenceUpdate.getUserOutPeers(),
differenceUpdate.getGroupOutPeers(),
differenceUpdate.getUpdates());
} else {
return super.onAsk(message);
}
}
}