/***********************************************************
Copyright (C) 2017 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.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import com.verisign.epp.codec.gen.EPPCodec;
import com.verisign.epp.codec.gen.EPPCodecComponent;
import com.verisign.epp.codec.gen.EPPMessage;
import com.verisign.epp.exception.EPPException;
import com.verisign.epp.pool.parser.EPPSchemaCachingParserPool;
import com.verisign.epp.pool.transformer.EPPTransformerPool;

/**
 * A concrete {@link EPPSendReceiveLogger} that logs the messages in raw form to
 * the Log4J com.verisign.epp.util.EPPXMLStream category. This logging category
 * is used for backward compatibility to logging configurations when the
 * {@link com.verisign.epp.util.EPPXMLStream} logged the packets directly.
 */
public class EPPRawSendReceiveLogger implements EPPSendReceiveLogger {

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

	private static Logger packetCat = LoggerFactory.getLogger(EPPXMLStream.class.getName() + ".packet");

	/**
	 * Log the raw sending of a message. No filtering or alterations are done to
	 * the attributes of the message.
	 * 
	 * @param aPacket
	 *           Packet to send. This may be <code>null</code> if the packet has
	 *           not been encoded yet.
	 * @param aMessage
	 *           The message that is being sent, which could be any concrete
	 *           <code>EPPMessage</code>, including a
	 *           {@link com.verisign.epp.codec.gen.EPPCommand}, an
	 *           {@link com.verisign.epp.codec.gen.EPPGreeting}, an
	 *           {@link com.verisign.epp.codec.gen.EPPHello}, or an
	 *           {@link com.verisign.epp.codec.gen.EPPResponse}. This may be
	 *           <code>null</code> if the <code>EPPMessage</code> is not
	 *           available.
	 */
	@Override
	public void logSend(byte[] aPacket, final EPPMessage aMessage) {
		cat.debug("logSend(byte[], EPPMessage): enter");

		this.log("writePacket() : Sending [", aPacket, aMessage);

		cat.debug("logSend(byte[], EPPMessage): exit");
	}

	/**
	 * Log the raw receiving of a message. No filtering or alterations are done
	 * to the attributes of the message.
	 * 
	 * @param aPacket
	 *           Packet received. This may be <code>null</code> if the packet is
	 *           not available.
	 * @param aMessage
	 *           The message received, which could be any concrete
	 *           <code>EPPMessage</code>, including a
	 *           {@link com.verisign.epp.codec.gen.EPPCommand}, an
	 *           {@link com.verisign.epp.codec.gen.EPPGreeting}, an
	 *           {@link com.verisign.epp.codec.gen.EPPHello}, or an
	 *           {@link com.verisign.epp.codec.gen.EPPResponse}. This may be
	 *           <code>null</code> if the <code>EPPMessage</code> is not
	 *           available.
	 */
	@Override
	public void logReceive(byte[] aPacket, final EPPMessage aMessage) {
		cat.debug("logReceive(byte[], EPPMessage): enter");

		this.log("decodePacket() : Received [", aPacket, aMessage);

		cat.debug("logReceive(byte[], EPPMessage): exit");
	}

	/**
	 * Writes the log given a log prefix set by either
	 * {@link #logReceive(byte[], EPPMessage)} or
	 * {@link #logSend(byte[], EPPMessage)}, the packet, and the message object.
	 * A non-<code>null</code> packet or message must be passed. It's most
	 * efficient to pass the packet over the message object, since the message
	 * object needed to be encoded into a packet.
	 * 
	 * @param logPrefix
	 *           Prefix to start the packet log with.
	 * @param aPacket
	 *           Packet to log if available; <code>null</code> otherwise.
	 * @param aMessage
	 *           Message object to log if available; <code>null</code> otherwise.
	 */
	private void log(String logPrefix, byte[] aPacket, final EPPMessage aMessage) {
		cat.debug("log(byte[], EPPMessage): enter");

		// If debug logging is not enabled, immediately return.
		if (!packetCat.isDebugEnabled())
			return;

		// Packet provided?
		if (aPacket != null) {
			packetCat.debug(logPrefix + new String(aPacket) + "]");
		}
		// Message provided?
		else if (aMessage != null) {

			try {
				Document theDoc = EPPCodec.getInstance().encode(aMessage);

				EPPXMLByteArray theByteArray = new EPPXMLByteArray(EPPSchemaCachingParserPool.getInstance().getPool(),
				      EPPTransformerPool.getInstance().getPool());
				byte[] thePacket = theByteArray.encode(theDoc);

				packetCat.debug(logPrefix + new String(thePacket) + "]");
			}
			catch (EPPException ex) {
				cat.error("log(byte[], EPPMessage); Error encoding message: " + ex);
				return;
			}

		}
		// Neither packet or message provided
		else {
			cat.error("log(byte[], EPPMessage); Both aPacket and aMessage are null");
		}

		cat.debug("log(byte[], EPPMessage): exit");
	}

	/**
	 * Utility method used to optionally mask specific message attributes based
	 * on the concrete <code>EPPSendReceiveLogger</code>.
	 * <code>EPPRawSendReceiveLogger</code> does not perform any masking, so the
	 * <code>aMessage</code> parameter is directly returned.
	 * 
	 * @param aMessage
	 *           Message to mask. <code>EPPRawSendReceiveLogger</code> does not
	 *           perform any masking, so the <code>aMessage</code> parameter is
	 *           directly returned.
	 * @return Matches the <code>aMessage</code> parameter.
	 */
	@Override
	public EPPCodecComponent maskMessage(EPPCodecComponent aMessage) {
		return aMessage;
	}

	/**
	 * Mask a general string of sensitive information. Specific string regular
	 * expressions are checked and matching strings are masked by this method for
	 * inclusion in exceptions and logs.
	 * 
	 * @param aString
	 *           <code>String</code> to scan for masking
	 * 
	 * @return Masked <code>String</code>.
	 */
	@Override
	public String maskString(String aString) {
		return aString;
	}

}
