@Override
  public void deverouiller(Verrou verrou, Credentials credentials) throws ServiceException {
    CompteUtilisateur compteUtilisateur =
        ((CompteUtilisateurDao) dao).readByUsername(credentials.getUsername());
    if (compteUtilisateur == null)
      serviceException(ServiceExceptionType.IDENTIFICATION_COMPTE_UTILISATEUR_INEXISTANT);

    // est ce que le compte est verouille
    if (compteUtilisateur.getVerrou() == null)
      serviceException(ServiceExceptionType.IDENTIFICATION_COMPTE_UTILISATEUR_ACTIF);

    if (compteUtilisateur.getVerrou().getCause() == null
        || !compteUtilisateur.getVerrou().getCode().equals(verrou.getCode()))
      serviceException(
          ServiceExceptionType.IDENTIFICATION_COMPTE_UTILISATEUR_CODE_DEVEROUILLAGE_INCONNU);

    if (Cause.ACCESS_MULTIPLE.equals(verrou.getCause())
        && !compteUtilisateur.getCredentials().getPassword().equals(credentials.getPassword()))
      serviceException(ServiceExceptionType.IDENTIFICATION_COMPTE_UTILISATEUR_INEXISTANT);

    if (!compteUtilisateur.getVerrou().getJeton().equals(verrou.getJeton()))
      serviceException(
          ServiceExceptionType.IDENTIFICATION_COMPTE_UTILISATEUR_JETON_DEVEROUILLAGE_INCONNU);

    switch (verrou.getCause()) {
      case ACCESS_MULTIPLE:
        infos.clear();
        notifier(
            NotificationMessageType.AVIS_COMPTE_UTILISATEUR_DEVERROUILLE_ACCES_MULTIPLE,
            new Object[] {"nomPrenomsAgentEtat", compteUtilisateur.getUtilisateur().getNom()},
            compteUtilisateur);
        break;
      case REINITIALISATION_PASSWORD:
        compteUtilisateur
            .getCredentials()
            .setPassword(
                credentials.getPassword()); // on ecrase son ancien mot de passe avec le nouveau
        notifier(
            NotificationMessageType.AVIS_COMPTE_UTILISATEUR_DEVERROUILLE_REINITIALISATION_PASSWORD,
            new Object[] {
              "nomPrenomsAgentEtat",
              compteUtilisateur.getUtilisateur().getNom(),
              "loginUtilisateur",
              credentials.getUsername(),
              "motPasseUtilisateur",
              credentials.getPassword()
            },
            compteUtilisateur);
        break;
    }
    compteUtilisateur.setVerrou(null);
    dao.update(compteUtilisateur);
  }
  private void notifierVerrou(CompteUtilisateur compteUtilisateur) {
    switch (compteUtilisateur.getVerrou().getCause()) {
      case ACCESS_MULTIPLE:
        notifier(
            NotificationMessageType.AVIS_COMPTE_UTILISATEUR_VERROUILLE_ACCES_MULTIPLE,
            new Object[] {
              "nomPrenomsAgentEtat",
              compteUtilisateur.getUtilisateur().getNom(),
              "codeDeverouillage",
              compteUtilisateur.getVerrou().getJeton(),
              "lienDeverouillage",
              lienDeverouillage(compteUtilisateur),
              "dateHeureVerouillage",
              formatDate(new Date()),
              "adresseIP",
              "000.000.000.000",
              "adresseGeographique",
              "A déterminer"
            },
            compteUtilisateur);
        break;

      case REINITIALISATION_PASSWORD:
        notifier(
            NotificationMessageType.AVIS_COMPTE_UTILISATEUR_VERROUILLE_REINITIALISATION_PASSWORD,
            new Object[] {
              "nomPrenomsAgentEtat",
              compteUtilisateur.getUtilisateur().getNom(),
              "codeDeverouillage",
              compteUtilisateur.getVerrou().getJeton(),
              "lienDeverouillage",
              lienDeverouillage(compteUtilisateur)
            },
            compteUtilisateur);
        break;

      case DESACTIVATION_COMPTE:
        notifier(
            NotificationMessageType.AVIS_COMPTE_UTILISATEUR_VERROUILLE_REINITIALISATION_PASSWORD,
            new Object[] {"nomPrenomsAgentEtat", compteUtilisateur.getUtilisateur().getNom()},
            compteUtilisateur);
        break;
    }
  }
  @Override
  public void modifierRoles(
      CompteUtilisateur compteUtilisateur,
      Collection<Role> nouveauxRoles,
      DelegueSotra delegueSotra)
      throws ServiceException {
    // suppression de roles
    Collection<Role> suppression = new HashSet<>();
    for (Role role : compteUtilisateur.getRoles())
      if (!nouveauxRoles.contains(role)) suppression.add(role);
    for (Role role : suppression) {
      compteUtilisateur.getRoles().remove(role);
      switch (role.getCode()) {
        default:
          break;
      }
    }

    // ajout de roles
    Collection<Role> ajout = new HashSet<>();
    for (Role role : nouveauxRoles)
      if (!compteUtilisateur.getRoles().contains(role)) ajout.add(role);

    for (Role role : ajout) {
      compteUtilisateur.getRoles().add(role);
      switch (role.getCode()) {
        case Code.ROLE_DELEGUE_SOTRA:
          if (compteUtilisateur.getUtilisateur() instanceof AgentEtat) {
            if (delegueSotraDao.readByAgentEtat((AgentEtat) compteUtilisateur.getUtilisateur())
                == null) delegueSotraDao.create(delegueSotra);
            delegueSotraDao.update(delegueSotra);
          }
          break;
        default:
          break;
      }
    }

    if (!suppression.isEmpty() || !ajout.isEmpty())
      ((CompteUtilisateurDao) dao).update(compteUtilisateur);
  }