/** Sends a real time event by itself */
  protected void sendRealTimeEvent(SerializedEvent singleEvent) {
    // Check to see if this single serialized event is greater than MAX_BUFFER_SIZE, if it is we
    // drop it.
    if (singleEvent.getSerializedData().length()
        > SettingsStore.getCllSettingsAsInt(SettingsStore.Settings.MAXEVENTSIZEINBYTES)) {
      return;
    }

    try {
      sender.sendEvent(singleEvent.getSerializedData());
    } catch (IOException e) {
      // Edge case for real time events that try to send but don't have network.
      // In this case we need to write to disk
      // Force Normal latency so we don't keep looping back to here
      handler.log(singleEvent);
      logger.error(TAG, "Cannot send event");
    }

    for (ICllEvents event : cllEvents) {
      event.sendComplete();
    }
  }
  /** Serializes, batches, and sends events */
  protected void send() {
    // Ensure that the serialized event string is under MAXEVENTSIZEINBYTES.
    // If it is over MAXEVENTSIZEINBYTES then we should use 2 or more strings and send them
    for (IStorage storage : storages) {
      if (executorService.isShutdown()) {
        return;
      }

      List<String> events = storage.drain();
      for (String event : events) {
        this.clientTelemetry.IncrementEventsQueuedForUpload();

        // Check to see if this single serialized event is greater than MAX_BUFFER_SIZE, if it is we
        // drop it.
        if (event.length()
            > SettingsStore.getCllSettingsAsInt(SettingsStore.Settings.MAXEVENTSIZEINBYTES)) {

          // This could cause big problems if the host application decides to do a ton of processing
          // for each
          // dropped event.
          for (ICllEvents cllEvent : cllEvents) {
            cllEvent.eventDropped(event);
          }

          continue;
        }

        if (batcher.canAddToBatch(event)) {
          try {
            batcher.addEventToBatch(event);
          } catch (EventBatcher.BatchFullException e) {
            logger.error(TAG, "Could not add to batch");
          }
        } else {
          // Full batch, send events
          String batchedEvents = batcher.getBatchedEvents();

          try {
            batcher.addEventToBatch(event);
          } catch (EventBatcher.BatchFullException e) {
            logger.error(TAG, "Could not add to batch");
          }

          boolean sendResult = sendBatch(batchedEvents, storage);
          if (sendResult == false) {
            storage.close();
            return;
          }
        }
      }

      // Send remaining events that didn't fill a whole batch
      String batchedEvents = batcher.getBatchedEvents();
      boolean sendResult = sendBatch(batchedEvents, storage);
      if (sendResult == false) {
        storage.close();
        return;
      }

      storage.discard();
    }

    logger.info(TAG, "Sent " + clientTelemetry.snapshot.getEventsQueuedForUpload() + " events.");

    for (ICllEvents event : cllEvents) {
      event.sendComplete();
    }
  }