/*
* Copyright (C) 2015 Actor LLC. <https://actor.im>
*/
package im.actor.core.modules.contacts;
import java.util.ArrayList;
import im.actor.core.api.ApiOutPeer;
import im.actor.core.api.ApiUser;
import im.actor.core.api.ApiUserOutPeer;
import im.actor.core.api.base.SeqUpdate;
import im.actor.core.api.rpc.RequestAddContact;
import im.actor.core.api.rpc.RequestRemoveContact;
import im.actor.core.api.rpc.RequestSearchContacts;
import im.actor.core.api.rpc.ResponseSeq;
import im.actor.core.api.updates.UpdateContactsAdded;
import im.actor.core.api.updates.UpdateContactsRemoved;
import im.actor.core.entity.User;
import im.actor.core.modules.AbsModule;
import im.actor.core.modules.api.ApiSupportConfiguration;
import im.actor.core.modules.Modules;
import im.actor.core.viewmodel.Command;
import im.actor.runtime.Storage;
import im.actor.runtime.actors.ActorRef;
import im.actor.runtime.actors.Props;
import im.actor.runtime.promise.Promise;
import im.actor.runtime.storage.ListEngine;
import im.actor.core.entity.Contact;
import im.actor.core.network.RpcCallback;
import im.actor.core.network.RpcException;
import im.actor.core.network.RpcInternalException;
import im.actor.core.viewmodel.UserVM;
import im.actor.runtime.storage.SyncKeyValue;
import static im.actor.runtime.actors.ActorSystem.system;
public class ContactsModule extends AbsModule {
private ListEngine<Contact> contacts;
private ActorRef bookImportActor;
private ActorRef contactSyncActor;
private SyncKeyValue bookImportState;
public ContactsModule(final Modules modules) {
super(modules);
contacts = Storage.createList(STORAGE_CONTACTS, Contact.CREATOR);
bookImportState = new SyncKeyValue(Storage.createKeyValue(STORAGE_BOOK_IMPORT));
}
public void run() {
bookImportActor = system().actorOf(Props.create(() -> new BookImportActor(context())).changeDispatcher("heavy"), "actor/book_import");
contactSyncActor = system().actorOf(Props.create(() -> new ContactsSyncActor(context())).changeDispatcher("heavy"), "actor/contacts_sync");
}
public SyncKeyValue getBookImportState() {
return bookImportState;
}
public void startImport() {
bookImportActor.send(new BookImportActor.Start());
}
public ListEngine<Contact> getContacts() {
return contacts;
}
public void onPhoneBookChanged() {
bookImportActor.send(new BookImportActor.PerformSync());
}
public ActorRef getContactSyncActor() {
return contactSyncActor;
}
public void markContact(int uid) {
preferences().putBool("contact_" + uid, true);
}
public void markNonContact(int uid) {
preferences().putBool("contact_" + uid, false);
}
public boolean isUserContact(int uid) {
return preferences().getBool("contact_" + uid, false);
}
public void markInPhoneBook(int uid) {
preferences().putBool("contact_in_pb_" + uid, true);
}
public void markNotInPhoneBook(int uid) {
preferences().putBool("contact_in_pb_" + uid, false);
}
public boolean isUserInPhoneBook(int uid) {
return preferences().getBool("contact_in_pb_" + uid, false);
}
public Promise<UserVM[]> findUsers(final String query) {
return api(new RequestSearchContacts(query, ApiSupportConfiguration.OPTIMIZATIONS))
.chain(responseSearchContacts -> updates().loadRequiredPeers(responseSearchContacts.getUserPeers(), new ArrayList<>()))
.map(responseSearchContacts1 -> {
ArrayList<UserVM> users = new ArrayList<>();
for (ApiUserOutPeer u : responseSearchContacts1.getUserPeers()) {
users.add(context().getUsersModule().getUsers().get(u.getUid()));
}
return users.toArray(new UserVM[users.size()]);
});
}
public Command<Boolean> addContact(final int uid) {
return callback -> {
User user = users().getValue(uid);
if (user == null) {
runOnUiThread(() -> callback.onError(new RpcInternalException()));
return;
}
request(new RequestAddContact(uid, user.getAccessHash()), new RpcCallback<ResponseSeq>() {
@Override
public void onResult(ResponseSeq response) {
ArrayList<Integer> uids = new ArrayList<>();
uids.add(uid);
SeqUpdate update = new SeqUpdate(response.getSeq(), response.getState(),
UpdateContactsAdded.HEADER, new UpdateContactsAdded(uids).toByteArray());
updates().onUpdateReceived(update);
runOnUiThread(() -> callback.onResult(true));
}
@Override
public void onError(RpcException e) {
runOnUiThread(() -> callback.onError(new RpcInternalException()));
}
});
};
}
public Command<Boolean> removeContact(final int uid) {
return callback -> {
User user = users().getValue(uid);
if (user == null) {
runOnUiThread(() -> callback.onError(new RpcInternalException()));
return;
}
request(new RequestRemoveContact(uid, user.getAccessHash()), new RpcCallback<ResponseSeq>() {
@Override
public void onResult(ResponseSeq response) {
ArrayList<Integer> uids = new ArrayList<>();
uids.add(uid);
SeqUpdate update = new SeqUpdate(response.getSeq(), response.getState(),
UpdateContactsRemoved.HEADER, new UpdateContactsRemoved(uids).toByteArray());
updates().onUpdateReceived(update);
runOnUiThread(() -> callback.onResult(true));
}
@Override
public void onError(RpcException e) {
runOnUiThread(() -> callback.onError(new RpcInternalException()));
}
});
};
}
public void resetModule() {
// TODO: Implement
}
}