content: package im.actor.core.modules.file;
  
  import org.jetbrains.annotations.NotNull;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  
  import im.actor.core.api.ApiFileLocation;
  import im.actor.core.api.ApiFileUrlDescription;
  import im.actor.core.api.rpc.RequestGetFileUrls;
  import im.actor.core.api.rpc.ResponseGetFileUrls;
  import im.actor.core.modules.ModuleContext;
  import im.actor.core.modules.ModuleActor;
  import im.actor.runtime.Log;
  import im.actor.runtime.actors.ActorCancellable;
  import im.actor.runtime.actors.ask.AskMessage;
  import im.actor.runtime.function.Consumer;
  import im.actor.runtime.promise.Promise;
  import im.actor.runtime.promise.PromiseFunc;
  import im.actor.runtime.promise.PromiseResolver;
  
  public class FileUrlLoader extends ModuleActor {
  
      private HashMap<Long, Promise<String>> requestedFiles = new HashMap<>();
  
      private ArrayList<RequestedFile> pendingFiles = new ArrayList<>();
      private boolean isExecuting = false;
      private ActorCancellable checkCancellable;
  
      public FileUrlLoader(ModuleContext context) {
          super(context);
      }
  
      public void checkQueue() {
          if (isExecuting) {
              return;
          }
  
          if (pendingFiles.size() == 0) {
              return;
          }
  
          final ArrayList<RequestedFile> destFiles = new ArrayList<>(pendingFiles);
          pendingFiles.clear();
  
          isExecuting = true;
          ArrayList<ApiFileLocation> locations = new ArrayList<>();
          for (RequestedFile f : destFiles) {
              Log.d("FileUrlLoader", "api: " + f.getFileId());
              locations.add(new ApiFileLocation(f.getFileId(), f.getAccessHash()));
          }
          api(new RequestGetFileUrls(locations)).then(responseGetFileUrls -> {
  
              outer:
              for (RequestedFile f : destFiles) {
                  for (ApiFileUrlDescription urlDescription : responseGetFileUrls.getFileUrls()) {
                      if (f.getFileId() == urlDescription.getFileId()) {
                          Log.d("FileUrlLoader", "resp: " + f.getFileId());
                          // TODO: Implement Timeouts
                          f.getResolver().result(urlDescription.getUrl());
  
                          continue outer;
                      }
                  }
              }
              isExecuting = false;
              scheduleCheck();
          }).failure(e -> {
              for (RequestedFile f : destFiles) {
                  f.getResolver().error(e);
              }
              isExecuting = false;
              scheduleCheck();
          });
      }
  
      public Promise<String> askUrl(final long fileId, final long accessHash) {
          Log.d("FileUrlLoader", "request: " + fileId);
          if (requestedFiles.containsKey(fileId)) {
              return requestedFiles.get(fileId);
          }
          final Promise<String> res = new Promise<>((PromiseFunc<String>) resolver -> {
              pendingFiles.add(new RequestedFile(fileId, accessHash, resolver));
              scheduleCheck();
          });
          requestedFiles.put(fileId, res);
          return res;
      }
  
      private void scheduleCheck() {
          if (checkCancellable != null) {
              checkCancellable.cancel();
  
          }
          checkCancellable = schedule(new CheckQueue(), 50);
      }
  
  
      //
      // Messages
      //
  
      @Override
      public Promise onAsk(Object message) throws Exception {
          if (message instanceof AskUrl) {
              AskUrl askUrl = (AskUrl) message;
              return askUrl(askUrl.getFileId(), askUrl.getAccessHash());
          } else {
              return super.onAsk(message);
          }
      }
  
      @Override
      public void onReceive(Object message) {
          if (message instanceof CheckQueue) {
              checkQueue();
          } else {
              super.onReceive(message);
          }
      }
  
      private static class RequestedFile {
  
          private final long fileId;
          private final long accessHash;
          private final PromiseResolver<String> resolver;
  
          public RequestedFile(long fileId, long accessHash, PromiseResolver<String> resolver) {
              this.fileId = fileId;
              this.accessHash = accessHash;
              this.resolver = resolver;
          }
  
          public long getFileId() {
              return fileId;
          }
  
          public long getAccessHash() {
              return accessHash;
          }
  
          public PromiseResolver<String> getResolver() {
              return resolver;
          }
      }
  
      public static class AskUrl implements AskMessage<String> {
  
          private long fileId;
          private long accessHash;
  
          public AskUrl(long fileId, long accessHash) {
              this.fileId = fileId;
              this.accessHash = accessHash;
          }
  
          public long getFileId() {
              return fileId;
          }
  
          public long getAccessHash() {
              return accessHash;
          }
      }
  
      private static class CheckQueue {
  
      }
  }