# OsUsersPresenter.java

    /*
    ** Module   : OsUsersPresenter.java
    ** Abstract : OsUsersPresenter implements common business methods to manage OS user accounts.
    **
    ** Copyright (c) 2023, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ----------------Description----------------------
    ** 001 GBB 20230807 Created initial version.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */
    package com.goldencode.p2j.admin.client.application.home.accounts.osusers;

    import com.goldencode.p2j.admin.*;
    import com.goldencode.p2j.admin.client.*;
    import com.goldencode.p2j.admin.client.application.*;
    import com.goldencode.p2j.admin.client.application.home.*;
    import com.goldencode.p2j.admin.client.application.home.accounts.*;
    import com.goldencode.p2j.admin.client.application.home.acl.*;
    import com.goldencode.p2j.admin.client.widget.dialog.*;
    import com.goldencode.p2j.admin.shared.*;
    import com.google.gwt.user.client.rpc.*;
    import com.google.gwt.user.client.ui.*;
    import com.google.inject.Inject;
    import com.google.inject.Provider;
    import com.google.web.bindery.event.shared.*;
    import com.gwtplatform.mvp.client.*;
    import com.gwtplatform.mvp.client.annotations.*;
    import com.gwtplatform.mvp.client.presenter.slots.*;
    import com.gwtplatform.mvp.client.proxy.*;

    import javax.inject.*;
    import java.util.*;
    import java.util.logging.*;

    /** OsUsersPresenter implements common business methods to manage OS user accounts. */
    public class OsUsersPresenter
    extends AccountsPresenter<OsUsersPresenter.MyView, OsUsersPresenter.MyProxy>
    implements OsUsersUIHandlers
    {
       /**
        * Defines user accounts view states.
        */
       private enum OsUsersViewStates
       implements ViewStateMachine.TransitionState
       {
          /** Users list has been refreshed. */
          USERS_LIST_REFRESHED(MASK_WEST_CENTER, STATE_INITIAL_EMPTY),

          /** The user account has been added currently. */
          ADD_USER_ACCOUNT(MASK_WEST_CENTER, STATE_USER_ADD),

          /** The user account has been edited currently. */
          EDIT_USER_ACCOUNT(MASK_WEST_CENTER, STATE_USER_EDIT),

          /** The single user has been selected currently. */
          SINGLE_USER_SELECTED(MASK_WEST_CENTER, STATE_USERS_SINGLE),

          /** The multiple users have been selected currently. */
          MULTI_USERS_SELECTED(MASK_WEST_CENTER, STATE_USERS_MULTI);

          /** The current components states to be enabled or disabled */
          private final boolean[] state;

          /** The current mask that defines components to which the current state is applied */
          private final boolean[] mask;

          /**
           * Creates a target view state.
           *
           * @param    mask
           *           The current mask
           * @param    state
           *           The current state
           */
          OsUsersViewStates(boolean[] mask, boolean[] state)
          {
             this.mask  = mask;
             this.state = state;
          }

          /**
           * Gets the current state that defines the affected components states.
           *
           * @return   The current state
           */
          @Override
          public boolean[] getState()
          {
             return this.state;
          }

          /**
           * Gets the current mask that defines the set of affected components (widgets).
           *
           * @return   The current mask
           */
          @Override
          public boolean[] getMask()
          {
             return mask;
          }
       }

       /** state definition - initial empty */
       private static final boolean[] STATE_INITIAL_EMPTY =
       {
          /*       refresh               */ true,
          /*       addOsUserAccount      */ true,
          /*       deleteOsUserAccount   */ false,
          /*       editOsUserAccount     */ false,
          /*       disableOsUserAccount  */ false,
          /*       findOsUser            */ true
       };

       /** state definition - group definition creation */
       private static final boolean[] STATE_USER_ADD =
       {
          /*       refresh               */ false,
          /*       addOsUserAccount      */ false,
          /*       deleteOsUserAccount   */ false,
          /*       editOsUserAccount     */ false,
          /*       disableOsUserAccount  */ false,
          /*       findOsUser            */ false
       };

       /** state definition - group definition editing */
       private static final boolean[] STATE_USER_EDIT =
       {
          /*       refresh               */ false,
          /*       addOsUserAccount      */ false,
          /*       deleteOsUserAccount   */ false,
          /*       editOsUserAccount     */ false,
          /*       disableOsUserAccount  */ false,
          /*       findOsUser            */ false
       };

       /** state definition - single selection in users list */
       private static final boolean[] STATE_USERS_SINGLE =
       {
          /*       refresh               */ true,
          /*       addOsUserAccount      */ true,
          /*       deleteOsUserAccount   */ true,
          /*       editOsUserAccount     */ true,
          /*       disableOsUserAccount  */ true,
          /*       findOsUser            */ true
       };

       /** state definition - multiple selection in users list */
       private static final boolean[] STATE_USERS_MULTI =
       {
          /*       refresh               */ true,
          /*       addOsUserAccount      */ true,
          /*       deleteOsUserAccount   */ true,
          /*       editOsUserAccount     */ false,
          /*       disableOsUserAccount  */ false,
          /*       findOsUser            */ true
       };

       /** mask definition - west-center */
       private static final boolean[] MASK_WEST_CENTER =
       {
          /*       refresh               */ true,
          /*       addOsUserAccount      */ true,
          /*       deleteOsUserAccount   */ true,
          /*       editOsUserAccount     */ true,
          /*       disableOsUserAccount  */ true,
          /*       findOsUser            */ true
       };

       /** The attachment point for modal dialogs on this view*/
       public static final NestedSlot MODAL_CONTENT = new NestedSlot();

       /** Administration server interface */
       private final AdminServiceAsync adminService;

       /** The common modal dialogs manager */
       private final ModalDialogs modalDialogsManager;

       /** The server alarms manager */
       private final Alarm serverAlarmsManager;

       /** The currently selected user */
       private OsUserDef selectedUser;

       /** The set of selected users */
       private final Set<OsUserDef> selectedUsers;

       /** The user account definition provider */
       private final Provider<AddEditOsUserWidget> uadProvider;

       /** The common input dialogs provider */
       private final Provider<InputDialog> inputDialogProvider;

       /** The Find OS User Account manager */
       private final FindOsUserAccount findOsUserAccountManager;

       /**
        * This view interface that must be implemented by the concrete view according to GWTP
        * framework. Defines the exposed business methods.
        */
       public interface MyView
       extends View, HasUiHandlers<OsUsersUIHandlers>, Provider<HasEnabled[]>, PrintingContext
       {
          /**
           * Sets the all users table's model with users accounts data given by tagged names
           *
           * @param    users
           *           The array of users accounts given by tagged names
           */
          void setUsers(TaggedName[] users);

          /**
           * Tests if these tested users have been selected from the all users table.
           *
           * @param    users
           *           The array of tested user accounts given by tagged names
           *
           * @return   True if all tested users have been selected, otherwise false.
           */
          boolean isSelectedFromUsers(TaggedName[] users);

          /**
           * Selects the user's data row from the all users table by a given user's tagged name.
           *
           * @param    user
           *           The user account given by its tagged name
           */
          void selectUser(TaggedName user);

          /**
           * Selects the user's data row from the all users table by a given user's account name.
           *
           * @param    name
           *           The account name.
           */
          void selectUserByName(String name);

          /**
           * Toggles the Disable/Enable User button's label.
           *
           * @param    enabled
           *           Indicates the user's enabled state. The true value switches this button's label
           *           from "Enable User" to "Disable User" and vice versa the false value switches
           *           from "Disable User" to "Enable User".
           */
          void toggleDisableUserButton(boolean enabled);

          /**
           * Gets a reference to the Deleting Users Alert.
           *
           * @return   The Deleting Users Alert
           */
          DeletingOsUsersAlert getDeletingUsersAlert();

          /**
           * Returns the parent container where the Add/Edit User Definition View will be revealed in.
           *
           * @return   The parent container for the Add/Edit User Definition View.
           */
          HasWidgets getOsUserDefModalParent();

          /**
           * Sets the FWD users table's model with all associated FWD users for the single selected OS user
           * from the OS users table view.
           *
           * @param    fwdUsers
           *           The array of FWD users given by tagged names
           */
          void setAssociatedFwdUsers(TaggedName[] fwdUsers);
       }

       /**
        * Defines the proxy place for GWTP framework. Binds /accounts/os-users url to this presenter.
        */
       @ProxyStandard
       @NameToken(NameTokens.OS_USERS)
       public interface MyProxy
       extends ProxyPlace<OsUsersPresenter>
       {}

       /**
        * Defines the Users presenter.
        *
        * @param    eventBus
        *           The event bus
        * @param    view
        *           The associated view
        * @param    proxy
        *           The proxy place
        * @param    placeManager
        *           The place manager
        * @param    viewStateMachine
        *           The view state machine
        * @param    adminService
        *           The administration service
        * @param    modalDialogsManager
        *           The common modal dialogs manager
        * @param    serverAlarmsManager
        *           The server alarms
        * @param    uadProvider
        *           The user account definition provider
        * @param    inputDialogProvider
        *           InputDialog provider
        * @param    acctExtensionHolder
        *           The account extension holder
        * @param    aclPopupPresenterProvider
        *           The ACL popup presenter provider
        */
       @Inject
       public OsUsersPresenter(EventBus eventBus,
                               MyView view,
                               MyProxy proxy,
                               PlaceManager placeManager,
                               @Named("OsUsersViewStateMachine") ViewStateMachine viewStateMachine,
                               AdminServiceAsync adminService,
                               ModalDialogs modalDialogsManager,
                               Alarm serverAlarmsManager,
                               Provider<AddEditOsUserWidget> uadProvider,
                               Provider<InputDialog> inputDialogProvider,
                               AccountExtensionHolder acctExtensionHolder,
                               ACLPopupPresenter aclPopupPresenterProvider)
       {
          super(eventBus,
                view,
                proxy,
                HomePresenter.SLOT_CONTENT,
                placeManager,
                viewStateMachine,
                aclPopupPresenterProvider);

          this.adminService = adminService;
          this.modalDialogsManager = modalDialogsManager;
          this.serverAlarmsManager = serverAlarmsManager;
          this.uadProvider = uadProvider;
          this.inputDialogProvider = inputDialogProvider;
          this.findOsUserAccountManager = new FindOsUserAccount(acctExtensionHolder);
          this.selectedUsers = new HashSet<>();
          getView().setUiHandlers(this);
       }

       /**
        * Lifecycle method called on all visible presenters whenever a
        * presenter is revealed anywhere in the presenter hierarchy.
        * <p>
        * <b>Important:</b> Make sure you call your superclass {@link #onReset()} if
        * you override. Also, do not call directly, fire a
        * {@link com.gwtplatform.mvp.client.proxy.ResetPresentersEvent} to perform a reset manually.
        * See {@link com.gwtplatform.mvp.client.PresenterWidget} for more details on lifecycle
        * methods.
        * <p>
        * This is one of the most frequently used lifecycle method. This is usually a good
        * place to refresh any information displayed by your presenter.
        * <p>
        * Note that {@link #onReset()} is not called only when using
        * {@link #addToSlot(Object, PresenterWidget)}, {@link #addToPopupSlot(PresenterWidget)}
        * or {@link #setInSlot(Object, PresenterWidget, boolean)} with {@code false} as the third
        * parameter.
        * <p>
        * In a presenter hierarchy, this method is called top-down: first on the
        * parent presenters, then on the children.
        */
       @Override
       protected void onReset()
       {
          super.onReset();
          updateUsersList();
          setState(OsUsersViewStates.USERS_LIST_REFRESHED);
       }

       /**
        * Triggers an action to refresh the all users table.
        */
       @Override
       public void onRefresh()
       {
          updateUsersList();
          changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
       }

       /**
        * Retrieves the user list and fills the all users table model.
        */
       private void updateUsersList()
       {
          updateUsersList(()->{});
       }

       /**
        * Retrieves the user list and fills the all users table model and executes a given command on
        * getting the user list.
        *
        * @param    callback
        *           The given command to execute on getting the data
        */
       private void updateUsersList(Runnable callback)
       {
          this.adminService.listOsUsers(new AsyncCallback<TaggedName[]>()
          {
             @Override
             public void onSuccess(TaggedName[] result)
             {
                getView().setUsers(result);
                callback.run();
             }

             @Override
             public void onFailure(Throwable caught)
             {
                logger.log(Level.INFO, "Can't get all OS Users", caught);
                callback.run();
             }
          });
       }

       /**
        * Shows the Add OS User Account Dialog.
        */
       @Override
       public void showAddUserAccountDialog()
       {
          logger.log(Level.INFO, "showAddOsUserAccountDialog");
          AddEditOsUserWidget uad = uadProvider.get();
          uad.build(null, r ->
          {
             if (!r)
             {
                return;
             }

             uad.show(getView().getOsUserDefModalParent(), new OsUserDef(), userDef ->
             {
                if (userDef == null)
                {
                   return;
                }

                addUser(userDef);
                updateUsersList();
             });
          });
       }

       /**
        * Setups the Deleting Users Alert.
        *
        * @param    users
        *           The array of users accounts given by tagged names
        */
       @Override
       public void setupDeletingUsersAlert(TaggedName[] users)
       {
          logger.log(Level.INFO, "setupDeletingUsersAlert");

          if (users == null || users.length == 0)
          {
             return;
          }

          checkAssociatedFwdUsers(users, 0);
       }

       /**
        * Checks if the selected OS users are associated with FWD accounts. If any mapping found, a warning
        * message is displayed to notify the delete action will not be executed. If no mapping is found, the
        * search continues with the next user in the array. If no mappings are found up to the last user, a
        * confirmation alert is displayed.
        *
        * @param    osUsers
        *           The array of OS users to be checked
        * @param    currentIndex
        *           The index of the current element in the array of OS users. Used for recursion.
        */
       private void checkAssociatedFwdUsers(TaggedName[] osUsers, int currentIndex)
       {
          String fwdUserId = osUsers[currentIndex].getName();
          adminService.listAssociatedFwdUsers(fwdUserId,
                                              new AdminCallback<TaggedName[]>()
                                              {
                                                 @Override
                                                 public void onDone(TaggedName[] result)
                                                 {
                                                    if (result != null && result.length > 0)
                                                    {
                                                       getView().getDeletingUsersAlert().setWarningAlert(osUsers);
                                                    }
                                                    else if (currentIndex + 1 < osUsers.length)
                                                    {
                                                       checkAssociatedFwdUsers(osUsers, currentIndex + 1);
                                                    }
                                                    else
                                                    {
                                                       getView().getDeletingUsersAlert().setAlert(osUsers);
                                                    }
                                                 }
                                              });
       }

       /**
        * Shows the Edit User Account Dialog to edit the target user account.
        *
        * @param    updatedUserAccount
        *           The target user account given by its tagged name
        */
       @Override
       public void showEditUserAccountDialog(TaggedName updatedUserAccount)
       {
          logger.log(Level.INFO, "showEditUserAccountDialog");
          AddEditOsUserWidget uad = uadProvider.get();
          uad.build(selectedUser, r ->
          {
             if (!r)
             {
                return;
             }

             uad.show(getView().getOsUserDefModalParent(), selectedUser, userDef ->
             {
                if (userDef == null)
                {
                   return;
                }

                updateUser(userDef);
                updateUsersList();
             });
          });
       }

       /**
        * Cancels the Add User Account Dialog and rolls back any related changes.
        */
       @Override
       public void cancelAddUserAccountDialog()
       {
          logger.log(Level.INFO, "cancelAddUserAccountDialog");
          restoreState();
       }

       /**
        * Cancels the Deleting Users Alert and rolls back any related changes.
        */
       @Override
       public void cancelDeletingUsersAlert()
       {
          logger.log(Level.INFO, "cancelDeletingUsersAlert");
       }

       /**
        * Cancels the Edit User Account Dialog and rolls back any related changes.
        */
       @Override
       public void cancelEditUserAccountDialog()
       {
          logger.log(Level.INFO, "cancelEditUserAccountDialog");
          restoreState();
       }

       /**
        * Deletes the given selected users accounts.
        *
        * @param    users
        *           The array of users accounts given by tagged names
        */
       @Override
       public void deleteSelectedUsers(TaggedName[] users)
       {
          if (!getView().isSelectedFromUsers(users))
          {
             return;
          }
          MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
          LinkedHashMap<TaggedName, AdminCallback<Boolean>> callbacks = new LinkedHashMap<>();
          for (TaggedName user : users)
          {
             AdminCallback<Boolean> callback = mc.newCallback();
             callbacks.put(user, callback);
             logger.info("OS user account to delete " + user.getName());
          };
          // the admin service must be called only after all callbacks have been created otherwise
          // the onDone method is called unpredictably multiple times
          for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
          {
             this.adminService.deleteOsUser(e.getKey().getName(), e.getValue());
          }
          mc.onDone(() ->
          {
             if (!mc.isSuccess())
             {
                // this branch is executed when one or more callbacks !isSuccess()
                for (Map.Entry<TaggedName, AdminCallback<Boolean>> e : callbacks.entrySet())
                {
                   if (e.getValue().getResult() == null || !e.getValue().getResult())
                   {
                      logger.info("failed to delete OS user account " + e.getKey().getName());
                   }
                }
             }
             updateUsersList(()-> changeState(OsUsersViewStates.USERS_LIST_REFRESHED));
          });
       }

       /**
        * Triggers the users selection changed event.
        *
        * @param    users
        *           The selected users accounts
        */
       @Override
       public void onUserSelected(Set<TaggedName> users)
       {
          if (users == null)
          {
             logger.info("Users selection is cleared.");
             changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
             return;
          }
          MultiCallback mc = new MultiCallback(adminService, serverAlarmsManager);
          LinkedHashMap<TaggedName, AdminCallback<OsUserDef>> callbacks = new LinkedHashMap<>();
          users.forEach(user ->
          {
             AdminCallback<OsUserDef> cb = mc.newCallback();
             callbacks.put(user, cb);
             logger.info("get user " + user.getName());
          });
          for (Map.Entry<TaggedName, AdminCallback<OsUserDef>> e : callbacks.entrySet())
          {
             this.adminService.getOsUser(e.getKey().getName(), e.getValue());
          }
          mc.onDone(() ->
          {
             if (mc.isSuccess())
             {
                selectedUsers.clear();
                for (Map.Entry<TaggedName, AdminCallback<OsUserDef>> e : callbacks.entrySet())
                {
                   OsUserDef OsUserDef = e.getValue().getResult();
                   logger.info("selected user " + OsUserDef);
                   selectedUsers.add(OsUserDef);
                   selectedUser = OsUserDef;
                }
                if (selectedUsers.size() > 1)
                {
                   changeState(OsUsersViewStates.MULTI_USERS_SELECTED);
                }
                else if (selectedUsers.size() == 1)
                {
                   changeState(OsUsersViewStates.SINGLE_USER_SELECTED);
                   getView().toggleDisableUserButton(selectedUser.enabled);
                }
                else
                {
                   changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
                }
             }
             else
             {
                for (Map.Entry<TaggedName, AdminCallback<OsUserDef>> e : callbacks.entrySet())
                {
                   if (e.getValue().getResult() == null)
                   {
                      logger.info("failed to get user definition for " + e.getKey().getName());
                   }
                }
                changeState(OsUsersViewStates.USERS_LIST_REFRESHED);
             }
          });

          if (callbacks.size() == 1)
          {
             TaggedName selectedUser = callbacks.keySet().toArray(new TaggedName [1])[0];
             final String name = selectedUser.getName();
             this.adminService.listAssociatedFwdUsers(name, new AsyncCallback<TaggedName[]>()
             {

                @Override
                public void onSuccess(TaggedName[] result)
                {
                   getView().setAssociatedFwdUsers(result);
                }

                @Override
                public void onFailure(Throwable caught)
                {
                   logger.log(Level.INFO, "Can't get associated FWD users for the OS user" + name);
                }
             });
          }
          else
          {
             getView().setAssociatedFwdUsers(null);
          }
       }

       /**
        * Adds a new user.
        *
        * @param    newUser
        *           The new user definition
        */
       @Override
       public void addUser(OsUserDef newUser)
       {
          this.adminService.addOsUser(newUser, new AsyncCallback<Boolean>()
          {
             @Override
             public void onSuccess(Boolean result)
             {
                logger.log(Level.INFO, "addUser " + newUser.subjectId + ", Is added? " + result);
                updateUsersList(()-> restoreState());

                if (result == null || !result)
                {
                   serverAlarmsManager.ring("Couldn't add OS user account " + newUser.subjectId);
                }
             }

             @Override
             public void onFailure(Throwable caught)
             {
                updateUsersList(()-> restoreState());
             }
          });
       }

       /**
        * Updates a given user account.
        *
        * @param    user
        *           The given user definition
        */
       @Override
       public void updateUser(OsUserDef user)
       {
          this.adminService.setOsUser(user, new AsyncCallback<Boolean>()
          {
             @Override
             public void onSuccess(Boolean result)
             {
                logger.log(Level.INFO, "updateUser " + user.subjectId + ", Is updated? " + result);
                updateUsersList(()->{getView().selectUserByName(user.subjectId); restoreState();});
             }

             @Override
             public void onFailure(Throwable caught)
             {
                updateUsersList(()->{getView().selectUserByName(user.subjectId); restoreState();});
             }
          });
       }

       /**
        * Cancels the Find User Account Dialog and rolls back any related changes.
        */
       @Override
       public void cancelFindUserAccountDialog()
       {
       }

       /**
        * Setups the Find User Account Dialog.
        */
       @Override
       public void setupFindUserAccountDialog()
       {
          InputDialog dialog = inputDialogProvider.get();
          IFindAccountScreen findAccount = new IFindAccountScreen()
          {
             @Override
             public void findAccountByName(String name)
             {
                adminService.checkOsUser(
                         name,
                         new AsyncCallback<TaggedName>()
                         {
                            @Override
                            public void onFailure(Throwable caught)
                            {
                               serverAlarmsManager.ring();
                               modalDialogsManager.showInfo("Can't find OS user " + name + ".");
                            }

                            @Override
                            public void onSuccess(TaggedName result)
                            {
                               if (result != null)
                               {
                                  getView().selectUser(result);
                                  dialog.dismiss();
                               }
                               else
                               {
                                  modalDialogsManager.showInfo("Can't find OS user " + name + ".");
                               }
                            }
                         });
             }
          };

          findOsUserAccountManager.show(getView().getOsUserDefModalParent(), dialog, findAccount);
       }

       /**
        * Disables the target user account.
        *
        * @param    user
        *           The target user account given by its tagged name
        */
       @Override
       public void disableUserAccount(TaggedName user)
       {
          if (selectedUser == null ||
             selectedUser.subjectId == null ||
             !selectedUser.subjectId.equals(user.getName()))
          {
             return;
          }
          boolean enable = !selectedUser.enabled;
          String title   = enable ? "Enable User" : "Disable User";
          String message = (enable ? "Enable user " : "Disable user ") + user.getName() + "?";
          modalDialogsManager.showYesNo(title, message, MessageType.QUESTION, button -> {
             if (button != 0)
             {
                return;
             }
             selectedUser.enabled = enable;
             adminService.setOsUser(selectedUser, new AsyncCallback<Boolean>()
             {

                @Override
                public void onFailure(Throwable caught)
                {
                   updateUsersList(() -> getView().selectUser(user));
                   logger.log(Level.WARNING, "setUser " + user.getName() + " got:", caught);
                   modalDialogsManager.showError("Can't " + (enable ? "enable" : "disable") +
                            user.getName() + " user account.");
                }

                @Override
                public void onSuccess(Boolean result)
                {
                   updateUsersList(() -> getView().selectUser(user));
                   if (!result)
                   {
                      modalDialogsManager.showError("Can't update to " +
                               (enable ? "enable" : "disable") + user.getName() + " user account.");
                   }
                }
             });
          });
       }
    }