/**
   * Adds resources for contact.
   *
   * @param tip the tool tip
   * @param protocolContact the protocol contact, which resources we're looking for
   */
  private void addContactResourceTooltipLines(ExtendedTooltip tip, Contact protocolContact) {
    Collection<ContactResource> contactResources = protocolContact.getResources();

    if (contactResources == null) return;

    Iterator<ContactResource> resourcesIter = contactResources.iterator();

    while (resourcesIter.hasNext()) {
      ContactResource contactResource = resourcesIter.next();

      // We only add the status icon if we have more than one resources,
      // otherwise it will always be identical to the contact status icon.
      ImageIcon protocolStatusIcon = null;
      if (contactResources.size() > 1) {
        protocolStatusIcon =
            ImageLoader.getIndexedProtocolIcon(
                ImageUtils.getBytesInImage(contactResource.getPresenceStatus().getStatusIcon()),
                protocolContact.getProtocolProvider());
      }

      String resourceName =
          (contactResource.getPriority() >= 0)
              ? contactResource.getResourceName() + " (" + contactResource.getPriority() + ")"
              : contactResource.getResourceName();

      if (protocolStatusIcon == null) tip.addSubLine(protocolStatusIcon, resourceName, 27);
      else tip.addSubLine(protocolStatusIcon, resourceName, 20);
    }

    tip.revalidate();
    tip.repaint();
  }
  /**
   * Gets the avatar of a specific <tt>MetaContact</tt> in the form of an <tt>ImageIcon</tt> value.
   *
   * @param isSelected indicates if the contact is selected
   * @param width the desired icon width
   * @param height the desired icon height
   * @return an <tt>ImageIcon</tt> which represents the avatar of the specified <tt>MetaContact</tt>
   */
  public ImageIcon getAvatar(boolean isSelected, int width, int height) {
    byte[] avatarBytes = metaContact.getAvatar(true);

    // If there's no avatar we have nothing more to do here.
    if ((avatarBytes == null) || (avatarBytes.length <= 0)) {
      if (!subscribed) {
        return ImageUtils.getScaledRoundedIcon(
            ImageLoader.getImage(ImageLoader.UNAUTHORIZED_CONTACT_PHOTO), width, height);
      }

      return null;
    }

    // If the cell is selected we return a zoomed version of the avatar
    // image.
    if (isSelected) return ImageUtils.getScaledRoundedIcon(avatarBytes, width, height);

    // In any other case try to get the avatar from the cache.
    Object[] avatarCache = (Object[]) metaContact.getData(AVATAR_DATA_KEY);
    ImageIcon avatar = null;

    if ((avatarCache != null) && (avatarCache[0] == avatarBytes))
      avatar = (ImageIcon) avatarCache[1];

    // If the avatar isn't available or it's not up-to-date, create it.
    if (avatar == null) {
      avatar = ImageUtils.getScaledRoundedIcon(avatarBytes, width, height);
    }

    // Cache the avatar in case it has changed.
    if (avatarCache == null) {
      if (avatar != null) metaContact.setData(AVATAR_DATA_KEY, new Object[] {avatarBytes, avatar});
    } else {
      avatarCache[0] = avatarBytes;
      avatarCache[1] = avatar;
    }

    return avatar;
  }
  /**
   * Loads the tooltip with the data for current metacontact.
   *
   * @param tip the tooltip to fill.
   */
  private void loadTooltip(final ExtendedTooltip tip) {
    Iterator<Contact> i = metaContact.getContacts();

    ContactPhoneUtil contactPhoneUtil = ContactPhoneUtil.getPhoneUtil(metaContact);

    String statusMessage = null;
    Contact protocolContact;
    boolean isLoading = false;
    while (i.hasNext()) {
      protocolContact = i.next();

      // Set the first found status message.
      if (statusMessage == null
          && protocolContact.getStatusMessage() != null
          && protocolContact.getStatusMessage().length() > 0)
        statusMessage = protocolContact.getStatusMessage();

      if (ConfigurationUtils.isHideAccountStatusSelectorsEnabled()) break;

      ImageIcon protocolStatusIcon =
          ImageLoader.getIndexedProtocolIcon(
              ImageUtils.getBytesInImage(protocolContact.getPresenceStatus().getStatusIcon()),
              protocolContact.getProtocolProvider());

      String contactAddress = protocolContact.getAddress();
      // String statusMessage = protocolContact.getStatusMessage();

      tip.addLine(protocolStatusIcon, contactAddress);

      addContactResourceTooltipLines(tip, protocolContact);

      if (!protocolContact.getProtocolProvider().isRegistered()) continue;

      contactPhoneUtil.addDetailsResponseListener(
          protocolContact,
          new OperationSetServerStoredContactInfo.DetailsResponseListener() {
            public void detailsRetrieved(final Iterator<GenericDetail> details) {
              if (!SwingUtilities.isEventDispatchThread()) {
                SwingUtilities.invokeLater(
                    new Runnable() {
                      public void run() {
                        detailsRetrieved(details);
                      }
                    });
                return;
              }

              // remove previously shown information
              // as it contains "Loading..." text
              tip.removeAllLines();

              // load it again
              loadTooltip(tip);
            }
          });

      List<String> phones = contactPhoneUtil.getPhones(protocolContact);

      if (phones != null) {
        addPhoneTooltipLines(tip, phones.iterator());
      } else isLoading = true;
    }

    if (isLoading)
      tip.addLine(null, GuiActivator.getResources().getI18NString("service.gui.LOADING"));

    if (statusMessage != null) tip.setBottomText(statusMessage);
  }