/* (non-Javadoc)
   * @see net.xeoh.plugins.remotediscovery.impl.v4.probes.AbstractProbe#shutdown()
   */
  @Override
  public void shutdown() {
    super.shutdown();

    try {
      this.timer.cancel();
    } catch (final Exception e) {
      //
    }

    final java.lang.Thread t =
        new java.lang.Thread(
            new Runnable() {

              public void run() {
                NetworkProbe.this.jmdnsLock.lock();

                // All of these statements tend to fail because of various reasons. During the
                // shutdown however,
                // we want to ignore them all ...
                try {
                  try {
                    NetworkProbe.this.localManagerExportServer.close();
                  } catch (final Exception e) {
                    //
                  }
                  try {
                    NetworkProbe.this.jmdns.unregisterAllServices();
                  } catch (final Exception e) {
                    //
                  }
                  try {
                    NetworkProbe.this.jmdns.close();
                  } catch (final Exception e) {
                    //
                  }
                } finally {
                  NetworkProbe.this.jmdnsLock.unlock();
                }
              }
            });
    t.setDaemon(true);
    t.start();
  }
  /** @return */
  private boolean awaitInitializationTime() {
    // Check if we're still on startup lock
    final long delay = this.timeOfStartup + this.startupLock - System.currentTimeMillis();
    if (delay > 0) {
      // If we are, halt this thread until lock time has passed. Unfortunatly the lookup is a
      // bit "unstable" during the first few miliseconds.
      try {
        java.lang.Thread.sleep(delay);
      } catch (final InterruptedException e) {
        e.printStackTrace();
        return false;
      }
    }

    return true;
  }
  /**
   * @param plugin
   * @param options
   * @return .
   */
  @Override
  public Collection<DiscoveredPlugin> discover(
      final Class<? extends Plugin> plugin, final DiscoverOption... options) {

    this.logger.status("discover/start", "plugin", plugin);

    // Wait until init is done ...
    try {
      this.startupLatch.await();
    } catch (final InterruptedException e) {
      return new ArrayList<DiscoveredPlugin>();
    }

    // Timelock: Wait for a certain time to pass since startup
    if (this.lockMode.equals("timelock")) {
      if (awaitInitializationTime() == false) return new ArrayList<DiscoveredPlugin>();
    }

    // Onepass: Wait for the discover to execute once
    if (this.lockMode.equals("onepass")) {

      // Also wait some time here, otherwise we won't find all plugins in all cases
      awaitInitializationTime();

      // Wait at least one discoverThreadTurn
      final long lastDisoverValue = this.discoverThreadCounter.get();
      final long startOfWait = System.currentTimeMillis();
      while (this.discoverThreadCounter.get() == lastDisoverValue) {
        try {
          java.lang.Thread.sleep(100);
        } catch (final InterruptedException e) {
          e.printStackTrace();
          return new ArrayList<DiscoveredPlugin>();
        }

        // Safety check
        if (System.currentTimeMillis() > startOfWait + 1000)
          throw new IllegalStateException("We are waiting way too long.");
      }
    }

    this.logger.status("discover/end");

    // Eventually resolve the request.
    return resolve(plugin, options);
  }