/***********************************************************
Copyright (C) 2010 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;

// Logging Imports
import java.util.Date;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;

import com.verisign.epp.codec.domain.EPPDomainCreateCmd;
import com.verisign.epp.codec.domain.EPPDomainCreateResp;
import com.verisign.epp.codec.domain.EPPDomainInfoCmd;
import com.verisign.epp.codec.domain.EPPDomainInfoResp;
import com.verisign.epp.codec.domain.EPPDomainUpdateCmd;
import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.gen.EPPResult;
import com.verisign.epp.codec.secdnsext.v11.EPPSecDNSAlgorithm;
import com.verisign.epp.codec.secdnsext.v11.EPPSecDNSExtCreate;
import com.verisign.epp.codec.secdnsext.v11.EPPSecDNSExtDsData;
import com.verisign.epp.codec.secdnsext.v11.EPPSecDNSExtInfData;
import com.verisign.epp.codec.secdnsext.v11.EPPSecDNSExtKeyData;
import com.verisign.epp.codec.secdnsext.v11.EPPSecDNSExtUpdate;
import com.verisign.epp.util.EPPCatFactory;

/**
 * The <code>SecDNSV11SubDomainHandler</code> class is a concrete
 * {@link SecDNSSubDomainHandler} for version 1.1 of the secDNS extension. It is
 * wrapped by the wrapping {@link SecDNSDomainHandler} to support multiple
 * versions of the secDNS extension. Any version 1.1 specific behavior is
 * handled by <code>SecDNSV11SubDomainHandler</code>.
 */
public class SecDNSV11SubDomainHandler implements SecDNSSubDomainHandler {

	/** Used for logging */
	private static Logger cat = Logger.getLogger(
			SecDNSV11SubDomainHandler.class.getName(), EPPCatFactory
					.getInstance().getFactory());

	/**
	 * Handle an EPP Domain Create Command for version 1.1 of the secDNS
	 * extension. The following is the handling by input domain name:<br>
	 * <ul>
	 * <li><code>key-data-interface.com</code> - Only support the Key Data
	 * Interface, meaning if DS data is passed that a 2306 error will be
	 * returned.
	 * <li><code>ds-data-interface.com</code> - Only support the DS Data
	 * Interface, meaning if Key data is passed that a 2306 error will be
	 * returned.
	 * <li><code>maxsiglife-not-supported.com</code> - If the maxSigLife element
	 * is included, a 2102 error is returned due to lack of support.
	 * <li>default - Log the input at info level and return a successful EPP
	 * response.
	 * </ul>
	 * 
	 * @param aCreateCommand
	 *            Command sent by the client
	 * @param aData
	 *            Server data. This is assumed to be an instance of
	 *            <code>SessionData</code>.
	 * 
	 * @return An <code>EPPResponse</code> to be returned to the client. The
	 *         transaction id (client and server) is not set.
	 */
	public EPPResponse doDomainCreate(EPPDomainCreateCmd aCreateCommand,
			Object aData) {
		EPPResponse theResponse;

		// print the incoming secDNS extension
		EPPSecDNSExtCreate secDNScreate = (EPPSecDNSExtCreate) aCreateCommand
				.getExtension(EPPSecDNSExtCreate.class);

		// maxSigLife?
		if (secDNScreate.hasMaxSigLife()) {

			if (aCreateCommand.getName().equalsIgnoreCase(
					"maxsiglife-not-supported.com")) {
				cat
						.error("SecDNSDomainHandler.doDomainCreate: secDNS:create maxSigLife specified for unsupporting server");
				EPPResult theResult = new EPPResult(
						EPPResult.UNIMPLEMENTED_OPTION);
				theResult.addExtValueReason("maxSigLife not supported");
				return new EPPResponse(null, theResult);
			}

			cat
					.info("SecDNSV11SubDomainHandler.doDomainCreate: secDNS:create maxSigLife = \n"
							+ secDNScreate.getMaxSigLife());
		}

		// dsData?
		if (secDNScreate.hasDsData()) {

			// Simulate server supporting Key Data Interface?
			if (aCreateCommand.getName().equalsIgnoreCase(
					"key-data-interface.com")) {
				cat
						.error("SecDNSDomainHandler.doDomainCreate: secDNS:create for server only supporting Key Data Interface");
				EPPResult theResult = new EPPResult(
						EPPResult.PARAM_VALUE_POLICY_ERROR);
				theResult
						.addExtValueReason("Only Key Data Interface supported");
				return new EPPResponse(null, theResult);
			}

			cat
					.info("SecDNSV11SubDomainHandler.doDomainCreate: secDNS:create dsData = \n"
							+ secDNScreate.getDsData());
		} // keyData?
		else if (secDNScreate.hasKeyData()) {

			// Simulate server supporting DS Data Interface?
			if (aCreateCommand.getName().equalsIgnoreCase(
					"ds-data-interface.com")) {
				cat
						.error("SecDNSDomainHandler.doDomainCreate: secDNS:create for server only supporting DS Data Interface");
				EPPResult theResult = new EPPResult(
						EPPResult.PARAM_VALUE_POLICY_ERROR);
				theResult.addExtValueReason("Only DS Data Interface supported");
				return new EPPResponse(null, theResult);
			}

			cat
					.info("SecDNSV11SubDomainHandler.doDomainCreate: secDNS:create dsData = \n"
							+ secDNScreate.getKeyData());
		}
		
		theResponse = new EPPDomainCreateResp(null, aCreateCommand.getName(),
				new Date());

		return theResponse;
	}

	/**
	 * Handle an EPP Domain Update Command for version 1.1 of the secDNS
	 * extension. The following is the handling by input domain name:<br>
	 * <ul>
	 * <li><code>urgent-not-supported.com</code> - If the urgent attribute is
	 * true, a 2102 error is returned due to lack of support.
	 * <li><code>urgent-supported-cannot-be-urgent.com</code> - If the urgent
	 * attribute is true, a 2306 error is returned due to the inability to
	 * complete the command with high priority.
	 * <li><code>key-data-interface.com</code> - Only support the Key Data
	 * Interface, meaning if DS data is passed that a 2306 error will be
	 * returned.
	 * <li><code>ds-data-interface.com</code> - Only support the DS Data
	 * Interface, meaning if Key data is passed that a 2306 error will be
	 * returned.
	 * <li><code>maxsiglife-not-supported.com</code> - If the maxSigLife element
	 * is included with a secDNS:chg, a 2102 error is returned due to lack of
	 * support.
	 * <li>default - Log the input at info level and return a successful EPP
	 * response.
	 * </ul>
	 * 
	 * @param aUpdateCommand
	 *            Command sent by the client
	 * @param aData
	 *            Server data. This is assumed to be an instance of
	 *            <code>SessionData</code>.
	 * 
	 * @return An <code>EPPResponse</code> to be returned to the client. The
	 *         transaction id (client and server) is not set.
	 */
	public EPPResponse doDomainUpdate(EPPDomainUpdateCmd aUpdateCommand,
			Object aData) {

		// print the incoming secDNS extension
		EPPSecDNSExtUpdate secDNSupdate = (EPPSecDNSExtUpdate) aUpdateCommand
				.getExtension(EPPSecDNSExtUpdate.class);
		
		boolean dsDataInterface = false;
		boolean keyDataInterface = false;
		boolean dsDataFound = false;
		boolean keyDataFound = false;
		
		if (aUpdateCommand.getName().equalsIgnoreCase("key-data-interface.com")) {
			keyDataInterface = true;
		}
		else if (aUpdateCommand.getName().equalsIgnoreCase("ds-data-interface.com")) {
			dsDataInterface = true;
		}

		if (secDNSupdate != null) {

			if (secDNSupdate.isUrgent()) {
				if (aUpdateCommand.getName().equalsIgnoreCase(
						"urgent-not-supported.com")) {
					EPPResult theResult = new EPPResult(
							EPPResult.UNIMPLEMENTED_OPTION);
					theResult
							.addExtValueReason("attribute \"urgent\" NOT supported");
					return new EPPResponse(null, theResult);
				}
				else if (aUpdateCommand.getName().equalsIgnoreCase(
						"urgent-supported-cannot-be-urgent.com")) {
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("attribute \"urgent\" supported, but cannot be completed with high priority");
					return new EPPResponse(null, theResult);
				}
				else {
					cat
							.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update urgent true");
				}
			}

			// -- Remove

			// secDNS:rem all?
			if (secDNSupdate.isRemAllData()) {
				cat
						.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:rem ALL");
			}
			else if (secDNSupdate.hasRemDsData()) {

				// Simulate server supporting Key Data Interface?
				if (keyDataInterface) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:rem dsData for server only supporting Key Data Interface");
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("Only Key Data Interface supported");
					return new EPPResponse(null, theResult);
				}

				dsDataFound = true;
				cat
						.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:rem dsData = "
								+ secDNSupdate.getRemDsData());
			}
			else if (secDNSupdate.hasRemKeyData()) {

				// Simulate server supporting DS Data Interface?
				if (dsDataInterface) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:rem keyData for server only supporting DS Data Interface");
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("Only DS Data Interface supported");
					return new EPPResponse(null, theResult);
				}

				keyDataFound = true;
				cat
						.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:rem keyData = "
								+ secDNSupdate.getRemKeyData());
			}

			// -- Add

			// secDNS:add dsData?
			if (secDNSupdate.hasAddDsData()) {

				// Key Data Interface already used?
				if (keyDataFound) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:add dsData when keyData was used on secDNS:rem");
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("DS Data Interface and Key Data Interface cannot be mixed");
					return new EPPResponse(null, theResult);
				}

				// Simulate server supporting Key Data Interface?
				if (keyDataInterface) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:add dsData for server only supporting Key Data Interface");
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("Only Key Data Interface supported");
					return new EPPResponse(null, theResult);
				}

				cat
						.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:add dsData = "
								+ secDNSupdate.getAddDsData());
			}

			// secDNS:add keyData?
			if (secDNSupdate.hasAddKeyData()) {

				if (dsDataFound) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:add keyData when dsData was used on secDNS:rem");
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("DS Data Interface and Key Data Interface cannot be mixed");
					return new EPPResponse(null, theResult);
				}

				// Simulate server supporting DS Data Interface?
				if (dsDataInterface) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:add keyData for server only supporting DS Data Interface");
					EPPResult theResult = new EPPResult(
							EPPResult.PARAM_VALUE_POLICY_ERROR);
					theResult
							.addExtValueReason("Only DS Data Interface supported");
					return new EPPResponse(null, theResult);
				}

				cat
						.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:add keyData = "
								+ secDNSupdate.getAddKeyData());
			}

			// -- Change
			if (secDNSupdate.hasChg()) {

				if (aUpdateCommand.getName().equalsIgnoreCase(
						"maxsiglife-not-supported.com")) {
					cat
							.error("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:chg maxSigLife specified for unsupporting server");
					EPPResult theResult = new EPPResult(
							EPPResult.UNIMPLEMENTED_OPTION);
					theResult.addExtValueReason("maxSigLife not supported");
					return new EPPResponse(null, theResult);
				}

				cat
						.info("SecDNSDomainHandler.doDomainUpdate: secDNS:update/secDNS:chg maxSigLife = "
								+ secDNSupdate.getMaxSigLife());
			}
		}
		else {
			cat
					.info("SecDNSDomainHandler.doDomainUpdate: no EPPSecDNSExtUpdate extension\n");
		}

		// Return successful EPPResponse, which is the default.
		return new EPPResponse();
	}

	/**
	 * Handle an EPP Domain Info Command. The following is the handling by input
	 * domain name:<br>
	 * <ul>
	 * <li><code>key-data-interface.com</code> - Return response with two keys
	 * using the Key Data Interface.
	 * <li><code>ds-data-interface-with-key.com</code> - Return response with
	 * two DS including the associated keys using the DS Data Interface.
	 * <li><code>ds-data-interface-with-maxsiglife.com</code> - Return response
	 * with two DS using the DS Data Interface and with the
	 * &lt;secDNS:maxSigLife&gt; element.
	 * <li>default - Return response with two DS using DS Data Interface.
	 * </ul>
	 * 
	 * @param aInfoCommand
	 *            Command sent by the client
	 * @param aInfoResponse
	 *            Response filled in without the secDNS extension.
	 * @param aData
	 *            Server data. This is assumed to be an instance of
	 *            <code>SessionData</code>.
	 * 
	 * @return An <code>EPPDomainInfoResp</code> to be returned to the client
	 *         with the secDNS extension attached.
	 */
	public EPPDomainInfoResp doDomainInfo(EPPDomainInfoCmd aInfoCommand,
			EPPDomainInfoResp aInfoResponse, Object aData) {

		EPPSecDNSExtInfData infData = new EPPSecDNSExtInfData();

		// instantiate a secDNS:keyData object
		EPPSecDNSExtKeyData keyData = new EPPSecDNSExtKeyData();
		keyData.setFlags(EPPSecDNSExtKeyData.FLAGS_ZONE_KEY_SEP);
		keyData.setProtocol(EPPSecDNSExtKeyData.DEFAULT_PROTOCOL);
		keyData.setAlg(EPPSecDNSAlgorithm.RSASHA1);
		keyData.setPubKey("AQPmsXk3Q1ngNSzsH1lrX63mRIhtwkkK+5Zj"
				+ "vxykBCV1NYne83+8RXkBElGb/YJ1n4TacMUs"
				+ "poZap7caJj7MdOaADKmzB2ci0vwpubNyW0t2"
				+ "AnaQqpy1ce+07Y8RkbTC6xCeEw1UQZ73PzIO"
				+ "OvJDdjwPxWaO9F7zSxnGpGt0WtuItQ==");

		// instantiate another secDNS:keyData object
		EPPSecDNSExtKeyData keyData2 = new EPPSecDNSExtKeyData(
				EPPSecDNSExtKeyData.FLAGS_ZONE_KEY_SEP,
				EPPSecDNSExtKeyData.DEFAULT_PROTOCOL,
				EPPSecDNSAlgorithm.RSASHA1,
				"AQOxXpFbRp7+zPBoTt6zL7Af0aEKzpS4JbVB"
						+ "5ofk5E5HpXuUmU+Hnt9hm2kMph6LZdEEL142"
						+ "nq0HrgiETFCsN/YM4Zn+meRkELLpCG93Cu/H"
						+ "hwvxfaZenUAAA6Vb9FwXQ1EMYRW05K/gh2Ge"
						+ "w5Sk/0o6Ev7DKG2YiDJYA17QsaZtFw==");

		if (aInfoCommand.getName().equalsIgnoreCase("key-data-interface.com")) {
			infData.appendKeyData(keyData);
			infData.appendKeyData(keyData2);
		}
		else { // default to DS Data Interface

			// instantiate a secDNS:dsData object
			EPPSecDNSExtDsData dsData = new EPPSecDNSExtDsData();
			dsData.setKeyTag(34095);
			dsData.setAlg(EPPSecDNSAlgorithm.RSASHA1);
			dsData.setDigestType(EPPSecDNSExtDsData.SHA1_DIGEST_TYPE);
			dsData.setDigest("6BD4FFFF11566D6E6A5BA44ED0018797564AA289");

			// instantiate another secDNS:dsData object
			EPPSecDNSExtDsData dsData2 = new EPPSecDNSExtDsData(10563,
					EPPSecDNSAlgorithm.RSASHA1,
					EPPSecDNSExtDsData.SHA1_DIGEST_TYPE,
					"9C20674BFF957211D129B0DFE9410AF753559D4B");

			// Add the key data to the DS?
			if (aInfoCommand.getName().equalsIgnoreCase(
					"ds-data-interface-with-key.com")) {
				dsData.setKeyData(keyData);
				dsData2.setKeyData(keyData2);
			}

			infData.appendDsData(dsData);
			infData.appendDsData(dsData2);

			// Include the maxSigLife attribute?
			if (aInfoCommand.getName().equalsIgnoreCase(
					"ds-data-interface-with-maxsiglife.com")) {
				infData.setMaxSigLife(604800);
			}
		}

		// set the secDNS:infData in the response as an extension
		aInfoResponse.addExtension(infData);

		return aInfoResponse;
	}
}
