/**
   * Joins the given chat room with the given password and manages all the exceptions that could
   * occur during the join process.
   *
   * @param chatRoomWrapper the chat room to join.
   * @param nickName the nickname we choose for the given chat room.
   * @param password the password.
   * @param rememberPassword if true the password should be saved.
   * @param isFirstAttempt is this the first attempt to join room, used to check whether to show
   *     some error messages
   * @param subject the subject which will be set to the room after the user join successful.
   */
  private void joinChatRoom(
      ChatRoomWrapper chatRoomWrapper,
      String nickName,
      byte[] password,
      boolean rememberPassword,
      boolean isFirstAttempt,
      String subject) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.WARNING"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_CONNECTED",
                      new String[] {chatRoomWrapper.getChatRoomName()}));
      return;
    }

    new JoinChatRoomTask(
            (ChatRoomWrapperImpl) chatRoomWrapper,
            nickName,
            password,
            rememberPassword,
            isFirstAttempt,
            subject)
        .start();
  }
 @Override
 public void run() {
   ChatRoomWrapper leavedRoomWrapped =
       MUCActivator.getMUCService().leaveChatRoom(chatRoomWrapper);
   if (leavedRoomWrapped != null)
     MUCActivator.getUIService().closeChatRoomWindow(leavedRoomWrapped);
 }
  /**
   * Leaves the given chat room.
   *
   * @param chatRoomWrapper the chat room to leave.
   * @return <tt>ChatRoomWrapper</tt> instance associated with the chat room.
   */
  public ChatRoomWrapper leaveChatRoom(ChatRoomWrapper chatRoomWrapper) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      ResourceManagementService resources = MUCActivator.getResources();

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              resources.getI18NString("service.gui.WARNING"),
              resources.getI18NString("service.gui.CHAT_ROOM_LEAVE_NOT_CONNECTED"));

      return null;
    }

    if (chatRoom.isJoined()) chatRoom.leave();

    ChatRoomWrapper existChatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

    if (existChatRoomWrapper == null) return null;

    // We save the choice of the user, before the chat room is really
    // joined, because even the join fails we want the next time when
    // we login to join this chat room automatically.
    ConfigurationUtils.updateChatRoomStatus(
        chatRoomWrapper.getParentProvider().getProtocolProvider(),
        chatRoomWrapper.getChatRoomID(),
        GlobalStatusEnum.OFFLINE_STATUS);

    return existChatRoomWrapper;
  }
        @Override
        public void run() {
          String[] joinOptions;
          String subject = null;
          String nickName = null;

          nickName =
              ConfigurationUtils.getChatRoomProperty(
                  chatRoomWrapper.getParentProvider().getProtocolProvider(),
                  chatRoomWrapper.getChatRoomID(),
                  "userNickName");
          if (nickName == null) {
            joinOptions =
                ChatRoomJoinOptionsDialog.getJoinOptions(
                    chatRoomWrapper.getParentProvider().getProtocolProvider(),
                    chatRoomWrapper.getChatRoomID(),
                    MUCActivator.getMUCService()
                        .getDefaultNickname(
                            chatRoomWrapper.getParentProvider().getProtocolProvider()));
            nickName = joinOptions[0];
            subject = joinOptions[1];
          }

          if (nickName != null)
            MUCActivator.getMUCService().joinChatRoom(chatRoomWrapper, nickName, null, subject);
        }
 @Override
 public void run() {
   String[] joinOptions;
   joinOptions =
       ChatRoomJoinOptionsDialog.getJoinOptions(
           chatRoomWrapper.getParentProvider().getProtocolProvider(),
           chatRoomWrapper.getChatRoomID(),
           MUCActivator.getMUCService()
               .getDefaultNickname(chatRoomWrapper.getParentProvider().getProtocolProvider()));
   if (joinOptions[0] == null) return;
   MUCActivator.getMUCService()
       .joinChatRoom(chatRoomWrapper, joinOptions[0], null, joinOptions[1]);
 }
 @Override
 public void run() {
   MUCActivator.getUIService()
       .showChatRoomAutoOpenConfigDialog(
           chatRoomWrapper.getParentProvider().getProtocolProvider(),
           chatRoomWrapper.getChatRoomID());
 }
  /**
   * Joins the given chat room with the given password and manages all the exceptions that could
   * occur during the join process.
   *
   * @param chatRoomWrapper the chat room to join.
   * @param nickName the nickname we choose for the given chat room.
   * @param password the password.
   */
  public void joinChatRoom(ChatRoomWrapper chatRoomWrapper, String nickName, byte[] password) {
    ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

    if (chatRoom == null) {
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.WARNING"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_CONNECTED",
                      new String[] {chatRoomWrapper.getChatRoomName()}));
      return;
    }

    new JoinChatRoomTask((ChatRoomWrapperImpl) chatRoomWrapper, nickName, password).start();
  }
 @Override
 public void run() {
   ChatRoomJoinOptionsDialog.getJoinOptions(
       true,
       chatRoomWrapper.getParentProvider().getProtocolProvider(),
       chatRoomWrapper.getChatRoomID(),
       MUCActivator.getMUCService()
           .getDefaultNickname(chatRoomWrapper.getParentProvider().getProtocolProvider()));
 }
    /**
     * Checks if the menu item should be enabled or disabled.
     *
     * @param contact the contact associated with the menu item.
     * @return <tt>true</tt> if the item should be enabled and <tt>false</tt> if not.
     */
    public boolean check(SourceContact contact) {
      ChatRoomWrapper chatRoomWrapper =
          MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
      ChatRoom chatRoom = null;
      if (chatRoomWrapper != null) {
        chatRoom = chatRoomWrapper.getChatRoom();
      }

      if ((chatRoom != null) && chatRoom.isJoined()) return false;
      return true;
    }
  /**
   * Joins the room with the given name though the given chat room provider.
   *
   * @param chatRoomName the name of the room to join.
   * @param chatRoomProvider the chat room provider to join through.
   */
  public void joinChatRoom(String chatRoomName, ChatRoomProviderWrapper chatRoomProvider) {
    OperationSetMultiUserChat groupChatOpSet =
        chatRoomProvider.getProtocolProvider().getOperationSet(OperationSetMultiUserChat.class);

    ChatRoom chatRoom = null;
    try {
      chatRoom = groupChatOpSet.findRoom(chatRoomName);
    } catch (Exception e) {
      if (logger.isTraceEnabled())
        logger.trace("Un exception occurred while searching for room:" + chatRoomName, e);
    }

    if (chatRoom != null) {
      ChatRoomWrapper chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

      if (chatRoomWrapper == null) {
        ChatRoomProviderWrapper parentProvider =
            chatRoomList.findServerWrapperFromProvider(chatRoom.getParentProvider());

        chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);

        chatRoomList.addChatRoom(chatRoomWrapper);

        fireChatRoomListChangedEvent(chatRoomWrapper, ChatRoomListChangeEvent.CHAT_ROOM_ADDED);
      }
      joinChatRoom(chatRoomWrapper);
    } else
      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CHAT_ROOM_NOT_EXIST",
                      new String[] {
                        chatRoomName,
                        chatRoomProvider.getProtocolProvider().getAccountID().getService()
                      }));
  }
    @Override
    public boolean isVisible(SourceContact actionSource) {
      if (!(actionSource instanceof ChatRoomSourceContact)) return false;

      if (name.equals("autojoin") || name.equals("autojoin_pressed")) {
        ChatRoomSourceContact contact = (ChatRoomSourceContact) actionSource;
        ChatRoomWrapper room =
            MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
        if (name.equals("autojoin")) return !room.isAutojoin();

        if (name.equals("autojoin_pressed")) return room.isAutojoin();
      }
      return true;
    }
 /**
  * Destroys the given <tt>ChatRoom</tt> from the list of all chat rooms.
  *
  * @param chatRoomWrapper the <tt>ChatRoomWrapper</tt> to be destroyed.
  * @param reason the reason for destroying.
  * @param alternateAddress the alternate address.
  */
 public void destroyChatRoom(
     ChatRoomWrapper chatRoomWrapper, String reason, String alternateAddress) {
   if (chatRoomWrapper.getChatRoom().destroy(reason, alternateAddress)) {
     MUCActivator.getUIService().closeChatRoomWindow(chatRoomWrapper);
     chatRoomList.removeChatRoom(chatRoomWrapper);
   } else {
     // if we leave a chat room which is not persistent
     // the room can be destroyed on the server, and error is returned
     // when we try to destroy it not-authorized(401)
     if (!chatRoomWrapper.getChatRoom().isPersistent()
         && !chatRoomWrapper.getChatRoom().isJoined()) {
       chatRoomList.removeChatRoom(chatRoomWrapper);
     }
   }
 }
    @Override
    public boolean isVisible(SourceContact actionSource) {
      if (actionSource instanceof ChatRoomSourceContact) {
        if (name.equals("leave")) {
          return actionsEnabledCheckers[3].check(actionSource);
        } else if (name.equals("join")) {
          return actionsEnabledCheckers[1].check(actionSource);
        } else {
          ChatRoomSourceContact contact = (ChatRoomSourceContact) actionSource;
          ChatRoomWrapper room =
              MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
          if (room == null) return false;

          if (name.equals("autojoin")) return room.isAutojoin();
          else if (name.equals("autojoin_pressed")) return !room.isAutojoin();
        }
      }
      return false;
    }
  /**
   * Opens a chat window for the chat room.
   *
   * @param room the chat room.
   */
  public void openChatRoom(ChatRoomWrapper room) {
    if (room.getChatRoom() == null) {
      room =
          createChatRoom(
              room.getChatRoomName(),
              room.getParentProvider().getProtocolProvider(),
              new ArrayList<String>(),
              "",
              false,
              false,
              true);

      // leave the chatroom because getChatRoom().isJoined() returns true
      // otherwise
      if (room.getChatRoom().isJoined()) room.getChatRoom().leave();
    }

    if (!room.getChatRoom().isJoined()) {
      String savedNick =
          ConfigurationUtils.getChatRoomProperty(
              room.getParentProvider().getProtocolProvider(), room.getChatRoomID(), "userNickName");
      String subject = null;

      if (savedNick == null) {
        String[] joinOptions =
            ChatRoomJoinOptionsDialog.getJoinOptions(
                room.getParentProvider().getProtocolProvider(),
                room.getChatRoomID(),
                getDefaultNickname(room.getParentProvider().getProtocolProvider()));
        savedNick = joinOptions[0];
        subject = joinOptions[1];
      }

      if (savedNick != null) {
        joinChatRoom(room, savedNick, null, subject);
      } else return;
    }

    MUCActivator.getUIService().openChatRoomWindow(room);
  }
  /**
   * Returns default nickname for chat room based on the given provider.
   *
   * @param pps the given protocol provider service
   * @return default nickname for chat room based on the given provider.
   */
  public String getDefaultNickname(ProtocolProviderService pps) {
    final OperationSetServerStoredAccountInfo accountInfoOpSet =
        pps.getOperationSet(OperationSetServerStoredAccountInfo.class);

    String displayName = "";
    if (accountInfoOpSet != null) {
      displayName = AccountInfoUtils.getDisplayName(accountInfoOpSet);
    }

    if (displayName == null || displayName.length() == 0) {
      displayName = MUCActivator.getGlobalDisplayDetailsService().getGlobalDisplayName();
      if (displayName == null || displayName.length() == 0) {
        displayName = pps.getAccountID().getUserID();
        if (displayName != null) {
          int atIndex = displayName.lastIndexOf("@");
          if (atIndex > 0) displayName = displayName.substring(0, atIndex);
        }
      }
    }

    return displayName;
  }
    /**
     * Performs UI changes after the chat room join task has finished.
     *
     * @param returnCode the result code from the chat room join task.
     */
    private void done(String returnCode) {
      ConfigurationUtils.updateChatRoomStatus(
          chatRoomWrapper.getParentProvider().getProtocolProvider(),
          chatRoomWrapper.getChatRoomID(),
          GlobalStatusEnum.ONLINE_STATUS);

      String errorMessage = null;
      if (JOIN_AUTHENTICATION_FAILED_PROP.equals(returnCode)) {
        chatRoomWrapper.removePassword();

        AuthenticationWindowService authWindowsService =
            ServiceUtils.getService(MUCActivator.bundleContext, AuthenticationWindowService.class);

        AuthenticationWindowService.AuthenticationWindow authWindow =
            authWindowsService.create(
                null,
                null,
                null,
                false,
                chatRoomWrapper.isPersistent(),
                AuthenticationWindow.getAuthenticationWindowIcon(
                    chatRoomWrapper.getParentProvider().getProtocolProvider()),
                resources.getI18NString(
                    "service.gui.AUTHENTICATION_WINDOW_TITLE",
                    new String[] {chatRoomWrapper.getParentProvider().getName()}),
                resources.getI18NString(
                    "service.gui.CHAT_ROOM_REQUIRES_PASSWORD",
                    new String[] {chatRoomWrapper.getChatRoomName()}),
                "",
                null,
                isFirstAttempt
                    ? null
                    : resources.getI18NString(
                        "service.gui.AUTHENTICATION_FAILED",
                        new String[] {chatRoomWrapper.getChatRoomName()}),
                null);

        authWindow.setVisible(true);

        if (!authWindow.isCanceled()) {
          joinChatRoom(
              chatRoomWrapper,
              nickName,
              new String(authWindow.getPassword()).getBytes(),
              authWindow.isRememberPassword(),
              false,
              subject);
        }
      } else if (JOIN_REGISTRATION_REQUIRED_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_REGISTRATION_REQUIRED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else if (JOIN_PROVIDER_NOT_REGISTERED_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_NOT_CONNECTED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else if (JOIN_SUBSCRIPTION_ALREADY_EXISTS_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_ALREADY_JOINED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else {
        errorMessage =
            resources.getI18NString(
                "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
                new String[] {chatRoomWrapper.getChatRoomName()});
      }

      if (!JOIN_SUCCESS_PROP.equals(returnCode)
          && !JOIN_AUTHENTICATION_FAILED_PROP.equals(returnCode)) {
        MUCActivator.getAlertUIService()
            .showAlertPopup(resources.getI18NString("service.gui.ERROR"), errorMessage);
      }

      if (JOIN_SUCCESS_PROP.equals(returnCode)) {
        if (rememberPassword) {
          chatRoomWrapper.savePassword(new String(password));
        }

        if (subject != null) {
          try {
            chatRoomWrapper.getChatRoom().setSubject(subject);
          } catch (OperationFailedException ex) {
            logger.warn("Failed to set subject.");
          }
        }
      }

      chatRoomWrapper.firePropertyChange(returnCode);
    }
  /** Joins a chat room in an asynchronous way. */
  private class JoinChatRoomTask extends Thread {
    private final ChatRoomWrapperImpl chatRoomWrapper;

    private final String nickName;

    private final byte[] password;

    private final boolean rememberPassword;

    private final boolean isFirstAttempt;

    private final String subject;

    private ResourceManagementService resources = MUCActivator.getResources();

    JoinChatRoomTask(
        ChatRoomWrapperImpl chatRoomWrapper,
        String nickName,
        byte[] password,
        boolean rememberPassword,
        boolean isFirstAttempt,
        String subject) {
      this.chatRoomWrapper = chatRoomWrapper;
      this.nickName = nickName;
      this.isFirstAttempt = isFirstAttempt;
      this.subject = subject;

      if (password == null) {
        String passString = chatRoomWrapper.loadPassword();
        if (passString != null) {
          this.password = passString.getBytes();
        } else {
          this.password = null;
        }
      } else {
        this.password = password;
      }
      this.rememberPassword = rememberPassword;
    }

    JoinChatRoomTask(ChatRoomWrapperImpl chatRoomWrapper, String nickName, byte[] password) {
      this(chatRoomWrapper, nickName, password, false, true, null);
    }

    JoinChatRoomTask(
        ChatRoomWrapperImpl chatRoomWrapper, String nickName, byte[] password, String subject) {
      this(chatRoomWrapper, nickName, password, false, true, subject);
    }

    /** @override {@link Thread}{@link #run()} to perform all asynchronous tasks. */
    @Override
    public void run() {
      ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

      try {
        if (password != null && password.length > 0) chatRoom.joinAs(nickName, password);
        else if (nickName != null) chatRoom.joinAs(nickName);
        else chatRoom.join();

        done(JOIN_SUCCESS_PROP);
      } catch (OperationFailedException e) {
        if (logger.isTraceEnabled())
          logger.trace("Failed to join chat room: " + chatRoom.getName(), e);

        switch (e.getErrorCode()) {
          case OperationFailedException.AUTHENTICATION_FAILED:
            done(JOIN_AUTHENTICATION_FAILED_PROP);
            break;
          case OperationFailedException.REGISTRATION_REQUIRED:
            done(JOIN_REGISTRATION_REQUIRED_PROP);
            break;
          case OperationFailedException.PROVIDER_NOT_REGISTERED:
            done(JOIN_PROVIDER_NOT_REGISTERED_PROP);
            break;
          case OperationFailedException.SUBSCRIPTION_ALREADY_EXISTS:
            done(JOIN_SUBSCRIPTION_ALREADY_EXISTS_PROP);
            break;
          default:
            done(JOIN_UNKNOWN_ERROR_PROP);
        }
      }
    }

    /**
     * Performs UI changes after the chat room join task has finished.
     *
     * @param returnCode the result code from the chat room join task.
     */
    private void done(String returnCode) {
      ConfigurationUtils.updateChatRoomStatus(
          chatRoomWrapper.getParentProvider().getProtocolProvider(),
          chatRoomWrapper.getChatRoomID(),
          GlobalStatusEnum.ONLINE_STATUS);

      String errorMessage = null;
      if (JOIN_AUTHENTICATION_FAILED_PROP.equals(returnCode)) {
        chatRoomWrapper.removePassword();

        AuthenticationWindowService authWindowsService =
            ServiceUtils.getService(MUCActivator.bundleContext, AuthenticationWindowService.class);

        AuthenticationWindowService.AuthenticationWindow authWindow =
            authWindowsService.create(
                null,
                null,
                null,
                false,
                chatRoomWrapper.isPersistent(),
                AuthenticationWindow.getAuthenticationWindowIcon(
                    chatRoomWrapper.getParentProvider().getProtocolProvider()),
                resources.getI18NString(
                    "service.gui.AUTHENTICATION_WINDOW_TITLE",
                    new String[] {chatRoomWrapper.getParentProvider().getName()}),
                resources.getI18NString(
                    "service.gui.CHAT_ROOM_REQUIRES_PASSWORD",
                    new String[] {chatRoomWrapper.getChatRoomName()}),
                "",
                null,
                isFirstAttempt
                    ? null
                    : resources.getI18NString(
                        "service.gui.AUTHENTICATION_FAILED",
                        new String[] {chatRoomWrapper.getChatRoomName()}),
                null);

        authWindow.setVisible(true);

        if (!authWindow.isCanceled()) {
          joinChatRoom(
              chatRoomWrapper,
              nickName,
              new String(authWindow.getPassword()).getBytes(),
              authWindow.isRememberPassword(),
              false,
              subject);
        }
      } else if (JOIN_REGISTRATION_REQUIRED_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_REGISTRATION_REQUIRED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else if (JOIN_PROVIDER_NOT_REGISTERED_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_NOT_CONNECTED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else if (JOIN_SUBSCRIPTION_ALREADY_EXISTS_PROP.equals(returnCode)) {
        errorMessage =
            resources.getI18NString(
                "service.gui.CHAT_ROOM_ALREADY_JOINED",
                new String[] {chatRoomWrapper.getChatRoomName()});
      } else {
        errorMessage =
            resources.getI18NString(
                "service.gui.FAILED_TO_JOIN_CHAT_ROOM",
                new String[] {chatRoomWrapper.getChatRoomName()});
      }

      if (!JOIN_SUCCESS_PROP.equals(returnCode)
          && !JOIN_AUTHENTICATION_FAILED_PROP.equals(returnCode)) {
        MUCActivator.getAlertUIService()
            .showAlertPopup(resources.getI18NString("service.gui.ERROR"), errorMessage);
      }

      if (JOIN_SUCCESS_PROP.equals(returnCode)) {
        if (rememberPassword) {
          chatRoomWrapper.savePassword(new String(password));
        }

        if (subject != null) {
          try {
            chatRoomWrapper.getChatRoom().setSubject(subject);
          } catch (OperationFailedException ex) {
            logger.warn("Failed to set subject.");
          }
        }
      }

      chatRoomWrapper.firePropertyChange(returnCode);
    }
  }
  /**
   * Creates a chat room, by specifying the chat room name, the parent protocol provider and
   * eventually, the contacts invited to participate in this chat room.
   *
   * @param roomName the name of the room
   * @param protocolProvider the parent protocol provider.
   * @param contacts the contacts invited when creating the chat room.
   * @param reason
   * @param join whether we should join the room after creating it.
   * @param persistent whether the newly created room will be persistent.
   * @param isPrivate whether the room will be private or public.
   * @return the <tt>ChatRoomWrapper</tt> corresponding to the created room
   */
  public ChatRoomWrapper createChatRoom(
      String roomName,
      ProtocolProviderService protocolProvider,
      Collection<String> contacts,
      String reason,
      boolean join,
      boolean persistent,
      boolean isPrivate) {
    ChatRoomWrapper chatRoomWrapper = null;
    OperationSetMultiUserChat groupChatOpSet =
        protocolProvider.getOperationSet(OperationSetMultiUserChat.class);

    // If there's no group chat operation set we have nothing to do here.
    if (groupChatOpSet == null) return null;

    ChatRoom chatRoom = null;
    try {

      HashMap<String, Object> roomProperties = new HashMap<String, Object>();
      roomProperties.put("isPrivate", isPrivate);
      chatRoom = groupChatOpSet.createChatRoom(roomName, roomProperties);

      if (join) {
        chatRoom.join();

        for (String contact : contacts) chatRoom.invite(contact, reason);
      }
    } catch (OperationFailedException ex) {
      logger.error("Failed to create chat room.", ex);

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CREATE_CHAT_ROOM_ERROR",
                      new String[] {protocolProvider.getProtocolDisplayName()}),
              ex);
    } catch (OperationNotSupportedException ex) {
      logger.error("Failed to create chat room.", ex);

      MUCActivator.getAlertUIService()
          .showAlertDialog(
              MUCActivator.getResources().getI18NString("service.gui.ERROR"),
              MUCActivator.getResources()
                  .getI18NString(
                      "service.gui.CREATE_CHAT_ROOM_ERROR",
                      new String[] {protocolProvider.getProtocolDisplayName()}),
              ex);
    }

    if (chatRoom != null) {
      ChatRoomProviderWrapper parentProvider =
          chatRoomList.findServerWrapperFromProvider(protocolProvider);

      // if there is the same room ids don't add new wrapper as old one
      // maybe already created
      chatRoomWrapper = chatRoomList.findChatRoomWrapperFromChatRoom(chatRoom);

      if (chatRoomWrapper == null) {
        chatRoomWrapper = new ChatRoomWrapperImpl(parentProvider, chatRoom);
        chatRoomWrapper.setPersistent(persistent);
        chatRoomList.addChatRoom(chatRoomWrapper);
      }
    }

    return chatRoomWrapper;
  }
/**
 * Implements <tt>CustomContactActionsService</tt> for MUC contact source.
 *
 * @author Hristo Terezov
 */
public class MUCCustomContactActionService implements CustomContactActionsService<SourceContact> {
  /** List of custom menu items. */
  private final List<ContactActionMenuItem<SourceContact>> mucActionMenuItems =
      new LinkedList<ContactActionMenuItem<SourceContact>>();

  /** List of custom actions. */
  private final List<ContactAction<SourceContact>> mucActions =
      new LinkedList<ContactAction<SourceContact>>();

  /** Array of names for the custom actions. */
  private String[] actionsNames = {"leave", "join", "autojoin", "autojoin_pressed"};

  /** Array of labels for the custom actions. */
  private String[] actionsLabels = {
    "service.gui.LEAVE",
    "service.gui.JOIN",
    "service.gui.JOIN_AUTOMATICALLY",
    "service.gui.JOIN_AUTOMATICALLY"
  };

  /** Array of icons for the custom actions. */
  private String[] actionsIcons = {
    "service.gui.icons.LEAVE_ICON_BUTTON",
    "service.gui.icons.JOIN_ICON_BUTTON",
    "service.gui.icons.AUTOJOIN_ON_ICON_BUTTON",
    "service.gui.icons.AUTOJOIN_OFF_ICON_BUTTON"
  };

  /** Array of rollover icons for the custom actions. */
  private String[] actionsIconsRollover = {
    "service.gui.icons.LEAVE_ICON_ROLLOVER_BUTTON",
    "service.gui.icons.JOIN_ICON_ROLLOVER_BUTTON",
    "service.gui.icons.AUTOJOIN_ON_ICON_ROLLOVER_BUTTON",
    "service.gui.icons.AUTOJOIN_OFF_ICON_ROLLOVER_BUTTON"
  };

  /** Array of pressed icons for the custom actions. */
  private String[] actionsIconsPressed = {
    "service.gui.icons.LEAVE_ICON_PRESSED_BUTTON",
    "service.gui.icons.JOIN_ICON_PRESSED_BUTTON",
    "service.gui.icons.AUTOJOIN_ON_ICON_PRESSED_BUTTON",
    "service.gui.icons.AUTOJOIN_OFF_ICON_PRESSED_BUTTON",
  };

  /** Array of names for the custom menu items. */
  private String[] menuActionsNames = {
    "open",
    "join",
    "join_as",
    "leave",
    "remove",
    "change_nick",
    "autojoin",
    "autojoin_pressed",
    "open_automatically"
  };

  /** Array of labels for the custom menu items. */
  private String[] menuActionsLabels = {
    "service.gui.OPEN",
    "service.gui.JOIN",
    "service.gui.JOIN_AS",
    "service.gui.LEAVE",
    "service.gui.REMOVE",
    "service.gui.CHANGE_NICK",
    "service.gui.JOIN_AUTOMATICALLY",
    "service.gui.DONT_JOIN_AUTOMATICALLY",
    "service.gui.OPEN_AUTOMATICALLY"
  };

  /** Array of icons for the custom menu items. */
  private String[] menuActionsIcons = {
    "service.gui.icons.CHAT_ROOM_16x16_ICON",
    "service.gui.icons.JOIN_ICON",
    "service.gui.icons.JOIN_AS_ICON",
    "service.gui.icons.LEAVE_ICON",
    "service.gui.icons.REMOVE_CHAT_ICON",
    "service.gui.icons.RENAME_16x16_ICON",
    "service.gui.icons.AUTOJOIN",
    "service.gui.icons.AUTOJOIN",
    null
  };

  /** A runnable that leaves the chat room. */
  private MUCCustomActionRunnable leaveRunnable =
      new MUCCustomActionRunnable() {

        @Override
        public void run() {
          ChatRoomWrapper leavedRoomWrapped =
              MUCActivator.getMUCService().leaveChatRoom(chatRoomWrapper);
          if (leavedRoomWrapped != null)
            MUCActivator.getUIService().closeChatRoomWindow(leavedRoomWrapped);
        }
      };

  /** A runnable that joins the chat room. */
  private MUCCustomActionRunnable joinRunnable =
      new MUCCustomActionRunnable() {

        @Override
        public void run() {
          String[] joinOptions;
          String subject = null;
          String nickName = null;

          nickName =
              ConfigurationUtils.getChatRoomProperty(
                  chatRoomWrapper.getParentProvider().getProtocolProvider(),
                  chatRoomWrapper.getChatRoomID(),
                  "userNickName");
          if (nickName == null) {
            joinOptions =
                ChatRoomJoinOptionsDialog.getJoinOptions(
                    chatRoomWrapper.getParentProvider().getProtocolProvider(),
                    chatRoomWrapper.getChatRoomID(),
                    MUCActivator.getMUCService()
                        .getDefaultNickname(
                            chatRoomWrapper.getParentProvider().getProtocolProvider()));
            nickName = joinOptions[0];
            subject = joinOptions[1];
          }

          if (nickName != null)
            MUCActivator.getMUCService().joinChatRoom(chatRoomWrapper, nickName, null, subject);
        }
      };

  /** A runnable that sets / unsets auto join setting of the chat room. */
  private MUCCustomActionRunnable autoJoinRunnable =
      new MUCCustomActionRunnable() {

        @Override
        public void run() {
          chatRoomWrapper.setAutoJoin(!chatRoomWrapper.isAutojoin());
        }
      };

  /**
   * Array of <tt>MUCCustomActionRunnable</tt> objects for the custom menu items. They will be
   * executed when the item is pressed.
   */
  private MUCCustomActionRunnable[] actionsRunnable = {
    leaveRunnable, joinRunnable, autoJoinRunnable, autoJoinRunnable
  };

  /**
   * Array of <tt>MUCCustomActionRunnable</tt> objects for the custom menu items. They will be
   * executed when the item is pressed.
   */
  private MUCCustomActionRunnable[] menuActionsRunnable = {
    new MUCCustomActionRunnable() {
      @Override
      public void run() {
        MUCActivator.getMUCService().openChatRoom(chatRoomWrapper);
      }
    },
    joinRunnable,
    new MUCCustomActionRunnable() {

      @Override
      public void run() {
        String[] joinOptions;
        joinOptions =
            ChatRoomJoinOptionsDialog.getJoinOptions(
                chatRoomWrapper.getParentProvider().getProtocolProvider(),
                chatRoomWrapper.getChatRoomID(),
                MUCActivator.getMUCService()
                    .getDefaultNickname(chatRoomWrapper.getParentProvider().getProtocolProvider()));
        if (joinOptions[0] == null) return;
        MUCActivator.getMUCService()
            .joinChatRoom(chatRoomWrapper, joinOptions[0], null, joinOptions[1]);
      }
    },
    leaveRunnable,
    new MUCCustomActionRunnable() {

      @Override
      public void run() {
        ChatRoom chatRoom = chatRoomWrapper.getChatRoom();

        if (chatRoom != null) {
          ChatRoomWrapper leavedRoomWrapped =
              MUCActivator.getMUCService().leaveChatRoom(chatRoomWrapper);
          if (leavedRoomWrapped != null)
            MUCActivator.getUIService().closeChatRoomWindow(leavedRoomWrapped);
        }

        MUCActivator.getUIService().closeChatRoomWindow(chatRoomWrapper);

        MUCActivator.getMUCService().removeChatRoom(chatRoomWrapper);
      }
    },
    new MUCCustomActionRunnable() {

      @Override
      public void run() {
        ChatRoomJoinOptionsDialog.getJoinOptions(
            true,
            chatRoomWrapper.getParentProvider().getProtocolProvider(),
            chatRoomWrapper.getChatRoomID(),
            MUCActivator.getMUCService()
                .getDefaultNickname(chatRoomWrapper.getParentProvider().getProtocolProvider()));
      }
    },
    autoJoinRunnable,
    autoJoinRunnable,
    new MUCCustomActionRunnable() {

      @Override
      public void run() {
        MUCActivator.getUIService()
            .showChatRoomAutoOpenConfigDialog(
                chatRoomWrapper.getParentProvider().getProtocolProvider(),
                chatRoomWrapper.getChatRoomID());
      }
    }
  };

  /**
   * Array of <tt>EnableChecker</tt> objects for the custom menu items. They are used to check if
   * the item is enabled or disabled.
   */
  private EnableChecker[] actionsEnabledCheckers = {
    null,
    new JoinEnableChecker(),
    new JoinEnableChecker(),
    new LeaveEnableChecker(),
    null,
    null,
    null,
    null,
    null
  };

  /** The resource management service instance. */
  ResourceManagementService resources = MUCActivator.getResources();

  /** Constructs the custom actions. */
  public MUCCustomContactActionService() {
    for (int i = 0; i < menuActionsLabels.length; i++) {
      MUCActionMenuItems item =
          new MUCActionMenuItems(
              menuActionsNames[i],
              menuActionsLabels[i],
              menuActionsIcons[i],
              menuActionsRunnable[i]);
      mucActionMenuItems.add(item);
      if (actionsEnabledCheckers[i] != null) item.setEnabled(actionsEnabledCheckers[i]);
    }

    for (int i = 0; i < actionsLabels.length; i++) {
      MUCAction item =
          new MUCAction(
              actionsNames[i],
              actionsLabels[i],
              actionsIcons[i],
              actionsIconsRollover[i],
              actionsIconsPressed[i],
              actionsRunnable[i]);
      mucActions.add(item);
    }
  }

  /**
   * Returns the template class that this service has been initialized with
   *
   * @return the template class
   */
  public Class<SourceContact> getContactSourceClass() {
    return SourceContact.class;
  }

  @Override
  public Iterator<ContactActionMenuItem<SourceContact>> getCustomContactActionsMenuItems() {
    return mucActionMenuItems.iterator();
  }

  @Override
  public Iterator<ContactAction<SourceContact>> getCustomContactActions() {
    return mucActions.iterator();
  }

  /** Implements the MUC custom action. */
  private class MUCAction implements ContactAction<SourceContact> {
    /** The text of the action. */
    private String text;

    /** The icon of the action */
    private byte[] icon;

    /** The icon that is shown when the action is pressed. */
    private byte[] iconPressed;

    /** The runnable that is executed when the action is pressed. */
    private MUCCustomActionRunnable actionPerformed;

    /** The icon that is shown when the mouse is over the action. */
    private byte[] iconRollover;

    /** The name of the action. */
    private String name;

    /**
     * Constructs <tt>MUCAction</tt> instance.
     *
     * @param textKey the key used to retrieve the label for the action.
     * @param iconKey the key used to retrieve the icon for the action.
     * @param actionPerformed the action executed when the action is pressed.
     * @param iconRolloverKey the key used to retrieve the rollover icon for the action.
     * @param iconPressedKey the key used to retrieve the pressed icon for the action.
     */
    public MUCAction(
        String name,
        String textKey,
        String iconKey,
        String iconRolloverKey,
        String iconPressedKey,
        MUCCustomActionRunnable actionPerformed) {
      this.name = name;
      this.text = resources.getI18NString(textKey);
      this.icon = resources.getImageInBytes(iconKey);
      this.iconRollover = resources.getImageInBytes(iconRolloverKey);
      this.iconPressed = resources.getImageInBytes(iconPressedKey);
      this.actionPerformed = actionPerformed;
    }

    @Override
    public void actionPerformed(SourceContact actionSource, int x, int y)
        throws OperationFailedException {
      if (!(actionSource instanceof ChatRoomSourceContact)) return;
      actionPerformed.setContact(actionSource);
      new Thread(actionPerformed).start();
    }

    @Override
    public byte[] getIcon() {
      return icon;
    }

    @Override
    public byte[] getRolloverIcon() {
      return iconRollover;
    }

    @Override
    public byte[] getPressedIcon() {
      return iconPressed;
    }

    @Override
    public String getToolTipText() {
      return text;
    }

    @Override
    public boolean isVisible(SourceContact actionSource) {
      if (actionSource instanceof ChatRoomSourceContact) {
        if (name.equals("leave")) {
          return actionsEnabledCheckers[3].check(actionSource);
        } else if (name.equals("join")) {
          return actionsEnabledCheckers[1].check(actionSource);
        } else {
          ChatRoomSourceContact contact = (ChatRoomSourceContact) actionSource;
          ChatRoomWrapper room =
              MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
          if (room == null) return false;

          if (name.equals("autojoin")) return room.isAutojoin();
          else if (name.equals("autojoin_pressed")) return !room.isAutojoin();
        }
      }
      return false;
    }
  }

  /** Implements the MUC custom menu items. */
  private class MUCActionMenuItems implements ContactActionMenuItem<SourceContact> {
    /** The label for the menu item. */
    private String text;

    /** The the icon for the menu item. */
    private byte[] image;

    /** The action executed when the menu item is pressed. */
    private MUCCustomActionRunnable actionPerformed;

    /** Object that is used to check if the item is enabled or disabled. */
    private EnableChecker enabled;

    /** The name of the custom action menu item. */
    private String name;

    /** The mnemonic for the action. */
    private char mnemonics;

    /**
     * Constructs <tt>MUCActionMenuItems</tt> instance.
     *
     * @param textKey the key used to retrieve the label for the menu item.
     * @param imageKey the key used to retrieve the icon for the menu item.
     * @param actionPerformed the action executed when the menu item is pressed.
     */
    public MUCActionMenuItems(
        String name, String textKey, String imageKey, MUCCustomActionRunnable actionPerformed) {
      this.text = resources.getI18NString(textKey);
      this.image = (imageKey == null) ? null : resources.getImageInBytes(imageKey);
      this.actionPerformed = actionPerformed;
      this.enabled = new EnableChecker();
      this.name = name;
      this.mnemonics = resources.getI18nMnemonic(text);
    }

    @Override
    public void actionPerformed(SourceContact actionSource) throws OperationFailedException {
      if (!(actionSource instanceof ChatRoomSourceContact)) return;
      actionPerformed.setContact(actionSource);
      new Thread(actionPerformed).start();
    }

    @Override
    public byte[] getIcon() {
      return image;
    }

    @Override
    public String getText(SourceContact actionSource) {
      if (!name.equals("open_automatically")) return text;

      String openAutomaticallyValue =
          MUCService.getChatRoomAutoOpenOption(
              ((ChatRoomSourceContact) actionSource).getProvider(),
              ((ChatRoomSourceContact) actionSource).getChatRoomID());
      if (openAutomaticallyValue == null)
        openAutomaticallyValue = MUCService.OPEN_ON_IMPORTANT_MESSAGE;
      String openAutomaticallyKey =
          MUCService.autoOpenConfigValuesTexts.get(openAutomaticallyValue);
      return "<html>"
          + text
          + "...<br><font size=\"2\"><center> ("
          + resources.getI18NString(openAutomaticallyKey)
          + ")</center></font></html>";
    }

    @Override
    public boolean isVisible(SourceContact actionSource) {
      if (!(actionSource instanceof ChatRoomSourceContact)) return false;

      if (name.equals("autojoin") || name.equals("autojoin_pressed")) {
        ChatRoomSourceContact contact = (ChatRoomSourceContact) actionSource;
        ChatRoomWrapper room =
            MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
        if (name.equals("autojoin")) return !room.isAutojoin();

        if (name.equals("autojoin_pressed")) return room.isAutojoin();
      }
      return true;
    }

    @Override
    public char getMnemonics() {
      return mnemonics;
    }

    @Override
    public boolean isEnabled(SourceContact actionSource) {
      return enabled.check(actionSource);
    }

    /**
     * Sets <tt>EnabledChecker</tt> instance that will be used to check if the item should be
     * enabled or disabled.
     *
     * @param enabled the <tt>EnabledChecker</tt> instance.
     */
    public void setEnabled(EnableChecker enabled) {
      this.enabled = enabled;
    }

    @Override
    public boolean isCheckBox() {
      return false;
    }

    @Override
    public boolean isSelected(SourceContact contact) {
      ChatRoomWrapper chatRoomWrapper =
          MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
      return chatRoomWrapper.isAutojoin();
    }
  }

  /**
   * Checks if the menu item should be enabled or disabled. This is default implementation. Always
   * returns that the item should be enabled.
   */
  private static class EnableChecker {
    /**
     * Checks if the menu item should be enabled or disabled.
     *
     * @param contact the contact associated with the menu item.
     * @return always <tt>true</tt>
     */
    public boolean check(SourceContact contact) {
      return true;
    }
  }

  /** Implements <tt>EnableChecker</tt> for the join menu items. */
  private static class JoinEnableChecker extends EnableChecker {
    /**
     * Checks if the menu item should be enabled or disabled.
     *
     * @param contact the contact associated with the menu item.
     * @return <tt>true</tt> if the item should be enabled and <tt>false</tt> if not.
     */
    public boolean check(SourceContact contact) {
      ChatRoomWrapper chatRoomWrapper =
          MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
      ChatRoom chatRoom = null;
      if (chatRoomWrapper != null) {
        chatRoom = chatRoomWrapper.getChatRoom();
      }

      if ((chatRoom != null) && chatRoom.isJoined()) return false;
      return true;
    }
  }

  /** Implements <tt>EnableChecker</tt> for the leave menu item. */
  private static class LeaveEnableChecker extends JoinEnableChecker {
    /**
     * Checks if the menu item should be enabled or disabled.
     *
     * @param contact the contact associated with the menu item.
     * @return <tt>true</tt> if the item should be enabled and <tt>false</tt> if not.
     */
    public boolean check(SourceContact contact) {
      return !super.check(contact);
    }
  }

  /**
   * Implements base properties for the MUC menu items.These properties are used when the menu item
   * is pressed.
   */
  private abstract class MUCCustomActionRunnable implements Runnable {
    /** The contact associated with the menu item. */
    protected SourceContact contact;

    /** The contact associated with the menu item. */
    protected ChatRoomWrapper chatRoomWrapper;

    /**
     * Sets the source contact.
     *
     * @param contact the contact to set
     */
    public void setContact(SourceContact contact) {
      this.contact = contact;
      chatRoomWrapper = MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
    }
  }
}
 @Override
 public boolean isSelected(SourceContact contact) {
   ChatRoomWrapper chatRoomWrapper =
       MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
   return chatRoomWrapper.isAutojoin();
 }
 /**
  * Sets the source contact.
  *
  * @param contact the contact to set
  */
 public void setContact(SourceContact contact) {
   this.contact = contact;
   chatRoomWrapper = MUCActivator.getMUCService().findChatRoomWrapperFromSourceContact(contact);
 }
 @Override
 public void run() {
   MUCActivator.getMUCService().openChatRoom(chatRoomWrapper);
 }