/***********************************************************
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.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.Vector;

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

import com.verisign.epp.codec.domain.EPPDomainCheckCmd;
import com.verisign.epp.codec.domain.EPPDomainCheckResp;
import com.verisign.epp.codec.domain.EPPDomainCheckResult;
import com.verisign.epp.codec.domain.EPPDomainContact;
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.EPPDomainInfoCmd;
import com.verisign.epp.codec.domain.EPPDomainInfoResp;
import com.verisign.epp.codec.domain.EPPDomainMapFactory;
import com.verisign.epp.codec.domain.EPPDomainPendActionMsg;
import com.verisign.epp.codec.domain.EPPDomainRenewCmd;
import com.verisign.epp.codec.domain.EPPDomainRenewResp;
import com.verisign.epp.codec.domain.EPPDomainStatus;
import com.verisign.epp.codec.domain.EPPDomainTransferCmd;
import com.verisign.epp.codec.domain.EPPDomainTransferResp;
import com.verisign.epp.codec.domain.EPPDomainUpdateCmd;
import com.verisign.epp.codec.gen.EPPAuthInfo;
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.EPPDomainHandler;
import com.verisign.epp.framework.EPPEvent;
import com.verisign.epp.framework.EPPEventResponse;
import com.verisign.epp.framework.EPPHandleEventException;
import com.verisign.epp.framework.EPPPollQueueException;
import com.verisign.epp.framework.EPPPollQueueMgr;

/**
 * The <code>DomainHandler</code> class is a concrete implementation of the
 * abstract <code>com.verisign.epp.framework.EPPDomainHandler</code> class. It
 * defines the Server's response to all received EPP Host Commands. <br>
 * <br>
 *
 * @author $Author: jim $
 *
 * @see com.verisign.epp.framework.EPPEvent
 * @see com.verisign.epp.framework.EPPEventResponse
 */
public class DomainHandler extends EPPDomainHandler {
  private static final String svrTransId = "54322-XYZ";

  private static final String roid = "NS1EXAMPLE1-VRSN";

  private static Logger cat = LoggerFactory.getLogger(DomainHandler.class);

  /**
   * Constructs an instance of DomainHandler
   */
  public DomainHandler() {
  }

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

    if (!sessionData.isLoggedIn()) {
      /**
       * The client isn't logged in so they can't successfully invoke a
       * command. Sending COMMAND_FAILED_END
       */
      /**
       * 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_FAILED_END);
      throw new EPPHandleEventException("The client has not established a session", theResponse);
    }
  }

  /**
   * Handles any common behavior that all Domain commands need to execute after
   * they execute their command specific behavior.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomainHandler</code>
   *
   * @exception EPPHandleEventException
   *               Thrown if an error condition occurs. It must contain an
   *               <code>EPPEventResponse</code>
   */
  protected void postHandleEvent(EPPEvent aEvent, Object aData) throws EPPHandleEventException {
  }

  /**
   * Invoked when a Domain Check command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainCheck(EPPEvent aEvent, Object aData) {
    EPPDomainCheckCmd theMessage = (EPPDomainCheckCmd) aEvent.getMessage();
    EPPResponse theResponse;

    // This is just a vector of strings representing Domain Names
    Vector<String> vNames = theMessage.getNames();
    Enumeration<String> eNames = vNames.elements();

    Vector<EPPDomainCheckResult> vResults = new Vector<EPPDomainCheckResult>();

    // create a Vector of Ping Results.
    boolean known = true;

    while (eNames.hasMoreElements()) {
      String domainName = eNames.nextElement();
      known = !known;
      vResults.addElement(new EPPDomainCheckResult(domainName, known));
    }

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

    // Response for many domain names
    theResponse = new EPPDomainCheckResp(transId, vResults);
    theResponse.setResult(EPPResult.SUCCESS);

    return new EPPEventResponse(theResponse);
  }

  /**
   * Invoked when a Domain Renew command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainRenew(EPPEvent aEvent, Object aData) {
    EPPDomainRenewCmd theMessage = (EPPDomainRenewCmd) aEvent.getMessage();
    EPPResponse theResponse;

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

    // Test with transId, domain name, roid, and expiration date
    theResponse = new EPPDomainRenewResp(transId, theMessage.getName(), new Date());

    theResponse.setResult(EPPResult.SUCCESS);

    return new EPPEventResponse(theResponse);
  }

  /**
   * Invoked when a Domain Delete command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainDelete(EPPEvent aEvent, Object aData) {
    EPPDomainDeleteCmd theMessage = (EPPDomainDeleteCmd) aEvent.getMessage();

    // Test with transId, domain name, and expiration date

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

    // Create Delete Response (Standard EPPResponse)
    EPPResponse theResponse = new EPPResponse(transId);
    theResponse.setResult(EPPResult.SUCCESS);

    return new EPPEventResponse(theResponse);
  }

  /**
   * Invoked when a Domain Create command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainCreate(EPPEvent aEvent, Object aData) {
    EPPDomainCreateCmd theMessage = (EPPDomainCreateCmd) aEvent.getMessage();

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

    // Calculate expiration date
    GregorianCalendar theExtDate = new GregorianCalendar();
    theExtDate.setTime(new Date());
    theExtDate.add(Calendar.YEAR, theMessage.getPeriod().getPeriod());

    EPPResponse theResponse = new EPPDomainCreateResp(transId, theMessage.getName(), new Date(),
          theExtDate.getTime());

    if (theMessage.getName().equals("pending.com") || theMessage.getName().equals("pending-approve.com")
          || theMessage.getName().equals("pending-denied.com")) {

      boolean thePAResult = false;

      if (theMessage.getName().equals("pending.com") || theMessage.getName().equals("pending-approve.com")) {
        thePAResult = true;
      }
      else { // theMessage.getName().equals("pending-denied.com")
        thePAResult = false;
      }

      EPPTransId pendingTransId = new EPPTransId(theMessage.getTransId(), svrTransId);
      EPPDomainPendActionMsg thePollMsg = new EPPDomainPendActionMsg(transId, theMessage.getName(), thePAResult,
            pendingTransId, new Date());

      try {
        EPPPollQueueMgr.getInstance().put(null, EPPDomainMapFactory.NS, thePollMsg, null);
      }
      catch (EPPPollQueueException ex) {
        cat.error("doDomainCreate: Error putting message [" + thePollMsg + "]");

        EPPResult theResult = new EPPResult(EPPResult.COMMAND_FAILED);
        theResponse = new EPPResponse(transId, theResult);

        return new EPPEventResponse(theResponse);
      }

      theResponse.setResult(EPPResult.SUCCESS_PENDING);
    }
    else {
      theResponse.setResult(EPPResult.SUCCESS);
    }

    return new EPPEventResponse(theResponse);
  }

  /**
   * Invoked when a Domain Transfer command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainTransfer(EPPEvent aEvent, Object aData) {
    EPPDomainTransferCmd theMessage = (EPPDomainTransferCmd) aEvent.getMessage();

    int theResultCode = EPPResult.SUCCESS;

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);
    EPPDomainTransferResp theResponse = new EPPDomainTransferResp(transId, theMessage.getName());
    theResponse.setRequestClient("ClientX");
    theResponse.setRequestDate(new Date());

    theResponse.setActionClient("ClientY");
    theResponse.setActionDate(new Date());

    // Is a transfer request?
    if (theMessage.getOp().equals(EPPCommand.OP_QUERY)) {
      // Calculate expiration date
      GregorianCalendar theExtDate = new GregorianCalendar();
      theExtDate.setTime(new Date());
      theExtDate.add(Calendar.YEAR, 1);
      theResponse.setTransferStatus(EPPResponse.TRANSFER_PENDING);
      theResponse.setResult(EPPResult.SUCCESS);
    }
    if (theMessage.getOp().equals(EPPCommand.OP_REQUEST)) {
      // Calculate expiration date
      GregorianCalendar theExtDate = new GregorianCalendar();
      theExtDate.setTime(new Date());
      theExtDate.add(Calendar.YEAR, theMessage.getPeriod().getPeriod());
      theResponse.setExpirationDate(theExtDate.getTime());
      theResponse.setTransferStatus(EPPResponse.TRANSFER_PENDING);
      theResponse.setResult(EPPResult.SUCCESS_PENDING);

      // Insert transfer response in poll queue
      try {
        EPPPollQueueMgr.getInstance().put(null, EPPDomainMapFactory.NS, theResponse, null);
      }
      catch (EPPPollQueueException ex) {
        cat.error("doDomainTransfer: Error putting message [" + theResponse + "]");

        EPPResult theResult = new EPPResult(EPPResult.COMMAND_FAILED);
        EPPResponse theErrorResponse = new EPPResponse(transId, theResult);

        return new EPPEventResponse(theErrorResponse);
      }
    } // Transfer Approve?
    else if (theMessage.getOp().equals(EPPCommand.OP_APPROVE)) {
      // Calculate expiration date
      GregorianCalendar theExtDate = new GregorianCalendar();
      theExtDate.setTime(new Date());
      theExtDate.add(Calendar.YEAR, 1);
      theResponse.setTransferStatus(EPPResponse.TRANSFER_CLIENT_APPROVED);
      theResponse.setResult(EPPResult.SUCCESS);
    } // Transfer Cancel?
    else if (theMessage.getOp().equals(EPPCommand.OP_CANCEL)) {
      // Calculate expiration date
      GregorianCalendar theExtDate = new GregorianCalendar();
      theExtDate.setTime(new Date());
      theExtDate.add(Calendar.YEAR, 1);
      theResponse.setTransferStatus(EPPResponse.TRANSFER_CLIENT_CANCELLED);
      theResponse.setResult(EPPResult.SUCCESS);
    } // Transfer Reject
    else if (theMessage.getOp().equals(EPPCommand.OP_REJECT)) {
      // Calculate expiration date
      GregorianCalendar theExtDate = new GregorianCalendar();
      theExtDate.setTime(new Date());
      theExtDate.add(Calendar.YEAR, 1);
      theResponse.setTransferStatus(EPPResponse.TRANSFER_CLIENT_REJECTED);
      theResponse.setResult(EPPResult.SUCCESS);
    }

    return new EPPEventResponse(theResponse);
  }

  /**
   * Invoked when a Domain Update command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainUpdate(EPPEvent aEvent, Object aData) {
    EPPDomainUpdateCmd theMessage = (EPPDomainUpdateCmd) aEvent.getMessage();

    // Create Update Response (Standard EPPResponse)

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

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

    return new EPPEventResponse(theResponse);
  }

  /**
   * Invoked when a Domain Info command is received.
   *
   * @param aEvent
   *           The <code>EPPEvent</code> that is being handled
   * @param aData
   *           Any data that a Server needs to send to this
   *           <code>EPPDomaindHandler</code>
   *
   * @return EPPEventResponse The response that should be sent back to the
   *         client.
   */
  protected EPPEventResponse doDomainInfo(EPPEvent aEvent, Object aData) {
    EPPDomainInfoCmd theMessage = (EPPDomainInfoCmd) aEvent.getMessage();

    // EPPDomainInfo Response requires a vector of status
    Vector<EPPDomainStatus> statuses = new Vector<EPPDomainStatus>();
    statuses.addElement(new EPPDomainStatus(EPPDomainStatus.ELM_STATUS_OK));
    statuses.addElement(new EPPDomainStatus(EPPDomainStatus.ELM_STATUS_CLIENT_HOLD));

    /**
     * Create the transId for the response with the client trans id and the
     * server trans id.
     */
    EPPTransId transId = new EPPTransId(theMessage.getTransId(), svrTransId);

    // Required EPPDomainInfoResp attributes.
    // trans id, domain name, roid, client id, statuses, created by id,
    // expiration date, Auth Info
    EPPDomainInfoResp theResponse = new EPPDomainInfoResp(transId, roid, theMessage.getName(), "ClientX", statuses,
          "ClientY", new Date(), new EPPAuthInfo("2fooBAR"));

    // Add Name Servers
    Vector<String> theNses = new Vector<String>();
    theNses.addElement("ns1.example.com");
    theNses.addElement("ns2.example.com");
    theResponse.setNses(theNses);

    // Add Subordinate Hosts
    Vector<String> theHosts = new Vector<String>();
    theHosts.addElement("ns1.example.com");
    theHosts.addElement("ns2.example.com");
    theResponse.setHosts(theHosts);

    // Add Contacts
    Vector<EPPDomainContact> theContacts = new Vector<EPPDomainContact>();
    theContacts.addElement(new EPPDomainContact("sh8013", EPPDomainContact.TYPE_ADMINISTRATIVE));
    theContacts.addElement(new EPPDomainContact("sh8013", EPPDomainContact.TYPE_BILLING));
    theContacts.addElement(new EPPDomainContact("sh8013", EPPDomainContact.TYPE_TECHNICAL));
    theResponse.setContacts(theContacts);

    // Set the expiration date to today plus one year
    GregorianCalendar theCal = new GregorianCalendar();
    theCal.setTime(new Date());
    theCal.add(Calendar.YEAR, 1);

    theResponse.setExpirationDate(theCal.getTime());

    // Set the Registrant
    theResponse.setRegistrant("jd1234");

    theResponse.setResult(EPPResult.SUCCESS);

    return new EPPEventResponse(theResponse);
  }
}
