/**
   * 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();
  }
  /**
   * 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;
  }
  /**
   * 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();
  }
  /**
   * 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()
                      }));
  }
 /**
  * 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);
     }
   }
 }
  /**
   * 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;
  }