content: /*
   * Copyright (C) 2015 Actor LLC. <https://actor.im>
   */
  
  package im.actor.core.modules.messaging.actions;
  
  import java.io.IOException;
  import java.util.HashSet;
  
  import im.actor.core.entity.Peer;
  import im.actor.core.modules.ModuleContext;
  import im.actor.core.modules.messaging.actions.entity.PlainCursor;
  import im.actor.core.modules.messaging.actions.entity.PlainCursorsStorage;
  import im.actor.core.modules.ModuleActor;
  import im.actor.runtime.storage.SyncKeyValue;
  
  public abstract class CursorActor extends ModuleActor {
  
      private PlainCursorsStorage plainCursorsStorage;
      private HashSet<Peer> inProgress = new HashSet<Peer>();
      private long cursorId;
      private SyncKeyValue keyValue;
  
      public CursorActor(long cursorId, ModuleContext context) {
          super(context);
          this.cursorId = cursorId;
          this.keyValue = context.getMessagesModule().getCursorStorage();
      }
  
      @Override
      public void preStart() {
          super.preStart();
  
          plainCursorsStorage = new PlainCursorsStorage();
          byte[] data = keyValue.get(cursorId);
          if (data != null) {
              try {
                  plainCursorsStorage = PlainCursorsStorage.fromBytes(data);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
  
          for (PlainCursor cursor : plainCursorsStorage.getAllCursors()) {
              if (cursor.getSortDate() < cursor.getPendingSortDate()) {
                  inProgress.add(cursor.getPeer());
                  perform(cursor.getPeer(), cursor.getPendingSortDate());
              }
          }
      }
  
      protected final void moveCursor(Peer peer, long date) {
          PlainCursor cursor = plainCursorsStorage.getCursor(peer);
          if (date <= cursor.getSortDate()) {
              return;
          }
          if (date <= cursor.getPendingSortDate()) {
              return;
          }
  
          date = Math.max(cursor.getPendingSortDate(), date);
  
          plainCursorsStorage.putCursor(cursor.changePendingSortDate(date));
  
          saveCursorState();
  
          if (inProgress.contains(peer)) {
              return;
          }
  
          inProgress.add(peer);
          perform(peer, date);
      }
  
      protected final void onMoved(Peer peer, long date) {
          inProgress.remove(peer);
  
          PlainCursor cursor = plainCursorsStorage.getCursor(peer);
          cursor = cursor.changeSortDate(Math.max(date, cursor.getSortDate()));
          plainCursorsStorage.putCursor(cursor);
          saveCursorState();
  
          if (cursor.getSortDate() < cursor.getPendingSortDate()) {
              inProgress.add(peer);
              perform(peer, cursor.getPendingSortDate());
          }
      }
  
      // Execution
      protected abstract void perform(Peer peer, long date);
  
      protected void onCompleted(Peer peer, long date) {
          self().send(new OnCompleted(peer, date));
      }
  
      protected void onError(Peer peer, long date) {
          // Ignore
      }
  
  
      private void saveCursorState() {
          keyValue.put(cursorId, plainCursorsStorage.toByteArray());
      }
  
      @Override
      public void onReceive(Object message) {
          if (message instanceof OnCompleted) {
              OnCompleted completed = (OnCompleted) message;
              onMoved(completed.getPeer(), completed.getDate());
          } else {
              super.onReceive(message);
          }
      }
  
      private static class OnCompleted {
          private Peer peer;
          private long date;
  
          private OnCompleted(Peer peer, long date) {
              this.peer = peer;
              this.date = date;
          }
  
          public Peer getPeer() {
              return peer;
          }
  
          public long getDate() {
              return date;
          }
      }
  }
  