content: package im.actor.core.modules.api;
  
  import im.actor.core.modules.ModuleContext;
  import im.actor.core.modules.api.entity.CursorStoredRequest;
  import im.actor.core.modules.api.entity.PersistentStorage;
  import im.actor.core.modules.api.entity.StoredRequest;
  import im.actor.core.modules.ModuleActor;
  import im.actor.core.network.RpcCallback;
  import im.actor.core.network.RpcException;
  import im.actor.core.network.parser.Request;
  import im.actor.core.network.parser.Response;
  import im.actor.runtime.Storage;
  import im.actor.runtime.storage.KeyValueStorage;
  
  public class PersistentRequestsActor extends ModuleActor {
  
      private static final String STORAGE = "persistent_requests";
  
      private KeyValueStorage storage;
      private PersistentStorage requestsStorage;
  
      public PersistentRequestsActor(ModuleContext context) {
          super(context);
      }
  
      @Override
      public void preStart() {
          super.preStart();
  
          storage = Storage.createKeyValue(STORAGE);
  
          requestsStorage = new PersistentStorage();
          byte[] data = storage.loadItem(0);
          if (data != null) {
              try {
                  requestsStorage = PersistentStorage.fromBytes(data);
              } catch (Throwable t) {
                  t.printStackTrace();
              }
          }
  
          // Restarting requests
  
          for (StoredRequest r : requestsStorage.getRequests()) {
              performRequest(r);
          }
  
          for (CursorStoredRequest r : requestsStorage.getCursorRequests()) {
              if (r.getRequest() != null) {
                  performCursorRequest(r.getRequest().getRequest(), r.getName(), r.getCurrentKey());
              }
          }
      }
  
      private void onNewRequest(Request request) {
          StoredRequest storedRequest = new StoredRequest(request);
          requestsStorage.getRequests().add(storedRequest);
          performRequest(storedRequest);
  
          // Saving storage
          saveStorage();
      }
  
      private void onNewCursorRequest(String name, long key, Request request) {
  
          // Checking if request is valid
          CursorStoredRequest cursorStoredRequest = requestsStorage.findCursorRequest(name);
          if (cursorStoredRequest != null) {
              if (cursorStoredRequest.getCurrentKey() >= key) {
                  return;
              }
              requestsStorage.getCursorRequests().remove(cursorStoredRequest);
          }
  
          cursorStoredRequest = new CursorStoredRequest(name, key, new StoredRequest(request));
          requestsStorage.getCursorRequests().add(cursorStoredRequest);
  
          performCursorRequest(request, name, key);
  
          // Saving storage
          saveStorage();
      }
  
      private void performCursorRequest(Request request, final String name, final long key) {
          request(request, new RpcCallback() {
              @Override
              public void onResult(Response response) {
                  requestCompleted(name, key);
              }
  
              @Override
              public void onError(RpcException e) {
                  // Remove even when error
                  requestCompleted(name, key);
              }
          });
      }
  
      private void requestCompleted(String name, long key) {
          CursorStoredRequest s = requestsStorage.findCursorRequest(name);
          if (s.getCurrentKey() == key) {
              requestsStorage.getCursorRequests().remove(s);
              requestsStorage.getCursorRequests().add(new CursorStoredRequest(name, key, null));
              saveStorage();
          }
      }
  
      private void performRequest(final StoredRequest request) {
  
          request(request.getRequest(), new RpcCallback() {
              @Override
              public void onResult(Response response) {
                  requestCompleted(request);
              }
  
              @Override
              public void onError(RpcException e) {
                  // Remove even when error
                  requestCompleted(request);
              }
          });
      }
  
      private void requestCompleted(StoredRequest request) {
          requestsStorage.getRequests().remove(request);
          saveStorage();
      }
  
      private void saveStorage() {
          storage.addOrUpdateItem(0, requestsStorage.toByteArray());
      }
  
      @Override
      public void onReceive(Object message) {
          if (message instanceof PerformRequest) {
              onNewRequest(((PerformRequest) message).getRequest());
          } else if (message instanceof PerformCursorRequest) {
              PerformCursorRequest cursorRequest = (PerformCursorRequest) message;
              onNewCursorRequest(cursorRequest.getName(), cursorRequest.getKey(),
                      cursorRequest.getRequest());
          } else {
              super.onReceive(message);
          }
      }
  
      public static class PerformRequest {
  
          private Request request;
  
          public PerformRequest(Request request) {
              this.request = request;
          }
  
          public Request getRequest() {
              return request;
          }
      }
  
      public static class PerformCursorRequest {
          private String name;
          private long key;
          private Request request;
  
          public PerformCursorRequest(String name, long key, Request request) {
              this.name = name;
              this.key = key;
              this.request = request;
          }
  
          public String getName() {
              return name;
          }
  
          public long getKey() {
              return key;
          }
  
          public Request getRequest() {
              return request;
          }
      }
  }