/***********************************************************
Copyright (C) 2021 VeriSign, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

http://www.verisign.com/nds/naming/namestore/techdocs.html
***********************************************************/
package com.verisign.epp.codec.unhandlednamespaces.v1_0;

import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.gen.EPPUtil;

/**
 * Monitor for unhandled namespaces by logging the full XML namespaces for the
 * unhandled namespaces. This is the default monitor used for the filter classes
 * ({@link EPPUnhandledNamespacesResponseFilter} and
 * {@link EPPUnhandledNamespacesPollMessageFilter}).
 */
public class EPPUnhandledNamespacesMonitorLogger implements EPPUnhandledNamespacesMonitor {

  /**
   * Category for logging
   */
  private static Logger cat = LoggerFactory.getLogger(EPPUnhandledNamespacesMonitorLogger.class);

  /**
   * Custom logger. If the custom logger is set, the default logger via
   * {@code cat} will not be used for logging the unhandled namespaces.
   */
  private Logger logger;

  /**
   * Log the unhandled namespace suffix in place of the full XML namespace for
   * condensed logging. The default is to log the full XML namespaces.
   */
  private boolean useSuffix = false;

  /**
   * Default constructor with no usage specified.
   */
  public EPPUnhandledNamespacesMonitorLogger() {
  }

  /**
   * Constructor that takes a usage value, which will be included in the logs.
   *
   * @param aLogger
   *           Logger to use for logging. Set to {@code null} to use the
   *           default logger, which is
   *           {@code EPPUnhandledNamespacesMonitorLogger.class}.
   * @param aUseSuffix
   *           Log the unhandled namespace suffix in place of the full XML
   *           namespace for condensed logging.
   */
  public EPPUnhandledNamespacesMonitorLogger(Logger aLogger, boolean aUseSuffix) {
    this.logger = aLogger;
    this.useSuffix = aUseSuffix;
  }

  /**
   * Will the logs include the XML namespace suffix instead of the full XML
   * namespace?
   *
   * @return {@code true} if the logs include the XML namespace suffix instead
   *         of the full XML namespace; {@code false} otherwise.
   */
  public boolean isUseSuffix() {
    return this.useSuffix;
  }

  /**
   * Sets whether the logs include the XML namespace suffix instead of the full
   * XML namespace.
   *
   * @param useSuffix
   *           {@code true} if the logs include the XML namespace suffix
   *           instead of the full XML namespace; {@code false} otherwise.
   */
  public void setUseSuffix(boolean useSuffix) {
    this.useSuffix = useSuffix;
  }

  /**
   * Gets the custom logger to use for logging the unhandled namespaces. If
   * unset, the default logger using the
   * {@code EPPUnhandledNamespacesMonitorLogger} FQCN.
   * 
   * @return The custom logger if set; {@code null} otherwise.
   */
  public Logger getLogger() {
    return logger;
  }

  /**
   * Gets the custom logger to use for logging the unhandled namespaces. If
   * unset, the default logger using the
   * {@code EPPUnhandledNamespacesMonitorLogger} FQCN.
   * 
   * @param aLogger
   *           The custom logger to use. Set to {@code null} to not use a
   *           custom logger.
   */
  public void setLogger(Logger aLogger) {
    this.logger = aLogger;
  }

  /**
   * Method called to monitor for returning unhandled namespace information to
   * clients and to report it to the clients out of band to EPP. This method
   * will log the list of unhandled namespaces either using the full XML
   * namespace when {@code useSuffix} is {@code false} or using the XML
   * namespace suffix when {@code useSuffix} is {@code true}.
   *
   * @param aOrigResponse
   *           The original EPP response that was created without consideration
   *           of the namespaces supported by the client.
   * @param aFilteredResponse
   *           The filtered EPP response that includes the filtered the
   *           unhandled namespace XML into &lt;extValue&gt; elements.
   * @param aNoOp
   *           If set to {@code true}, the filter classes
   *           ({@code EPPUnhandledNamespacesResponseFilter} and
   *           {@code EPPUnhandledNamespacesPollMessageFilter}) are used only
   *           to identify for the use of unhandled namespaces and
   * @param aUnhandledNamespaces
   *           The list of unhandled namespace URIs that were filtered into
   *           &lt;extValue&gt; elements.
   * @param aData
   *           Data object passed to the filter classes
   *           ({@code EPPUnhandledNamespacesResponseFilter} and
   *           {@code EPPUnhandledNamespacesPollMessageFilter}).
   */
  @Override
  public void monitorUnhandledNamespaces(EPPResponse aOrigResponse, EPPResponse aFilteredResponse, boolean aNoOp,
        Set<String> aUnhandledNamespaces, Object aData) {

    Logger theLogger = cat;
    if (this.logger != null) {
      theLogger = this.logger;
    }

    if (aNoOp) {
      theLogger.debug("No op = true, so response with unhandled namespaces is unfiltered");
    }
    else if (theLogger.isInfoEnabled()) {
      theLogger.info(
            "Response with unhandled namespaces [" + aOrigResponse + "] filtered to [" + aFilteredResponse + "]");
    }

    // The original response and the filtered responses are not logged due to
    // size.

    // No unhandled namespaces?
    if (aUnhandledNamespaces == null || aUnhandledNamespaces.isEmpty()) {
      return;
    }

    if (theLogger.isInfoEnabled()) {
      String theMsg = "";

      boolean theFirst = true;

      for (String theNamespace : aUnhandledNamespaces) {
        // Ignore null namespaces
        if (theNamespace == null) {
          continue;
        }
        if (theFirst) {
          theFirst = false;
        }
        else {
          theMsg += ",";
        }

        if (this.useSuffix) {
          theMsg += EPPUtil.namespaceToNamespaceSuffix(theNamespace);
        }
        else {
          theMsg += theNamespace;
        }
      }

      theLogger.info("Unhandled namespaces = [" + theMsg + "]");
    }
  }

}
