/*
* Copyright (C) 2015 Actor LLC. <https://actor.im>
*/
package im.actor.core.modules.sequence;
import org.jetbrains.annotations.NotNull;
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.base.FatSeqUpdate;
import im.actor.core.api.base.SeqUpdate;
import im.actor.core.api.rpc.RequestGetReferencedEntitites;
import im.actor.core.events.NewSessionCreated;
import im.actor.core.modules.AbsModule;
import im.actor.core.modules.ModuleContext;
import im.actor.core.modules.sequence.internal.ExecuteAfter;
import im.actor.core.network.parser.Update;
import im.actor.runtime.actors.ActorRef;
import im.actor.runtime.actors.messages.Void;
import im.actor.runtime.eventbus.BusSubscriber;
import im.actor.runtime.eventbus.Event;
import im.actor.runtime.promise.Promise;
import im.actor.runtime.promise.PromiseFunc;
import im.actor.runtime.promise.PromiseResolver;
import im.actor.runtime.promise.Promises;
import im.actor.runtime.promise.PromisesArray;
import static im.actor.runtime.actors.ActorSystem.system;
public class Updates extends AbsModule implements BusSubscriber {
// j2objc workaround
private static final Void DUMB = null;
private ActorRef updateActor;
private ActorRef updateHandler;
private SequenceHandlerInt updateHandlerInt;
public Updates(ModuleContext messenger) {
super(messenger);
}
public void run() {
this.updateHandler = system().actorOf("actor/updates/handler", SequenceHandlerActor.CONSTRUCTOR(context()));
this.updateHandlerInt = new SequenceHandlerInt(this.updateHandler);
this.updateActor = system().actorOf("actor/updates", SequenceActor.CONSTRUCTOR(context()));
context().getEvents().subscribe(this, NewSessionCreated.EVENT);
}
public SequenceHandlerInt getUpdateHandler() {
return updateHandlerInt;
}
public void onPushReceived(int seq, long authId) {
if (updateActor != null) {
updateActor.send(new SequenceActor.PushSeq(seq, authId));
}
}
public Promise<Void> applyUpdate(int seq, byte[] state, Update update) {
return new Promise<>((PromiseFunc<Void>) resolver -> {
updateActor.send(new SeqUpdate(seq, state, update.getHeaderKey(), update.toByteArray()));
executeAfter(seq, () -> resolver.result(null));
});
}
public Promise<Void> applyUpdate(int seq, byte[] state, Update update,
List<ApiUser> users, ApiGroup group) {
ArrayList<ApiGroup> groups = new ArrayList<>();
groups.add(group);
return applyUpdate(seq, state, update, users, groups);
}
public Promise<Void> applyUpdate(int seq, byte[] state, Update update,
List<ApiUser> users, List<ApiGroup> groups) {
return new Promise<>((PromiseFunc<Void>) resolver -> {
updateActor.send(new FatSeqUpdate(seq, state, update.getHeaderKey(), update.toByteArray(),
users, groups));
executeAfter(seq, () -> resolver.result(null));
});
}
public Promise<Void> waitForUpdate(int seq) {
return new Promise<>((PromiseFunc<Void>) resolver -> {
executeAfter(seq, () -> resolver.result(null));
});
}
public Promise<Void> applyRelatedData(final List<ApiUser> users) {
return applyRelatedData(users, new ArrayList<>());
}
public Promise<Void> applyRelatedData(final List<ApiUser> users, final ApiGroup group) {
ArrayList<ApiGroup> groups = new ArrayList<>();
groups.add(group);
return applyRelatedData(users, groups);
}
public Promise<Void> applyRelatedData(final List<ApiUser> users, final List<ApiGroup> groups) {
Promise<Void> res = Promise.success(null);
if (users.size() > 0) {
res = res.chain(v -> context().getUsersModule().getUserRouter().applyUsers(users));
}
if (groups.size() > 0) {
res = res.chain(v -> context().getGroupsModule().getRouter().applyGroups(groups));
}
return res;
}
public Promise<Void> loadRequiredPeers(List<ApiUserOutPeer> users, List<ApiGroupOutPeer> groups) {
Promise<List<ApiUserOutPeer>> usersMissingPeers = context().getUsersModule().getUserRouter()
.fetchMissingUsers(users);
Promise<List<ApiGroupOutPeer>> groupMissingPeers = context().getGroupsModule().getRouter()
.fetchPendingGroups(groups);
return Promises.tuple(usersMissingPeers, groupMissingPeers)
.flatMap(missing -> {
if (missing.getT1().size() > 0 || missing.getT2().size() > 0) {
return api(new RequestGetReferencedEntitites(missing.getT1(), missing.getT2()))
.flatMap(r -> applyRelatedData(r.getUsers(), r.getGroups()));
} else {
return Promise.success(null);
}
});
}
@Deprecated
public void onUpdateReceived(Object update) {
updateActor.send(update);
}
@Deprecated
public void executeAfter(int seq, Runnable runnable) {
updateActor.send(new ExecuteAfter(seq, runnable));
}
public void resetModule() {
// TODO: Implement
}
@Override
public void onBusEvent(Event event) {
if (event instanceof NewSessionCreated) {
updateActor.send(new SequenceActor.Invalidate());
}
}
}