/**
   * Used by functions testing the queryContactStatus method of the presence operation set.
   *
   * @param taStatusLong the icq status as specified by FullUserInfo, that the tester agent should
   *     switch to.
   * @param expectedReturn the PresenceStatus that the presence operation set should see the tester
   *     agent in once it has switched to taStatusLong.
   * @throws java.lang.Exception if querying the status causes some exception.
   */
  public void subtestQueryContactStatus(long taStatusLong, PresenceStatus expectedReturn)
      throws Exception {
    if (!fixture.testerAgent.enterStatus(taStatusLong)) {
      throw new RuntimeException(
          "Tester UserAgent Failed to switch to the " + expectedReturn.getStatusName() + " state.");
    }

    PresenceStatus actualReturn =
        operationSetPresence.queryContactStatus(fixture.testerAgent.getIcqUIN());
    assertEquals(
        "Querying a " + expectedReturn.getStatusName() + " state did not return as expected",
        expectedReturn,
        actualReturn);
  }
  /**
   * Publish present status. We search for the highest value in the given interval.
   *
   * @param protocolProvider the protocol provider to which we change the status.
   * @param status the status tu publish.
   */
  public void publishStatus(
      ProtocolProviderService protocolProvider, PresenceStatus status, boolean rememberStatus) {
    OperationSetPresence presence = protocolProvider.getOperationSet(OperationSetPresence.class);

    LoginManager loginManager = GuiActivator.getUIService().getLoginManager();
    RegistrationState registrationState = protocolProvider.getRegistrationState();

    if (registrationState == RegistrationState.REGISTERED
        && presence != null
        && !presence.getPresenceStatus().equals(status)) {
      if (status.isOnline()) {
        new PublishPresenceStatusThread(protocolProvider, presence, status).start();
      } else {
        loginManager.setManuallyDisconnected(true);
        GuiActivator.getUIService().getLoginManager().logoff(protocolProvider);
      }
    } else if (registrationState != RegistrationState.REGISTERED
        && registrationState != RegistrationState.REGISTERING
        && registrationState != RegistrationState.AUTHENTICATING
        && status.isOnline()) {
      GuiActivator.getUIService().getLoginManager().login(protocolProvider);
    } else if (!status.isOnline() && !(registrationState == RegistrationState.UNREGISTERING)) {
      loginManager.setManuallyDisconnected(true);
      GuiActivator.getUIService().getLoginManager().logoff(protocolProvider);
    }

    if (rememberStatus) saveStatusInformation(protocolProvider, status.getStatusName());
  }
  /**
   * Returns the last status that was stored in the configuration for the given protocol provider.
   *
   * @param protocolProvider the protocol provider
   * @return the last status that was stored in the configuration for the given protocol provider
   */
  public PresenceStatus getLastPresenceStatus(ProtocolProviderService protocolProvider) {
    String lastStatus = getLastStatusString(protocolProvider);

    if (lastStatus != null) {
      OperationSetPresence presence = protocolProvider.getOperationSet(OperationSetPresence.class);

      if (presence == null) return null;

      Iterator<PresenceStatus> i = presence.getSupportedStatusSet();
      PresenceStatus status;

      while (i.hasNext()) {
        status = i.next();
        if (status.getStatusName().equals(lastStatus)) return status;
      }
    }
    return null;
  }
  /**
   * Publish present status. We search for the highest value in the given interval.
   *
   * @param protocolProvider the protocol provider to which we change the status.
   * @param floorStatusValue the min status value.
   * @param ceilStatusValue the max status value.
   */
  private void publishStatus(
      ProtocolProviderService protocolProvider, int floorStatusValue, int ceilStatusValue) {
    if (!protocolProvider.isRegistered()) return;

    OperationSetPresence presence = protocolProvider.getOperationSet(OperationSetPresence.class);

    if (presence == null) return;

    Iterator<PresenceStatus> statusSet = presence.getSupportedStatusSet();

    PresenceStatus status = null;

    while (statusSet.hasNext()) {
      PresenceStatus currentStatus = statusSet.next();

      if (status == null
          && currentStatus.getStatus() < ceilStatusValue
          && currentStatus.getStatus() >= floorStatusValue) {
        status = currentStatus;
      }

      if (status != null) {
        if (currentStatus.getStatus() < ceilStatusValue
            && currentStatus.getStatus() >= floorStatusValue
            && currentStatus.getStatus() > status.getStatus()) {
          status = currentStatus;
        }
      }
    }

    if (status != null) {
      new PublishPresenceStatusThread(protocolProvider, presence, status).start();

      this.saveStatusInformation(protocolProvider, status.getStatusName());
    }
  }
  /**
   * Publish present status. We search for the highest value in the given interval.
   *
   * <p>change the status.
   *
   * @param globalStatus
   */
  public void publishStatus(GlobalStatusEnum globalStatus) {
    String itemName = globalStatus.getStatusName();

    Iterator<ProtocolProviderService> pProviders =
        GuiActivator.getUIService().getMainFrame().getProtocolProviders();

    while (pProviders.hasNext()) {
      ProtocolProviderService protocolProvider = pProviders.next();

      if (itemName.equals(GlobalStatusEnum.ONLINE_STATUS)) {
        if (!protocolProvider.isRegistered()) {
          saveStatusInformation(protocolProvider, itemName);

          GuiActivator.getUIService().getLoginManager().login(protocolProvider);
        } else {
          OperationSetPresence presence =
              protocolProvider.getOperationSet(OperationSetPresence.class);

          if (presence == null) {
            saveStatusInformation(protocolProvider, itemName);

            continue;
          }

          Iterator<PresenceStatus> statusSet = presence.getSupportedStatusSet();

          while (statusSet.hasNext()) {
            PresenceStatus status = statusSet.next();

            if (status.getStatus() < PresenceStatus.EAGER_TO_COMMUNICATE_THRESHOLD
                && status.getStatus() >= PresenceStatus.AVAILABLE_THRESHOLD) {
              new PublishPresenceStatusThread(protocolProvider, presence, status).start();

              this.saveStatusInformation(protocolProvider, status.getStatusName());

              break;
            }
          }
        }
      } else if (itemName.equals(GlobalStatusEnum.OFFLINE_STATUS)) {
        if (!protocolProvider.getRegistrationState().equals(RegistrationState.UNREGISTERED)
            && !protocolProvider.getRegistrationState().equals(RegistrationState.UNREGISTERING)) {
          OperationSetPresence presence =
              protocolProvider.getOperationSet(OperationSetPresence.class);

          if (presence == null) {
            saveStatusInformation(protocolProvider, itemName);

            GuiActivator.getUIService().getLoginManager().logoff(protocolProvider);

            continue;
          }

          Iterator<PresenceStatus> statusSet = presence.getSupportedStatusSet();

          while (statusSet.hasNext()) {
            PresenceStatus status = statusSet.next();

            if (status.getStatus() < PresenceStatus.ONLINE_THRESHOLD) {
              this.saveStatusInformation(protocolProvider, status.getStatusName());

              break;
            }
          }

          try {
            protocolProvider.unregister();
          } catch (OperationFailedException e1) {
            logger.error(
                "Unable to unregister the protocol provider: "
                    + protocolProvider
                    + " due to the following exception: "
                    + e1);
          }
        }
      } else if (itemName.equals(GlobalStatusEnum.FREE_FOR_CHAT_STATUS)) {
        // we search for highest available status here
        publishStatus(
            protocolProvider, PresenceStatus.AVAILABLE_THRESHOLD, PresenceStatus.MAX_STATUS_VALUE);
      } else if (itemName.equals(GlobalStatusEnum.DO_NOT_DISTURB_STATUS)) {
        // status between online and away is DND
        publishStatus(
            protocolProvider, PresenceStatus.ONLINE_THRESHOLD, PresenceStatus.AWAY_THRESHOLD);
      } else if (itemName.equals(GlobalStatusEnum.AWAY_STATUS)) {
        // a status in the away interval
        publishStatus(
            protocolProvider, PresenceStatus.AWAY_THRESHOLD, PresenceStatus.AVAILABLE_THRESHOLD);
      }
    }
  }
  /**
   * Used by methods testing state transiotions
   *
   * @param newStatus the IcqStatusEnum field corresponding to the status that we'd like the
   *     opeation set to enter.
   * @throws Exception in case changing the state causes an exception
   */
  public void subtestStateTransition(IcqStatusEnum newStatus) throws Exception {
    logger.trace(" --=== beginning state transition test ===--");

    PresenceStatus oldStatus = operationSetPresence.getPresenceStatus();
    String oldStatusMessage = operationSetPresence.getCurrentStatusMessage();
    String newStatusMessage = statusMessageRoot + newStatus;

    logger.debug(
        "old status is=" + oldStatus.getStatusName() + " new status=" + newStatus.getStatusName());

    // First register a listener to make sure that all corresponding
    // events have been generated.
    PresenceStatusEventCollector statusEventCollector = new PresenceStatusEventCollector();
    operationSetPresence.addProviderPresenceStatusListener(statusEventCollector);

    // change the status
    operationSetPresence.publishPresenceStatus(newStatus, newStatusMessage);

    // test event notification.
    statusEventCollector.waitForPresEvent(10000);
    statusEventCollector.waitForStatMsgEvent(10000);

    // sometimes we don't get response from the server for the
    // changed status. we will query it once again.
    // and wait for the response
    if (statusEventCollector.collectedPresEvents.size() == 0) {
      logger.trace("Will query again status as we haven't received one");
      operationSetPresence.queryContactStatus(fixture.icqAccountID.getUserID());
      statusEventCollector.waitForPresEvent(10000);
    }

    operationSetPresence.removeProviderPresenceStatusListener(statusEventCollector);

    assertEquals(
        "Events dispatched during an event transition.",
        1,
        statusEventCollector.collectedPresEvents.size());
    assertEquals(
        "A status changed event contained wrong old status.",
        oldStatus,
        ((ProviderPresenceStatusChangeEvent) statusEventCollector.collectedPresEvents.get(0))
            .getOldStatus());
    assertEquals(
        "A status changed event contained wrong new status.",
        newStatus,
        ((ProviderPresenceStatusChangeEvent) statusEventCollector.collectedPresEvents.get(0))
            .getNewStatus());

    // verify that the operation set itself is aware of the status change
    assertEquals(
        "opSet.getPresenceStatus() did not return properly.",
        newStatus,
        operationSetPresence.getPresenceStatus());

    IcqStatusEnum actualStatus =
        fixture.testerAgent.getBuddyStatus(fixture.icqAccountID.getUserID());
    assertEquals(
        "The underlying implementation did not switch to the " + "requested presence status.",
        newStatus,
        actualStatus);

    // check whether the server returned the status message that we've set.
    assertEquals(
        "No status message events.", 1, statusEventCollector.collectedStatMsgEvents.size());
    assertEquals(
        "A status message event contained wrong old value.",
        oldStatusMessage,
        ((PropertyChangeEvent) statusEventCollector.collectedStatMsgEvents.get(0)).getOldValue());
    assertEquals(
        "A status message event contained wrong new value.",
        newStatusMessage,
        ((PropertyChangeEvent) statusEventCollector.collectedStatMsgEvents.get(0)).getNewValue());

    // verify that the operation set itself is aware of the new status msg.
    assertEquals(
        "opSet.getCurrentStatusMessage() did not return properly.",
        newStatusMessage,
        operationSetPresence.getCurrentStatusMessage());

    logger.trace(" --=== finished test ===--");
    // make it sleep a bit cause the aol server gets mad otherwise.
    pauseBetweenStateChanges();
  }