/***********************************************************
Copyright (C) 2022 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.serverstub.eai.v1_0;

import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;

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

import com.verisign.epp.codec.contact.EPPContactCreateCmd;
import com.verisign.epp.codec.contact.EPPContactInfoCmd;
import com.verisign.epp.codec.contact.EPPContactInfoResp;
import com.verisign.epp.codec.contact.EPPContactUpdateCmd;
import com.verisign.epp.codec.eai.v1_0.EPPEAIExtFactory;
import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.gen.EPPResult;
import com.verisign.epp.codec.gen.EPPService;
import com.verisign.epp.codec.gen.EPPTransId;
import com.verisign.epp.framework.EPPEvent;
import com.verisign.epp.framework.EPPEventResponse;
import com.verisign.epp.serverstub.ContactHandler;
import com.verisign.epp.serverstub.SessionData;

/**
 * The {@code EAIContactHandler} class extends the {@link ContactHandler} class
 * to implement the behavior defined in draft-ietf-regext-epp-eai for commands
 * and responses that contain EAI addresses when the client does or does not
 * support draft-ietf-regext-epp-eai.
 */
public class EAIContactHandler extends ContactHandler {
	/** Default server transaction identifier */
	private static final String svrTransId = "54322-XYZ";

	/**
	 * Logger
	 */
	private static Logger cat = LoggerFactory.getLogger(EAIContactHandler.class);

	/**
	 * Constructs an instance of {@code EAIContactHandler}
	 */
	public EAIContactHandler() {
	}

	/**
	 * Invoked when a Contact Create command is received. This method will key
	 * off a contact starting with the ID "EAI" to include an EAI address in the
	 * response or return an error if the client doesn't support EAI.
	 *
	 * @param aEvent
	 *           The {@code EPPEvent} that is being handled
	 * @param aData
	 *           Any data that a Server needs to send to this
	 *           {@code EPPDomaindHandler}
	 *
	 * @return EPPEventResponse The response that should be sent back to the
	 *         client.
	 */
	public EPPEventResponse doContactCreate(EPPEvent aEvent, Object aData) {
		SessionData sessionData = (SessionData) aData;

		EPPContactCreateCmd theCommand = (EPPContactCreateCmd) aEvent.getMessage();

		// EAI contact create?
		if (theCommand.getId().startsWith("EAI")) {
			// Client does NOT support EAI?
			if ((theCommand.getId().equalsIgnoreCase("EAI-notsupported"))
			      || (!supportsNamespace(EPPEAIExtFactory.NS, sessionData.getLoginCmd().getExtensionServices()))) {

				// Is Email set and is not an ASCII value?
				if (theCommand.hasEmail() && !Charset.forName("US-ASCII").newEncoder().canEncode(theCommand.getEmail())) {
					EPPTransId transId = new EPPTransId(theCommand.getTransId(), svrTransId);
					EPPResponse theResponse = new EPPResponse(transId);
					EPPResult theResult = new EPPResult(EPPResult.DATA_MGT_POLICY_VIOLATION);
					theResult.addExtValueReason("EAI not supported with EAI value");
					theResponse.setResult(theResult);

					return new EPPEventResponse(theResponse);
				}
				else {
					return super.doContactCreate(aEvent, aData);
				}

			}
			else { // Client does support EAI
				// Server validates the Email if set
				return super.doContactCreate(aEvent, aData);
			}
		}
		else {
			return super.doContactCreate(aEvent, aData);
		}

	}

	/**
	 * Invoked when a Contact Update command is received. This method will key
	 * off a contact starting with the ID "EAI" to include an EAI address in the
	 * response or return an error if the client doesn't support EAI.
	 *
	 * @param aEvent
	 *           The {@code EPPEvent} that is being handled
	 * @param aData
	 *           Any data that a Server needs to send to this
	 *           {@code EPPDomaindHandler}
	 *
	 * @return EPPEventResponse The response that should be sent back to the
	 *         client.
	 */
	public EPPEventResponse doContactUpdate(EPPEvent aEvent, Object aData) {
		SessionData sessionData = (SessionData) aData;

		EPPContactUpdateCmd theCommand = (EPPContactUpdateCmd) aEvent.getMessage();

		// EAI contact create?
		if (theCommand.getId().startsWith("EAI")) {
			// Client does NOT support EAI?
			if ((theCommand.getId().equalsIgnoreCase("EAI-notsupported"))
			      || (!supportsNamespace(EPPEAIExtFactory.NS, sessionData.getLoginCmd().getExtensionServices()))) {

				// Is Email set and is not an ASCII value?
				if ((theCommand.hasChange() && theCommand.getChange().hasEmail())
				      && !Charset.forName("US-ASCII").newEncoder().canEncode(theCommand.getChange().getEmail())) {
					EPPTransId transId = new EPPTransId(theCommand.getTransId(), svrTransId);
					EPPResponse theResponse = new EPPResponse(transId);
					EPPResult theResult = new EPPResult(EPPResult.DATA_MGT_POLICY_VIOLATION);
					theResult.addExtValueReason("EAI not supported with EAI value");
					theResponse.setResult(theResult);

					return new EPPEventResponse(theResponse);
				}
				else {
					return super.doContactUpdate(aEvent, aData);
				}

			}
			else { // Client does support EAI
				// Server validates the Email if set
				return super.doContactUpdate(aEvent, aData);
			}
		}
		else {
			return super.doContactUpdate(aEvent, aData);
		}
	}

	/**
	 * Invoked when a Contact Info command is received. This method will key off
	 * a contact starting with the ID "EAI" to include an EAI address in the
	 * response or return an error if the client doesn't support EAI.
	 *
	 * @param aEvent
	 *           The {@code EPPEvent} that is being handled
	 * @param aData
	 *           Any data that a Server needs to send to this
	 *           {@code EPPDomaindHandler}
	 *
	 * @return EPPEventResponse The response that should be sent back to the
	 *         client.
	 */
	public EPPEventResponse doContactInfo(EPPEvent aEvent, Object aData) {
		SessionData sessionData = (SessionData) aData;

		EPPContactInfoCmd theCommand = (EPPContactInfoCmd) aEvent.getMessage();

		// EAI contact create?
		if (theCommand.getId().startsWith("EAI")) {

			// Client does NOT support EAI?
			if ((theCommand.getId().equalsIgnoreCase("EAI-notsupported"))
			      || (!supportsNamespace(EPPEAIExtFactory.NS, sessionData.getLoginCmd().getExtensionServices()))) {
				EPPTransId transId = new EPPTransId(theCommand.getTransId(), svrTransId);
				EPPResponse theResponse = new EPPResponse(transId);
				EPPResult theResult = new EPPResult(EPPResult.DATA_MGT_POLICY_VIOLATION);
				theResult.addExtValueReason("EAI not supported with EAI value");
				theResponse.setResult(theResult);

				return new EPPEventResponse(theResponse);
			}
			else {
				EPPContactInfoResp theResponse = super.getDefaultInfoResponseWithAllElements(theCommand);
				theResponse.setEmail("DörteSörensen2@example.com");
				return new EPPEventResponse(theResponse);
			}

		}
		else {
			return super.doContactInfo(aEvent, aData);

		}

	}

	/**
	 * Is the specified XML namespace in the list of services?
	 *
	 * @param aNamespace
	 *           XML namespace string
	 * @param aServices
	 *           {@code List} of {@link EPPService} objects.
	 * @return {@code true} if the XML namespace is supported; {@code false}
	 *         otherwise.
	 */
	private boolean supportsNamespace(String aNamespace, List<EPPService> aServices) {

		cat.debug("supportsNamespace(String, List); Looking for namespace " + aNamespace + " support");

		if (aServices != null) {

			Iterator iterator = aServices.iterator();

			while (iterator.hasNext()) {
				EPPService theService = (EPPService) iterator.next();

				if (theService.getNamespaceURI().equals(aNamespace)) {
					cat.debug("supportsNamespace(String, List); namespace " + aNamespace + " supported");
					return true;
				}
			}
		}

		cat.debug("supportsNamespace(String, List); namespace " + aNamespace + " not supported");
		return false;
	}

}
