public void doOptimization(ReconnectResult res, ProcessCallBackAdapter processCallBackAdapter) throws InterruptedException {
        java.util.List<ReconnectResult> list = new ArrayList<ReconnectResult>();
        list.add(res);
        // int failed = 0;
        int success = 1;
        long duration = res.getSuccessDuration();
        long offlineDuration = res.getOfflineDuration();
        long maxOfflineDuration = res.getOfflineDuration();
        long maxSuccessDuration = res.getSuccessDuration();
        long startTime = res.getStartTime();
        for (int i = 1; i < JsonConfig.create(ReconnectConfig.class).getOptimizationRounds(); i++) {
            processCallBackAdapter.setProgress(this, (i * 100) / JsonConfig.create(ReconnectConfig.class).getOptimizationRounds());
            ReconnectResult r;
            try {
                r = validate();
            } catch (ReconnectException e) {
                e.printStackTrace();
                r = createReconnectResult();
            }
            list.add(r);
            if (r.isSuccess()) {

                success++;
                duration += r.getSuccessDuration();
                startTime = r.getStartTime();
                offlineDuration = Math.min(offlineDuration, r.getOfflineDuration());
                maxOfflineDuration = Math.max(maxOfflineDuration, r.getOfflineDuration());
                maxSuccessDuration = Math.max(maxSuccessDuration, r.getSuccessDuration());
            }

        }
        duration /= success;
        double successRate = success / (double) JsonConfig.create(ReconnectConfig.class).getOptimizationRounds();
        // increase successduration if successrate is lower than 1.0 (100%)
        res.setAverageSuccessDuration((long) (duration / successRate));
        res.setMaxOfflineDuration(maxOfflineDuration * 2);
        res.setMaxSuccessDuration(maxSuccessDuration * 4);
        res.setOfflineTime(offlineDuration);
        res.setStartTime(startTime);

    }
    protected ReconnectResult validate(ReconnectResult ret) throws InterruptedException, ReconnectException {
        ret.setInvoker(this);

        // Make sure that we are online

        if (IPController.getInstance().getIpState().isOffline()) {
            IPController.getInstance().invalidate();
            Thread.sleep(1000);
            IPController.getInstance().validate();
            if (IPController.getInstance().getIpState().isOffline()) {
                throw new ReconnectException(_GUI._.ReconnectInvoker_validate_offline_());
            }

        }
        logger.info("IP BEFORE=" + IPController.getInstance().getIP());

        try {
            IPController.getInstance().invalidate();
            ret.setStartTime(System.currentTimeMillis());
            testRun();
            Thread.sleep(1 * 1000);
            IPController ipc = IPController.getInstance();
            if (ipc.validate()) {
                // wow this hsa been fast
                logger.info("Successful: REconnect has been very fast!");
                ret.setSuccess(true);
                ret.setOfflineTime(System.currentTimeMillis());
                ret.setSuccessTime(System.currentTimeMillis());
                return ret;
            }
            logger.info("Script done. Wait for offline");
            do {
                // wait until we are offline
                Thread.sleep(1 * 1000);
                if (!ipc.validate() && !ipc.getIpState().isOffline() && (System.currentTimeMillis() - ret.getStartTime()) > OFFLINE_TIMEOUT) {
                    // we are not offline after 30 seconds
                    logger.info("Disconnect failed. Still online after " + OFFLINE_TIMEOUT + " ms");
                    return ret;
                }
            } while (!ipc.getIpState().isOffline() && ipc.isInvalidated());
            ret.setOfflineTime(System.currentTimeMillis());
            logger.info("Offline after " + ret.getOfflineDuration() + " ms");
            if (ipc.isInvalidated()) {
                logger.info("Wait for online status");
                // we have to wait LOOOONG here. reboot may take its time
                final long endTime = System.currentTimeMillis() + 450 * 1000;
                while (System.currentTimeMillis() < endTime) {
                    /* ip change detected then we can stop */
                    long s = System.currentTimeMillis();
                    if (Thread.currentThread().isInterrupted()) {
                        throw new InterruptedException();
                    }
                    if (ipc.validate()) {
                        ret.setSuccessTime(System.currentTimeMillis());
                        ret.setSuccess(true);
                        logger.info("Successful: REconnect after " + ret.getSuccessDuration() + " ms");

                        return ret;
                        //
                    }
                    if (!ipc.getIpState().isOffline()) {
                        logger.info("Failed. returned from offline. But no new ip");
                        return ret;

                    }

                    Thread.sleep(Math.max(0, 1000 - (System.currentTimeMillis() - s)));
                }
                logger.info("Connect failed! Maybe router restart is required. This should NEVER happen!");
                return ret;
            } else {
                ret.setSuccessTime(System.currentTimeMillis());
                ret.setSuccess(true);
                logger.info("Successful: REconnect after " + ret.getSuccessDuration() + " ms");
                return ret;
            }
        } finally {
            logger.info("IP AFTER=" + IPController.getInstance().getIP());
        }
    }
  public java.util.List<ReconnectResult> autoFind(final ProcessCallBack feedback)
      throws InterruptedException {

    StatsManager.I().track("reconnectAutoFind/start");
    final java.util.List<ReconnectResult> scripts = new ArrayList<ReconnectResult>();

    for (final RouterPlugin plg : ReconnectPluginController.this.plugins) {
      if (Thread.currentThread().isInterrupted()) {
        throw new InterruptedException();
      }
      if (plg instanceof UPNPRouterPlugin || plg instanceof LiveHeaderReconnect) {
        try {

          feedback.setStatus(plg, null);

          java.util.List<ReconnectResult> founds = plg.runDetectionWizard(feedback);

          if (founds != null) {
            scripts.addAll(founds);
          }
          if (scripts.size() > 0) {
            break;
          }
        } catch (InterruptedException e) {
          throw e;
        } catch (Exception e) {

        }
      }
    }
    if (scripts.size() > 0) {
      HashMap<String, String> map = new HashMap<String, String>();
      map.put("plg", scripts.get(0).getInvoker().getPlugin().getID());
      StatsManager.I().track("reconnectAutoFind/success", map);
    } else {
      StatsManager.I().track("reconnectAutoFind/failed");
    }
    if (JsonConfig.create(ReconnectConfig.class).getOptimizationRounds() > 1
        && scripts.size() > 0) {
      int i = 1;
      long bestTime = Long.MAX_VALUE;
      long optiduration = 0;
      for (ReconnectResult found : scripts) {

        bestTime = Math.min(bestTime, found.getSuccessDuration());
        optiduration +=
            found.getSuccessDuration()
                * (JsonConfig.create(ReconnectConfig.class).getOptimizationRounds() - 1)
                * 1.5;
      }
      try {

        Dialog.getInstance()
            .showConfirmDialog(
                0,
                _GUI.T.AutoDetectAction_actionPerformed_dooptimization_title(),
                _GUI.T.AutoDetectAction_actionPerformed_dooptimization_msg(
                    scripts.size(),
                    TimeFormatter.formatMilliSeconds(optiduration, 0),
                    TimeFormatter.formatMilliSeconds(bestTime, 0)),
                new AbstractIcon(IconKey.ICON_OK, 32),
                _GUI.T.AutoDetectAction_run_optimization(),
                _GUI.T.AutoDetectAction_skip_optimization());
        feedback.setProgress(this, 0);
        for (int ii = 0; ii < scripts.size(); ii++) {
          ReconnectResult found = scripts.get(ii);
          feedback.setStatusString(
              this, _GUI.T.AutoDetectAction_run_optimize(found.getInvoker().getName()));
          final int step = ii;
          found.optimize(
              new ProcessCallBackAdapter() {

                public void setProgress(Object caller, int percent) {
                  feedback.setProgress(
                      caller, (step) * (100 / scripts.size()) + percent / scripts.size());
                }

                public void setStatusString(Object caller, String string) {
                  feedback.setStatusString(caller, _GUI.T.AutoDetectAction_run_optimize(string));
                }
              });
        }
      } catch (DialogNoAnswerException e) {

      }
    }
    try {
      Collections.sort(
          scripts,
          new Comparator<ReconnectResult>() {

            public int compare(ReconnectResult o1, ReconnectResult o2) {
              return new Long(o1.getAverageSuccessDuration())
                  .compareTo(new Long(o2.getAverageSuccessDuration()));
            }
          });
    } catch (final Throwable e) {

      org.appwork.utils.logging2.extmanager.LoggerFactory.getDefaultLogger().log(e);
    }
    return scripts;
  }