content: /*
   * Copyright (C) 2015 Actor LLC. <https://actor.im>
   */
  
  package im.actor.core.modules.search;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import im.actor.core.api.ApiGroupOutPeer;
  import im.actor.core.api.ApiSearchAndCondition;
  import im.actor.core.api.ApiSearchCondition;
  import im.actor.core.api.ApiSearchContentType;
  import im.actor.core.api.ApiSearchPeerCondition;
  import im.actor.core.api.ApiSearchPeerContentType;
  import im.actor.core.api.ApiSearchPeerType;
  import im.actor.core.api.ApiSearchPeerTypeCondition;
  import im.actor.core.api.ApiSearchPieceText;
  import im.actor.core.api.rpc.RequestMessageSearch;
  import im.actor.core.api.rpc.RequestPeerSearch;
  import im.actor.core.entity.Dialog;
  import im.actor.core.entity.MessageSearchEntity;
  import im.actor.core.entity.Peer;
  import im.actor.core.entity.PeerSearchEntity;
  import im.actor.core.entity.PeerSearchType;
  import im.actor.core.entity.SearchEntity;
  import im.actor.core.entity.SearchResult;
  import im.actor.core.entity.content.AbsContent;
  import im.actor.core.modules.AbsModule;
  import im.actor.core.modules.api.ApiSupportConfiguration;
  import im.actor.core.modules.Modules;
  import im.actor.core.modules.search.sources.GlobalSearchSource;
  import im.actor.runtime.Storage;
  import im.actor.runtime.actors.ActorRef;
  import im.actor.runtime.actors.messages.Void;
  import im.actor.runtime.collections.ManagedList;
  import im.actor.runtime.mvvm.SearchValueModel;
  import im.actor.runtime.promise.Promise;
  import im.actor.runtime.storage.ListEngine;
  
  import static im.actor.core.entity.EntityConverter.convert;
  import static im.actor.runtime.actors.ActorSystem.system;
  
  public class SearchModule extends AbsModule {
  
      // j2objc workaround
      private static final Void DUMB = null;
  
      private ListEngine<SearchEntity> searchList;
      private ActorRef actorRef;
  
      public SearchModule(Modules modules) {
          super(modules);
  
          searchList = Storage.createList(STORAGE_SEARCH, SearchEntity.CREATOR);
      }
  
      public void run() {
          actorRef = system().actorOf("actor/search", () -> new SearchActor(context()));
      }
  
      public ListEngine<SearchEntity> getSearchList() {
          return searchList;
      }
  
  
      //
      // Message Search
      //
  
      public Promise<List<MessageSearchEntity>> findTextMessages(Peer peer, String query) {
          ArrayList<ApiSearchCondition> conditions = new ArrayList<>();
          conditions.add(new ApiSearchPeerCondition(getApiOutPeer(peer)));
          conditions.add(new ApiSearchPieceText(query));
          return findMessages(new ApiSearchAndCondition(conditions));
      }
  
      public Promise<List<MessageSearchEntity>> findAllDocs(Peer peer) {
          return findAllContent(peer, ApiSearchContentType.DOCUMENTS);
      }
  
      public Promise<List<MessageSearchEntity>> findAllLinks(Peer peer) {
          return findAllContent(peer, ApiSearchContentType.LINKS);
      }
  
      public Promise<List<MessageSearchEntity>> findAllPhotos(Peer peer) {
          return findAllContent(peer, ApiSearchContentType.PHOTOS);
      }
  
      private Promise<List<MessageSearchEntity>> findAllContent(Peer peer, ApiSearchContentType contentType) {
          ArrayList<ApiSearchCondition> conditions = new ArrayList<>();
          conditions.add(new ApiSearchPeerCondition(getApiOutPeer(peer)));
          conditions.add(new ApiSearchPeerContentType(contentType));
          return findMessages(new ApiSearchAndCondition(conditions));
      }
  
      private Promise<List<MessageSearchEntity>> findMessages(final ApiSearchCondition condition) {
          return api(new RequestMessageSearch(condition, ApiSupportConfiguration.OPTIMIZATIONS))
                  .chain(responseMessageSearchResponse ->
                          updates().applyRelatedData(
                                  responseMessageSearchResponse.getUsers(),
                                  responseMessageSearchResponse.getGroups()))
                  .map(responseMessageSearchResponse1 ->
                          ManagedList.of(responseMessageSearchResponse1.getSearchResults())
                                  .map(itm -> new MessageSearchEntity(
                                          convert(itm.getResult().getPeer()), itm.getResult().getRid(),
                                          itm.getResult().getDate(), itm.getResult().getSenderId(),
                                          AbsContent.fromMessage(itm.getResult().getContent()))));
      }
  
      public Promise<List<PeerSearchEntity>> findPeers(PeerSearchType type) {
          final ApiSearchPeerType apiType;
          if (type == PeerSearchType.GROUPS) {
              apiType = ApiSearchPeerType.GROUPS;
          } else if (type == PeerSearchType.PUBLIC) {
              apiType = ApiSearchPeerType.PUBLIC;
          } else {
              apiType = ApiSearchPeerType.CONTACTS;
          }
          ArrayList<ApiSearchCondition> conditions = new ArrayList<>();
          conditions.add(new ApiSearchPeerTypeCondition(apiType));
          return findPeers(conditions);
      }
  
      public Promise<List<PeerSearchEntity>> findPeers(String query) {
          ArrayList<ApiSearchCondition> conditions = new ArrayList<>();
          conditions.add(new ApiSearchPieceText(query));
          return findPeers(conditions);
      }
  
      public Promise<List<PeerSearchEntity>> findPeers(ArrayList<ApiSearchCondition> conditions) {
  
          return api(new RequestPeerSearch(conditions, ApiSupportConfiguration.OPTIMIZATIONS))
                  .chain(responsePeerSearch ->
                          updates().applyRelatedData(
                                  responsePeerSearch.getUsers(),
                                  responsePeerSearch.getGroups()))
                  .chain(responsePeerSearch2 ->
                          updates().loadRequiredPeers(responsePeerSearch2.getUserPeers(), responsePeerSearch2.getGroupPeers()))
                  .map(responsePeerSearch1 ->
                          ManagedList.of(responsePeerSearch1.getSearchResults())
                                  .map(r -> new PeerSearchEntity(convert(r.getPeer()), r.getOptMatchString())));
      }
  
      public Promise<Peer> findPublicGroupById(int gid) {
          ArrayList<ApiGroupOutPeer> groups = new ArrayList<>();
          groups.add(new ApiGroupOutPeer(gid, 0));
          return updates().loadRequiredPeers(new ArrayList<>(), groups).map(aVoid -> Peer.group(gid));
      }
  
      public SearchValueModel<SearchResult> buildSearchModel() {
          return new SearchValueModel<>(new GlobalSearchSource(context()));
      }
  
      //
      // Local Search
      //
  
      public void onDialogsChanged(List<Dialog> dialogs) {
          actorRef.send(new SearchActor.OnDialogsUpdated(dialogs));
      }
  
      public void onContactsChanged(Integer[] contacts) {
          int[] res = new int[contacts.length];
          for (int i = 0; i < res.length; i++) {
              res[i] = contacts[i];
          }
          actorRef.send(new SearchActor.OnContactsUpdated(res));
      }
  
      public void resetModule() {
          actorRef.send(new SearchActor.Clear());
      }
  }
  