private void onSent(Peer peer, long rid) {
   for (PendingMessage pending : pendingMessages.getPendingMessages()) {
     if (pending.getRid() == rid && pending.getPeer().equals(peer)) {
       pendingMessages.getPendingMessages().remove(pending);
       break;
     }
   }
   savePending();
 }
 private void onError(Peer peer, long rid) {
   for (PendingMessage pending : pendingMessages.getPendingMessages()) {
     if (pending.getRid() == rid && pending.getPeer().equals(peer)) {
       pendingMessages.getPendingMessages().remove(pending);
       break;
     }
   }
   savePending();
   context().getMessagesModule().getRouter().onOutgoingError(peer, rid);
 }
  private void onFileUploaded(long rid, FileReference fileReference) {
    PendingMessage msg = findPending(rid);
    if (msg == null) {
      return;
    }

    pendingMessages.getPendingMessages().remove(msg);

    AbsContent nContent;
    if (msg.getContent() instanceof PhotoContent) {
      PhotoContent basePhotoContent = (PhotoContent) msg.getContent();
      nContent =
          PhotoContent.createRemotePhoto(
              fileReference,
              basePhotoContent.getW(),
              basePhotoContent.getH(),
              basePhotoContent.getFastThumb());
    } else if (msg.getContent() instanceof VideoContent) {
      VideoContent baseVideoContent = (VideoContent) msg.getContent();
      nContent =
          VideoContent.createRemoteVideo(
              fileReference,
              baseVideoContent.getW(),
              baseVideoContent.getH(),
              baseVideoContent.getDuration(),
              baseVideoContent.getFastThumb());
    } else if (msg.getContent() instanceof VoiceContent) {
      VoiceContent baseVoiceContent = (VoiceContent) msg.getContent();
      nContent = VoiceContent.createRemoteAudio(fileReference, baseVoiceContent.getDuration());
    } else if (msg.getContent() instanceof AnimationContent) {
      AnimationContent baseAnimcationContent = (AnimationContent) msg.getContent();
      nContent =
          AnimationContent.createRemoteAnimation(
              fileReference,
              baseAnimcationContent.getW(),
              baseAnimcationContent.getH(),
              baseAnimcationContent.getFastThumb());
    } else if (msg.getContent() instanceof DocumentContent) {
      DocumentContent baseDocContent = (DocumentContent) msg.getContent();
      nContent = DocumentContent.createRemoteDocument(fileReference, baseDocContent.getFastThumb());
    } else {
      return;
    }

    pendingMessages
        .getPendingMessages()
        .add(new PendingMessage(msg.getPeer(), msg.getRid(), nContent));
    context()
        .getMessagesModule()
        .getRouter()
        .onContentChanged(msg.getPeer(), msg.getRid(), nContent);
    performSendContent(msg.getPeer(), rid, nContent);
    fileUplaodingWakeLocks.remove(rid).releaseLock();
  }
 private PendingMessage findPending(long rid) {
   for (PendingMessage message : pendingMessages.getPendingMessages()) {
     if (message.getRid() == rid) {
       return message;
     }
   }
   return null;
 }
  @Override
  public void preStart() {
    pendingMessages = new PendingMessagesStorage();
    byte[] p = preferences().getBytes(PREFERENCES);
    if (p != null) {
      try {
        pendingMessages = PendingMessagesStorage.fromBytes(p);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

    boolean isChanged = false;
    ArrayList<PendingMessage> messages = pendingMessages.getPendingMessages();
    for (PendingMessage pending : messages.toArray(new PendingMessage[messages.size()])) {
      if (pending.getContent() instanceof TextContent) {
        performSendContent(pending.getPeer(), pending.getRid(), pending.getContent());
      } else if (pending.getContent() instanceof DocumentContent) {
        DocumentContent documentContent = (DocumentContent) pending.getContent();
        if (documentContent.getSource() instanceof FileLocalSource) {
          if (Storage.isFsPersistent()) {
            performUploadFile(
                pending.getRid(),
                ((FileLocalSource) documentContent.getSource()).getFileDescriptor(),
                ((FileLocalSource) documentContent.getSource()).getFileName());
          } else {
            List<Long> rids = new ArrayList<>();
            rids.add(pending.getRid());
            context().getMessagesModule().getRouter().onMessagesDeleted(pending.getPeer(), rids);
            pendingMessages.getPendingMessages().remove(pending);
            isChanged = true;
          }
        } else {
          performSendContent(pending.getPeer(), pending.getRid(), pending.getContent());
        }
      }
    }

    if (isChanged) {
      savePending();
    }
  }
  public void doForwardContent(Peer peer, AbsContent content) {
    long rid = RandomUtils.nextRid();
    long date = createPendingDate();
    long sortDate = date + 365 * 24 * 60 * 60 * 1000L;

    Message message = new Message(rid, sortDate, date, myUid(), MessageState.PENDING, content);
    context().getMessagesModule().getRouter().onOutgoingMessage(peer, message);

    pendingMessages.getPendingMessages().add(new PendingMessage(peer, rid, content));
    savePending();

    performSendContent(peer, rid, content);
  }
  public void doSendText(
      @NotNull Peer peer,
      @NotNull String text,
      @Nullable ArrayList<Integer> mentions, /*Ignored*/
      @Nullable String markDownText,
      boolean autoDetect) {

    text = text.trim();

    long rid = RandomUtils.nextRid();
    long date = createPendingDate();
    long sortDate = date + 365 * 24 * 60 * 60 * 1000L;

    if (autoDetect) {
      mentions = new ArrayList<>();
      if (peer.getPeerType() == PeerType.GROUP) {
        Group group = getGroup(peer.getPeerId());
        String lowText = text.toLowerCase();
        if (group.getMembers() != null) {
          for (GroupMember member : group.getMembers()) {
            User user = getUser(member.getUid());
            if (user.getNick() != null) {
              String nick = "@" + user.getNick().toLowerCase();
              // TODO: Better filtering
              if (lowText.contains(nick + ":")
                  || lowText.contains(nick + " ")
                  || lowText.contains(" " + nick)
                  || lowText.endsWith(nick)
                  || lowText.equals(nick)) {
                mentions.add(user.getUid());
              }
            }
          }
        }
      }
    }

    TextContent content = TextContent.create(text, null, mentions);

    Message message = new Message(rid, sortDate, date, myUid(), MessageState.PENDING, content);

    context().getMessagesModule().getRouter().onOutgoingMessage(peer, message);

    pendingMessages.getPendingMessages().add(new PendingMessage(peer, rid, content));
    savePending();

    performSendContent(peer, rid, content);
  }
  public void doSendAudio(
      Peer peer, String descriptor, String fileName, int fileSize, int duration) {
    long rid = RandomUtils.nextRid();
    long date = createPendingDate();
    long sortDate = date + 365 * 24 * 60 * 60 * 1000L;
    VoiceContent audioContent =
        VoiceContent.createLocalAudio(descriptor, fileName, fileSize, duration);

    Message message = new Message(rid, sortDate, date, myUid(), MessageState.PENDING, audioContent);
    context().getMessagesModule().getRouter().onOutgoingMessage(peer, message);

    pendingMessages.getPendingMessages().add(new PendingMessage(peer, rid, audioContent));
    savePending();

    performUploadFile(rid, descriptor, fileName);
  }
  public void doSendLocation(
      @NotNull Peer peer,
      @NotNull Double longitude,
      @NotNull Double latitude,
      @Nullable String street,
      @Nullable String place) {

    long rid = RandomUtils.nextRid();
    long date = createPendingDate();
    long sortDate = date + 365 * 24 * 60 * 60 * 1000L;

    LocationContent content = LocationContent.create(longitude, latitude, street, place);

    Message message = new Message(rid, sortDate, date, myUid(), MessageState.PENDING, content);
    context().getMessagesModule().getRouter().onOutgoingMessage(peer, message);

    pendingMessages.getPendingMessages().add(new PendingMessage(peer, rid, content));
    savePending();

    performSendContent(peer, rid, content);
  }
  public void doSendContact(
      @NotNull Peer peer,
      @NotNull ArrayList<String> emails,
      @NotNull ArrayList<String> phones,
      @Nullable String name,
      @Nullable String base64photo) {

    long rid = RandomUtils.nextRid();
    long date = createPendingDate();
    long sortDate = date + 365 * 24 * 60 * 60 * 1000L;

    ContactContent content = ContactContent.create(name, phones, emails, base64photo);

    Message message = new Message(rid, sortDate, date, myUid(), MessageState.PENDING, content);
    context().getMessagesModule().getRouter().onOutgoingMessage(peer, message);

    pendingMessages.getPendingMessages().add(new PendingMessage(peer, rid, content));
    savePending();

    performSendContent(peer, rid, content);
  }
  public void doSendPhoto(
      Peer peer,
      FastThumb fastThumb,
      String descriptor,
      String fileName,
      int fileSize,
      int w,
      int h) {
    long rid = RandomUtils.nextRid();
    long date = createPendingDate();
    long sortDate = date + 365 * 24 * 60 * 60 * 1000L;
    PhotoContent photoContent =
        PhotoContent.createLocalPhoto(descriptor, fileName, fileSize, w, h, fastThumb);

    Message message = new Message(rid, sortDate, date, myUid(), MessageState.PENDING, photoContent);
    context().getMessagesModule().getRouter().onOutgoingMessage(peer, message);

    pendingMessages.getPendingMessages().add(new PendingMessage(peer, rid, photoContent));
    savePending();

    performUploadFile(rid, descriptor, fileName);
  }
 private void savePending() {
   preferences().putBytes(PREFERENCES, pendingMessages.toByteArray());
 }