public String createWaitForUpdate(
      RemoteDesktopServerEvent e, List events, UserConfiguration cfg) {

    boolean insertUpdateArea = this.insertUpdateArea;
    boolean insertUpdateExtent = this.insertUpdateExtent;
    float defaultUpdateExtent = this.defaultUpdateExtent;
    boolean insertUpdateTimeout = this.insertUpdateTimeout;
    float timeoutUpdateRatio = this.timeoutUpdateRatio;
    boolean useMinUpdateTimeout = this.useMinUpdateTimeout;
    long minUpdateTimeout = this.minUpdateTimeout;
    boolean useUpdateWait = this.useUpdateWait;
    boolean useMinUpdateWait = this.useMinUpdateWait;
    float waitUpdateRatio = this.waitUpdateRatio;
    long minUpdateWait = this.minUpdateWait;

    if (cfg != null) {
      insertUpdateArea = cfg.getBoolean("recording.waitfor.update.insertArea").booleanValue();
      insertUpdateExtent = cfg.getBoolean("recording.waitfor.update.insertExtent").booleanValue();
      defaultUpdateExtent = cfg.getInteger("recording.waitfor.update.defaultExtent").intValue();
      insertUpdateTimeout = cfg.getBoolean("recording.waitfor.update.insertTimeout").booleanValue();
      timeoutUpdateRatio = cfg.getDouble("recording.waitfor.update.timeoutRatio").floatValue();
      useMinUpdateTimeout = cfg.getBoolean("recording.waitfor.update.useMinTimeout").booleanValue();
      minUpdateTimeout = cfg.getInteger("recording.waitfor.update.minTimeout").intValue();
      useUpdateWait = cfg.getBoolean("recording.waitfor.update.useWait").booleanValue();
      useMinUpdateWait = cfg.getBoolean("recording.waitfor.update.useMinWait").booleanValue();
      waitUpdateRatio = cfg.getDouble("recording.waitfor.update.waitRatio").floatValue();
      minUpdateWait = cfg.getInteger("recording.waitfor.update.minWait").intValue();
    }

    String s = "Waitfor " + WaitforCommand.EVENT_UPDATE;
    if (insertUpdateArea) {
      s += " " + WaitforCommand.PARAM_AREA + "=" + parser.rectToString(e.getUpdateRect());
    }

    if (insertUpdateExtent) {
      float extent = defaultUpdateExtent;

      // If the 'area' param is not included, we must calculate a relative update compared to the
      // whole screen
      if (!insertUpdateArea) {
        RfbClient rfb = (RfbClient) e.getSource();
        extent =
            defaultUpdateExtent
                * ((float) (e.getUpdateRect().width * e.getUpdateRect().height)
                    / (rfb.getDesktopWidth() * rfb.getDesktopHeight()));
      }
      s += " " + WaitforCommand.PARAM_EXTENT + "=" + extent + "%";
    }

    long time = e.getWhen();
    //        System.out.println("base event, time="+e.getWhen());

    RemoteDesktopServerEvent evt;
    int count = 1;
    for (int i = 0; i < events.size(); i++) {
      evt = (RemoteDesktopServerEvent) events.get(i);
      if (!e.equals(evt)
          && isUpdateApplicable(e, evt, insertUpdateExtent ? defaultUpdateExtent : 100)) {
        count++;
        time = Math.max(time, evt.getWhen());
        //                System.out.println("applicable event #"+i+" found, time="+evt.getWhen());
      }
    }

    //        System.out.println("final time="+time);
    if (count > 1) {
      if (!useUpdateWait) {
        s += " " + WaitforCommand.PARAM_COUNT + "=" + count;
      } else {
        long wait = (long) ((e.getWhen() - lastEventListUpdateTime) * waitUpdateRatio);
        if (useMinUpdateWait) {
          wait = wait > minUpdateWait ? wait : minUpdateWait;
        }
        s += " " + WaitforCommand.PARAM_WAIT + "=" + wait;
      }
    }

    if (insertUpdateTimeout) {
      time = (long) ((time - lastEventListUpdateTime) * timeoutUpdateRatio);
      if (useMinUpdateTimeout) {
        time = time > minUpdateTimeout ? time : minUpdateTimeout;
      }
      s += " " + WaitforCommand.PARAM_TIMEOUT + "=" + time;
    }
    return s;
  }