static void sendEventChanges(DhisApi dhisApi, Event event) throws APIException {
    if (event == null) {
      return;
    }

    if (Utils.isLocal(event.getEnrollment())
        && event.getEnrollment()
            != null /*if enrollments==null, then it is probably a single event without reg*/) {
      return;
    }

    if (event.getCreated() == null) {
      postEvent(event, dhisApi);
    } else {
      putEvent(event, dhisApi);
    }
  }
  static void sendEnrollmentChanges(
      DhisApi dhisApi, List<Enrollment> enrollments, boolean sendEvents) throws APIException {
    if (enrollments == null || enrollments.isEmpty()) {
      return;
    }

    for (int i = 0; i < enrollments.size(); i++) {
        /* workaround for not attempting to upload enrollments with local tei reference*/
      Enrollment enrollment = enrollments.get(i);
      if (Utils.isLocal(enrollment.getTrackedEntityInstance())) {
        enrollments.remove(i);
        i--;
      }
    }
    Log.d(CLASS_TAG, "got this many enrollments to send:" + enrollments.size());
    for (Enrollment enrollment : enrollments) {
      sendEnrollmentChanges(dhisApi, enrollment, sendEvents);
    }
  }
  static void sendEventChanges(DhisApi dhisApi, List<Event> events) throws APIException {
    if (events == null || events.isEmpty()) {
      return;
    }

    for (int i = 0; i < events.size(); i++) {
        /* removing events with local enrollment reference. In this case, the enrollment needs to be synced first*/
      Event event = events.get(i);
      if (Utils.isLocal(event.getEnrollment())
          && event.getEnrollment()
              != null /*if enrollments==null, then it is probably a single event without reg*/) {
        events.remove(i);
        i--;
        continue;
      }
    }
    Log.d(CLASS_TAG, "got this many events to send:" + events.size());

    for (Event event : events) {
      sendEventChanges(dhisApi, event);
    }
  }
  static void sendEnrollmentChanges(DhisApi dhisApi, Enrollment enrollment, boolean sendEvents)
      throws APIException {
    if (enrollment == null) {
      return;
    }
    if (Utils.isLocal(
        enrollment.getTrackedEntityInstance())) { // don't send enrollment with locally made uid
      return;
    }

    if (enrollment.getCreated() == null) {
      postEnrollment(enrollment, dhisApi);
      if (sendEvents) {
        List<Event> events = TrackerController.getEventsByEnrollment(enrollment.getLocalId());
        sendEventChanges(dhisApi, events);
      }
    } else {
      if (sendEvents) {
        List<Event> events = TrackerController.getEventsByEnrollment(enrollment.getLocalId());
        sendEventChanges(dhisApi, events);
      }
      putEnrollment(enrollment, dhisApi);
    }
  }
  private static void updateTrackedEntityInstanceReferences(
      long localId,
      String newTrackedEntityInstanceReference,
      String oldTempTrackedEntityInstanceReference) {
    // update references with uid received from server
    new Update(TrackedEntityAttributeValue.class)
        .set(
            Condition.column(TrackedEntityAttributeValue$Table.TRACKEDENTITYINSTANCEID)
                .is(newTrackedEntityInstanceReference))
        .where(
            Condition.column(TrackedEntityAttributeValue$Table.LOCALTRACKEDENTITYINSTANCEID)
                .is(localId))
        .async()
        .execute();

    new Update(Event.class)
        .set(
            Condition.column(Event$Table.TRACKEDENTITYINSTANCE)
                .is(newTrackedEntityInstanceReference))
        .where(
            Condition.column(Event$Table.TRACKEDENTITYINSTANCE)
                .is(oldTempTrackedEntityInstanceReference))
        .async()
        .execute();

    new Update(Enrollment.class)
        .set(
            Condition.column(Enrollment$Table.TRACKEDENTITYINSTANCE)
                .is(newTrackedEntityInstanceReference))
        .where(
            Condition.column(Enrollment$Table.TRACKEDENTITYINSTANCE)
                .is(oldTempTrackedEntityInstanceReference))
        .async()
        .execute();

    long updated =
        new Update(Relationship.class)
            .set(
                Condition.column(Relationship$Table.TRACKEDENTITYINSTANCEA)
                    .is(newTrackedEntityInstanceReference))
            .where(
                Condition.column(Relationship$Table.TRACKEDENTITYINSTANCEA)
                    .is(oldTempTrackedEntityInstanceReference))
            .count();

    updated +=
        new Update(Relationship.class)
            .set(
                Condition.column(Relationship$Table.TRACKEDENTITYINSTANCEB)
                    .is(newTrackedEntityInstanceReference))
            .where(
                Condition.column(Relationship$Table.TRACKEDENTITYINSTANCEB)
                    .is(oldTempTrackedEntityInstanceReference))
            .count();

    Log.d(CLASS_TAG, "updated relationships: " + updated);

    /* mechanism for triggering updating of relationships
     * a relationship can only be uploaded if both involved teis are sent to server
     * and have a valid UID.
     * So, we check if this tei was just updated with a valid reference, and if there now
     * exist >0 relationships that are valid. If >0 relationship is valid, it
     * should get uploaded, as it is the first time it has been valid. */
    boolean hasValidRelationship = false;
    if (Utils.isLocal(oldTempTrackedEntityInstanceReference)) {
      List<Relationship> teiIsB =
          new Select()
              .from(Relationship.class)
              .where(
                  Condition.column(Relationship$Table.TRACKEDENTITYINSTANCEB)
                      .is(newTrackedEntityInstanceReference))
              .queryList();
      List<Relationship> teiIsA =
          new Select()
              .from(Relationship.class)
              .where(
                  Condition.column(Relationship$Table.TRACKEDENTITYINSTANCEA)
                      .is(newTrackedEntityInstanceReference))
              .queryList();
      if (teiIsB != null) {
        for (Relationship relationship : teiIsB) {
          if (!Utils.isLocal(relationship.getTrackedEntityInstanceA())) {
            hasValidRelationship = true;
          }
        }
      }
      if (teiIsA != null) {
        for (Relationship relationship : teiIsA) {
          if (!Utils.isLocal(relationship.getTrackedEntityInstanceB())) {
            hasValidRelationship = true;
          }
        }
      }
    }
    boolean fullySynced = !(hasValidRelationship && updated > 0);

    new Update(TrackedEntityInstance.class)
        .set(
            Condition.column(TrackedEntityInstance$Table.TRACKEDENTITYINSTANCE)
                .is(newTrackedEntityInstanceReference),
            Condition.column(TrackedEntityInstance$Table.FROMSERVER).is(fullySynced))
        .where(Condition.column(TrackedEntityInstance$Table.LOCALID).is(localId))
        .async()
        .execute();
  }