/***********************************************************
 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-0107  USA

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

import java.util.ArrayList;
import java.util.Iterator;

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

import com.verisign.epp.codec.change.EPPChangeCheckCmd;
import com.verisign.epp.codec.change.EPPChangeCheckResp;
import com.verisign.epp.codec.change.EPPChangeCreateCmd;
import com.verisign.epp.codec.change.EPPChangeDeleteCmd;
import com.verisign.epp.codec.change.EPPChangeInfoCmd;
import com.verisign.epp.codec.change.EPPChangeUpdateCmd;
import com.verisign.epp.codec.change.type.EPPChangeRequest;
import com.verisign.epp.codec.change.util.RandomHelper;
import com.verisign.epp.codec.gen.EPPCodecException;
import com.verisign.epp.codec.gen.EPPCommand;
import com.verisign.epp.codec.gen.EPPFactory;
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.codec.idnext.EPPIdnExtFactory;
import com.verisign.epp.codec.loginsec.v1_0.EPPLoginSecExtFactory;
import com.verisign.epp.framework.EPPChangeHandler;
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;

/**
 * Handler that simulates a persistent Change Handler by using the
 * {@link RootZoneManager}. This handler is not used for the client server test,
 * since the client tests simply exercise the interface and doesn't work with a
 * persistent handler. Use {@link com.verisign.epp.serverstub.ChangeHandler} for
 * the client server tests and this handler when manually testing the behavior
 * of the server.
 */
public class RZChangeHandler extends EPPChangeHandler {

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

	/**
	 * The server transaction id used for all responses
	 */
	private static final String svrTransId = "SRV-thx1138";

	/**
	 * Constructs an instance of RZChangeHandler
	 */
	public RZChangeHandler() {
		// Add the additional extension factories
		try {
			EPPFactory.getInstance().addExtFactory(EPPLoginSecExtFactory.class.getName());
		}
		catch (EPPCodecException e) {
			cat.error("Couldn't load the Ext Factory for the Login Security Extension", e);
			System.exit(1);
		}

		try {
			EPPFactory.getInstance().addExtFactory(EPPIdnExtFactory.class.getName());
		}
		catch (EPPCodecException e) {
			cat.error("Couldn't load the Ext Factory for the IDN Extension", e);
			System.exit(1);
		}
	}

	/**
	 * Handles any common behavior that all Change 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 EPPChangeHandler} 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()) {
			/**
			 * Create the transId for the response with the client trans id and the
			 * server trans id.
			 */
			EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

			// Create the Response (Standard EPPResponse)
			EPPResponse theResponse = new EPPResponse(transId);

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

	/**
	 * Handles any common behavior that all Change commands need to execute after
	 * 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 EPPChangeHandler}
	 * @exception EPPHandleEventException
	 *               Thrown if an error condition occurs. It must contain an
	 *               {@code EPPEventResponse}
	 */
	protected void postHandleEvent(EPPEvent aEvent, Object aData) throws EPPHandleEventException {
	}

	/**
	 * Invoked when a Change Info command is received.
	 * 
	 * @param aEvent
	 *           The {@code EPPEvent} that is being handled
	 * @param aData
	 *           Any data that a Server needs to send to this
	 *           {@code EPPChangedHandler}
	 * @return EPPEventResponse The response that should be sent back to the
	 *         client.
	 */
	protected EPPEventResponse doChangeCheck(EPPEvent aEvent, Object aData) {
		EPPChangeCheckCmd cmd = (EPPChangeCheckCmd) aEvent.getMessage();

		cat.debug("doChangeCheck: command = [" + cmd + "]");

		String cltrid = cmd.getTransId();

		EPPTransId aTransId = new EPPTransId(cltrid, svrTransId);
		EPPChangeCheckResp resp = new EPPChangeCheckResp(aTransId);

		/**
		 * LOGIC: Simulate Root Zone Management System
		 */
		ArrayList list = cmd.getRequestIds();
		Iterator i = list.iterator();
		while (i.hasNext()) {
			resp.addCheckData(RootZoneManager.checkChangeRequest((String) i.next()));
		}
		resp.setResult(EPPResult.SUCCESS);

		return new EPPEventResponse(resp);
	}

	protected EPPEventResponse doChangeInfo(EPPEvent aEvent, Object aData) {
		EPPChangeInfoCmd cmd = (EPPChangeInfoCmd) aEvent.getMessage();

		cat.debug("doChangeInfo: command = [" + cmd + "]");

		String cltrid = cmd.getTransId();
		EPPTransId aTransId = new EPPTransId(cltrid, svrTransId);
		EPPResponse response = null;

		/**
		 * LOGIC: Simulate Root Zone Management System
		 */
		EPPChangeRequest request = RootZoneManager.findChangeRequest(cmd.getRequestId());

		if (request != null) {
			response = request.getInfoResponse();
			response.setResult(EPPResult.SUCCESS);
		}
		else {
			response = new EPPResponse();
			response.setResult(EPPResult.OBJECT_DOES_NOT_EXIST);
		}
		response.setTransId(aTransId);
		return new EPPEventResponse(response);

	}

	protected EPPEventResponse doChangeCreate(EPPEvent aEvent, Object aData) {
		EPPChangeCreateCmd cmd = (EPPChangeCreateCmd) aEvent.getMessage();

		cat.debug("doChangeCreate: command = [" + cmd + "]");

		String cltrid = cmd.getTransId();

		/**
		 * LOGIC: Simulate Root Zone Management System
		 */
		EPPChangeRequest request = new EPPChangeRequest(cmd);
		RootZoneManager.addChangeRequest(request);

		EPPResponse resp = RandomHelper.getEppResponse(cltrid);
		resp.setResult(EPPResult.SUCCESS);

		return new EPPEventResponse(resp);
	}

	protected EPPEventResponse doChangeUpdate(EPPEvent aEvent, Object aData) {
		EPPChangeUpdateCmd cmd = (EPPChangeUpdateCmd) aEvent.getMessage();

		cat.debug("doChangeUpdate: command = [" + cmd + "]");

		String cltrid = cmd.getTransId();

		/**
		 * LOGIC: Simulate Root Zone Management System
		 */
		String requestId = cmd.getRequestId();
		EPPResponse resp = null;
		if (cmd.isClear()) {
			RootZoneManager.clearChangeRequest(requestId);
			resp = RandomHelper.getChangeUpdateEmptyResp(cltrid);
		}
		else if (cmd.isSubmit()) {
			RootZoneManager.submitChangeRequest(requestId);
			resp = RandomHelper.getChangeUpdateSubmitResp(cltrid);
		}
		else if (cmd.isWithdraw()) {
			RootZoneManager.withdrawChangeRequest(requestId);
			resp = RandomHelper.getChangeUpdateEmptyResp(cltrid);
		}
		else {
			RootZoneManager.updateChangeRequest(requestId, cmd.getAttributes());
			resp = RandomHelper.getChangeUpdateEmptyResp(cltrid);
		}

		resp.setResult(EPPResult.SUCCESS);

		return new EPPEventResponse(resp);
	}

	protected EPPEventResponse doChangeDelete(EPPEvent aEvent, Object aData) {
		EPPChangeDeleteCmd cmd = (EPPChangeDeleteCmd) aEvent.getMessage();

		cat.debug("EPPChangeDeleteCmd: command = [" + cmd + "]");

		String cltrid = cmd.getTransId();

		/**
		 * LOGIC: Simulate Root Zone Management System
		 */
		RootZoneManager.deleteChangeRequest(cmd.getRequestId());

		EPPResponse resp = RandomHelper.getEppResponse(cltrid);
		resp.setResult(EPPResult.SUCCESS);

		return new EPPEventResponse(resp);
	}
}
