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

import java.util.Date;

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

import com.verisign.epp.codec.change.type.EPPChangeAction;
import com.verisign.epp.codec.changeext.EPPChangeExt;
import com.verisign.epp.codec.domain.EPPDomainCreateCmd;
import com.verisign.epp.codec.domain.EPPDomainCreateResp;
import com.verisign.epp.codec.domain.EPPDomainDeleteCmd;
import com.verisign.epp.codec.domain.EPPDomainUpdateCmd;
import com.verisign.epp.codec.gen.EPPCommand;
import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.gen.EPPResult;
import com.verisign.epp.codec.gen.EPPTransId;
import com.verisign.epp.framework.EPPEvent;
import com.verisign.epp.framework.EPPEventResponse;
import com.verisign.epp.framework.EPPHandleEventException;
import com.verisign.epp.rootzone.util.RootZoneManager;


/**
 * The {@code RZDomainHandler} class is a concrete implementation of the
 * abstract {@code com.verisign.epp.framework.EPPDomainHandler} class for the Root Zone. It
 * defines the Server's response to all received EPP Domain Commands.
 * 
 * @see com.verisign.epp.framework.EPPEvent
 * @see com.verisign.epp.framework.EPPEventResponse
 */
public class RZDomainHandler extends DomainHandler {
	/** Constant server transaction id */
	private static final String svrTransId = "54322-SVR";

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

	/**
	 * Handles any common behavior that all Domain commands need to execute
	 * before they execute their command specific behavior.
	 * 
	 * @param aEvent
	 *           The {@code EPPEvent} that is being handled
	 * @param aData
	 *           Any data that a Server needs to send to this
	 *           {@code EPPDomainHandler} This is assumed to be an instance
	 *           of SessionData here.
	 * @exception EPPHandleEventException
	 *               Thrown if an error condition occurs. It must contain an
	 *               {@code EPPEventResponse}
	 */
	protected void preHandleEvent(EPPEvent aEvent, Object aData) throws EPPHandleEventException {
		SessionData sessionData = (SessionData) aData;
		EPPCommand theMessage = (EPPCommand) aEvent.getMessage();

		if (!sessionData.isLoggedIn()) {
			EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

			EPPResponse theResponse = new EPPResponse(transId);

			theResponse.setResult(EPPResult.COMMAND_FAILED_END);
			throw new EPPHandleEventException("The client has not established a session", theResponse);
		}

	}

	/**
	 * Returns an unimplemented object service error (2307) result.
	 * 
	 * @return EPPEventResponse Response containing an unimplemented object
	 *         service error (2307) result.
	 */
	private EPPEventResponse unsupportedCommandResult(EPPEvent aEvent, Object aData) {
		EPPCommand theCommand = (EPPCommand) aEvent.getMessage();
		EPPTransId theTransId = new EPPTransId(theCommand.getTransId(), svrTransId);

		EPPResponse response = new EPPResponse(theTransId);
		response.setResult(EPPResult.UNIMPLEMENTED_OBJECT_SERVICE);
		return new EPPEventResponse(response);
	}

	/**
	 * Invoked when a Domain command is received in the RZMS. A Change Action is
	 * constructed from the incoming message and passed to the server to be
	 * associated with the specified Change Request.
	 * 
	 * @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.
	 */
	protected EPPEventResponse doDomainCreate(EPPEvent aEvent, Object aData) {
		String requestId = null;

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

		cat.debug("doDomainCreate: command = [" + theCommand + "]");

		EPPTransId transId = new EPPTransId(theCommand.getTransId(), svrTransId);

		if (theCommand.getTransId() == null) {
			cat.error("doDomainCreate: Client transaction identifier is missing");

			EPPResult theResult = new EPPResult(EPPResult.PARAM_VALUE_POLICY_ERROR,
			      "Client transaction identifier is required on delete");
			EPPResponse theResponse = new EPPResponse(transId, theResult);

			return new EPPEventResponse(theResponse);
		}

		if (theCommand.hasExtension(EPPChangeExt.class)) {
			EPPChangeExt ext = (EPPChangeExt) theCommand.getExtension(EPPChangeExt.class);
			requestId = ext.getRequestId();
		}
		else {
			cat.error("doDomainCreate: EPPChangeExt missing");

			EPPResult theResult = new EPPResult(EPPResult.PARAM_VALUE_POLICY_ERROR,
			      "Change Extension is required on delete");
			EPPResponse theResponse = new EPPResponse(transId, theResult);

			return new EPPEventResponse(theResponse);
		}

		/**
		 * LOGIC: Simulate adding Change Action
		 */
		EPPChangeAction theAction = new EPPChangeAction(requestId, theCommand.getTransId(), svrTransId);
		theAction.setDefinition(theCommand.toString());
		RootZoneManager.addChangeAction(requestId, theAction);

		EPPResponse theResponse = new EPPDomainCreateResp(transId, theCommand.getName(), new Date());
		theResponse.setResult(EPPResult.SUCCESS);
		return new EPPEventResponse(theResponse);
	}

	/**
	 * Invoked when a Domain command is received in the RZMS. A Change Action is
	 * constructed from the incoming message and passed to the server to be
	 * associated with the specified Change Request.
	 * 
	 * @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.
	 */
	protected EPPEventResponse doDomainDelete(EPPEvent aEvent, Object aData) {
		String requestId = null;

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

		cat.debug("doDomainDelete: command = [" + theCommand + "]");

		EPPTransId transId = new EPPTransId(theCommand.getTransId(), svrTransId);

		if (theCommand.getTransId() == null) {
			cat.error("doDomainDelete: Client transaction identifier is missing");

			EPPResult theResult = new EPPResult(EPPResult.PARAM_VALUE_POLICY_ERROR,
			      "Client transaction identifier is required on delete");
			EPPResponse theResponse = new EPPResponse(transId, theResult);

			return new EPPEventResponse(theResponse);
		}

		if (theCommand.hasExtension(EPPChangeExt.class)) {
			EPPChangeExt ext = (EPPChangeExt) theCommand.getExtension(EPPChangeExt.class);
			requestId = ext.getRequestId();
		}
		else {
			cat.error("doDomainDelete: EPPChangeExt missing");

			EPPResult theResult = new EPPResult(EPPResult.PARAM_VALUE_POLICY_ERROR,
			      "Change Extension is required on delete");
			EPPResponse theResponse = new EPPResponse(transId, theResult);

			return new EPPEventResponse(theResponse);
		}

		/**
		 * LOGIC: Simulate adding Change Action
		 */
		EPPChangeAction theAction = new EPPChangeAction(requestId, theCommand.getTransId(), svrTransId);
		theAction.setDefinition(theCommand.toString());
		RootZoneManager.addChangeAction(requestId, theAction);

		EPPResponse theResponse = new EPPResponse(transId);
		theResponse.setResult(EPPResult.SUCCESS);
		return new EPPEventResponse(theResponse);
	}

	/**
	 * Invoked when a Domain command is received in the RZMS. A Change Action is
	 * constructed from the incoming message and passed to the server to be
	 * associated with the specified Change Request.
	 * 
	 * @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.
	 */
	protected EPPEventResponse doDomainUpdate(EPPEvent aEvent, Object aData) {
		String requestId = null;

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

		cat.debug("doDomainUpdate: command = [" + theCommand + "]");

		EPPTransId transId = new EPPTransId(theCommand.getTransId(), svrTransId);

		if (theCommand.getTransId() == null) {
			cat.error("doDomainUpdate: Client transaction identifier is missing");

			EPPResult theResult = new EPPResult(EPPResult.PARAM_VALUE_POLICY_ERROR,
			      "Client transaction identifier is required on update");
			EPPResponse theResponse = new EPPResponse(transId, theResult);

			return new EPPEventResponse(theResponse);
		}

		if (theCommand.hasExtension(EPPChangeExt.class)) {
			EPPChangeExt ext = (EPPChangeExt) theCommand.getExtension(EPPChangeExt.class);
			requestId = ext.getRequestId();
		}
		else {
			cat.error("doDomainUpdate: EPPChangeExt missing");

			EPPResult theResult = new EPPResult(EPPResult.PARAM_VALUE_POLICY_ERROR,
			      "Change Extension is required on update");
			EPPResponse theResponse = new EPPResponse(transId, theResult);

			return new EPPEventResponse(theResponse);
		}

		/**
		 * LOGIC: Simulate adding Change Action
		 */
		EPPChangeAction theAction = new EPPChangeAction(requestId, theCommand.getTransId(), svrTransId);
		theAction.setDefinition(theCommand.toString());
		RootZoneManager.addChangeAction(requestId, theAction);

		EPPResponse theResponse = new EPPResponse(transId);
		theResponse.setResult(EPPResult.SUCCESS);
		return new EPPEventResponse(theResponse);
	}

	/**
	 * Handle a renew command by returning an error, since the Root Zone does not
	 * support the domain renew command.
	 * 
	 * @param aEvent
	 *           Domain command event
	 * @param aData
	 *           Server session data
	 */
	protected EPPEventResponse doDomainRenew(EPPEvent aEvent, Object aData) {
		return unsupportedCommandResult(aEvent, aData);
	}

	/**
	 * Handle a transfer command by returning an error, since the Root Zone does
	 * not support the domain transfer command.
	 * 
	 * @param aEvent
	 *           Domain command event
	 * @param aData
	 *           Server session data
	 */
	protected EPPEventResponse doDomainTransfer(EPPEvent aEvent, Object aData) {
		return unsupportedCommandResult(aEvent, aData);
	}

}
