/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.Message;



import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.messages.ExtensionMessages.*;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.
       ErrorLogAccountStatusNotificationHandlerCfgDefn;
import org.opends.server.admin.std.server.AccountStatusNotificationHandlerCfg;
import org.opends.server.admin.std.server.
       ErrorLogAccountStatusNotificationHandlerCfg;
import org.opends.server.api.AccountStatusNotificationHandler;
import org.opends.server.config.ConfigException;
import org.opends.server.types.AccountStatusNotification;
import org.opends.server.types.AccountStatusNotificationType;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;



/**
 * This class defines an account status notification handler that will write
 * information about status notifications using the Directory Server's error
 * logging facility.
 */
public class ErrorLogAccountStatusNotificationHandler
       extends
          AccountStatusNotificationHandler
          <ErrorLogAccountStatusNotificationHandlerCfg>
       implements
          ConfigurationChangeListener
          <ErrorLogAccountStatusNotificationHandlerCfg>
{
  /**
   * The set of names for the account status notification types that may be
   * logged by this notification handler.
   */
  private static final HashSet<String> NOTIFICATION_TYPE_NAMES =
       new HashSet<String>();

  static
  {
    for (AccountStatusNotificationType t :
         AccountStatusNotificationType.values())
    {
      NOTIFICATION_TYPE_NAMES.add(t.getName());
    }
  }


  // The DN of the configuration entry for this notification handler.
  private DN configEntryDN;

  // The set of notification types that should generate log messages.
  private HashSet<AccountStatusNotificationType> notificationTypes;



  /**
   * {@inheritDoc}
   */
  public void initializeStatusNotificationHandler(
      ErrorLogAccountStatusNotificationHandlerCfg configuration
      )
      throws ConfigException, InitializationException
  {
    configuration.addErrorLogChangeListener (this);
    configEntryDN = configuration.dn();

    // Read configuration and apply changes.
    boolean applyChanges = true;
    processNotificationHandlerConfig (configuration, applyChanges);
  }



  /**
   * {@inheritDoc}
   */
  public void handleStatusNotification(
                   AccountStatusNotification notification)
  {
    logError(NOTE_ERRORLOG_ACCTNOTHANDLER_NOTIFICATION.get(
                  notification.getNotificationType().getName(),
                  String.valueOf(notification.getUserDN()),
                  notification.getMessage().getDescriptor().getId(),
                  notification.getMessage()));
  }



  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isConfigurationAcceptable(
                      AccountStatusNotificationHandlerCfg configuration,
                      List<Message> unacceptableReasons)
  {
    ErrorLogAccountStatusNotificationHandlerCfg config =
         (ErrorLogAccountStatusNotificationHandlerCfg) configuration;
    return isConfigurationChangeAcceptable(config, unacceptableReasons);
  }



  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationChangeAcceptable(
      ErrorLogAccountStatusNotificationHandlerCfg configuration,
      List<Message> unacceptableReasons
      )
  {
    // Make sure that we can process the defined notification handler.
    // If so, then we'll accept the new configuration.
    boolean applyChanges = false;
    boolean isAcceptable = processNotificationHandlerConfig (
        configuration, applyChanges
        );

    return isAcceptable;
  }



  /**
   * Makes a best-effort attempt to apply the configuration contained in the
   * provided entry.  Information about the result of this processing should be
   * added to the provided message list.  Information should always be added to
   * this list if a configuration change could not be applied.  If detailed
   * results are requested, then information about the changes applied
   * successfully (and optionally about parameters that were not changed) should
   * also be included.
   *
   * @param  configuration    The entry containing the new configuration to
   *                          apply for this component.
   * @param  detailedResults  Indicates whether detailed information about the
   *                          processing should be added to the list.
   *
   * @return  Information about the result of the configuration update.
   */
  public ConfigChangeResult applyConfigurationChange (
      ErrorLogAccountStatusNotificationHandlerCfg configuration,
      boolean detailedResults
      )
  {
    ConfigChangeResult changeResult = applyConfigurationChange (configuration);
    return changeResult;
  }



  /**
   * {@inheritDoc}
   */
  public ConfigChangeResult applyConfigurationChange (
      ErrorLogAccountStatusNotificationHandlerCfg configuration
      )
  {
    ResultCode resultCode = ResultCode.SUCCESS;
    boolean adminActionRequired = false;
    ArrayList<Message> messages = new ArrayList<Message>();
    ConfigChangeResult changeResult = new ConfigChangeResult(
        resultCode, adminActionRequired, messages
        );

    // Initialize the set of notification types that should generate log
    // messages.
    boolean applyChanges = false;
    processNotificationHandlerConfig (
        configuration, applyChanges
        );

    return changeResult;
  }


  /**
   * Parses the provided configuration and configure the notification handler.
   *
   * @param configuration  The new configuration containing the changes.
   * @param applyChanges   If true then take into account the new configuration.
   *
   * @return  The mapping between strings of character set values and the
   *          minimum number of characters required from those sets.
   */
  public boolean processNotificationHandlerConfig(
      ErrorLogAccountStatusNotificationHandlerCfg configuration,
      boolean                                     applyChanges
      )
  {
    // false if the configuration is not acceptable
    boolean isAcceptable = true;

    // The set of notification types that should generate log messages.
    HashSet<AccountStatusNotificationType> newNotificationTypes =
        new HashSet<AccountStatusNotificationType>();

    // Initialize the set of notification types that should generate log
    // messages.
    for (ErrorLogAccountStatusNotificationHandlerCfgDefn.
         AccountStatusNotificationType configNotificationType:
         configuration.getAccountStatusNotificationType())
    {
      newNotificationTypes.add (getNotificationType (configNotificationType));
    }

    if (applyChanges && isAcceptable)
    {
      notificationTypes = newNotificationTypes;
    }

    return isAcceptable;
  }


  /**
   * Gets the OpenDS notification type object that corresponds to the
   * configuration counterpart.
   *
   * @param  configNotificationType  The configuration notification type for
   *                                 which  to retrieve the OpenDS notification
   *                                 type.
   */
  private AccountStatusNotificationType getNotificationType(
      ErrorLogAccountStatusNotificationHandlerCfgDefn.
         AccountStatusNotificationType configNotificationType
      )
  {
    AccountStatusNotificationType nt = null;

    switch (configNotificationType)
    {
    case ACCOUNT_TEMPORARILY_LOCKED:
         nt = AccountStatusNotificationType.ACCOUNT_TEMPORARILY_LOCKED;
         break;
    case ACCOUNT_PERMANENTLY_LOCKED:
         nt = AccountStatusNotificationType.ACCOUNT_PERMANENTLY_LOCKED;
         break;
    case ACCOUNT_UNLOCKED:
         nt = AccountStatusNotificationType.ACCOUNT_UNLOCKED;
         break;
    case ACCOUNT_IDLE_LOCKED:
         nt = AccountStatusNotificationType.ACCOUNT_IDLE_LOCKED;
         break;
    case ACCOUNT_RESET_LOCKED:
         nt = AccountStatusNotificationType.ACCOUNT_RESET_LOCKED;
         break;
    case ACCOUNT_DISABLED:
         nt = AccountStatusNotificationType.ACCOUNT_DISABLED;
         break;
    case ACCOUNT_ENABLED:
         nt = AccountStatusNotificationType.ACCOUNT_ENABLED;
         break;
    case ACCOUNT_EXPIRED:
         nt = AccountStatusNotificationType.ACCOUNT_EXPIRED;
         break;
    case PASSWORD_EXPIRED:
         nt = AccountStatusNotificationType.PASSWORD_EXPIRED;
         break;
    case PASSWORD_EXPIRING:
         nt = AccountStatusNotificationType.PASSWORD_EXPIRING;
         break;
    case PASSWORD_RESET:
         nt = AccountStatusNotificationType.PASSWORD_RESET;
         break;
    case PASSWORD_CHANGED:
         nt = AccountStatusNotificationType.PASSWORD_CHANGED;
         break;
    }

    return nt;
  }

}

