/***********************************************************
 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.interfaces;

import java.util.List;
import java.util.Vector;

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.EPPChangeInfoResp;
import com.verisign.epp.codec.change.EPPChangeUpdateCmd;
import com.verisign.epp.codec.change.EPPChangeUpdateResp;
import com.verisign.epp.codec.change.type.EPPChangeUpdateAttributes;
import com.verisign.epp.codec.gen.EPPCodecComponent;
import com.verisign.epp.codec.gen.EPPCommand;
import com.verisign.epp.codec.gen.EPPResponse;

/**
 * <code>EPPChange</code> is the primary client interface class used for
 * Change management. An instance of <code>EPPChange</code> is created with an
 * initialized <code>EPPSession</code>, and can be used for more than one
 * request within a single thread. A setter method is provided to set the
 * extensions before a call to one of the send action methods. The responses
 * returned from the send action methods are either instances of
 * <code>EPPResponse</code> or instances of response classes in the
 * <code>com.verisign.epp.codec.change</code> package. <br>
 * <br>
 * @author $Author: jim $
 * @version $Revision: 1.2 $
 * @see com.verisign.epp.codec.gen.EPPResponse
 * @see com.verisign.epp.codec.change.EPPChangeInfoResp
 * @see com.verisign.epp.codec.change.EPPChangeCheckResp
 */
public class EPPChange {

  static private void unexpectedResponseType(EPPResponse response, String expected)
      throws EPPCommandException {
    throw new EPPCommandException("Unexpected response type of "
        + response.getClass().getName() + ", expecting " + expected);
  }

  /**
   * Extension objects associated with the command. This is a
   * <code>Vector</code> of <code>EPPCodecComponent</code> objects.
   */
  private Vector extensions = null;

  /** Response of the last operation. */
  private EPPResponse response = null;

  /** An instance of a session. */
  private EPPSession session = null;

  private EPPCommand lastCommand = null;

  /**
   * Constructs an <code>EPPChange</code> given an initialized EPP session.
   * @param newSession Server session to use.
   */
  public EPPChange(EPPSession newSession) {
    session = newSession;
    return;
  }

  /**
   * Adds a command extension object.
   * @param aExtension command extension object associated with the command
   */
  public void addExtension(EPPCodecComponent aExtension) {
    if (aExtension != null) {
      if (this.extensions == null) this.extensions = new Vector();
      this.extensions.addElement(aExtension);
    }
  }

  /**
   * Gets the command extensions.
   * @return <code>Vector</code> of concrete <code>EPPCodecComponent</code>
   *         associated with the command if exists; <code>null</code>
   *         otherwise.
   */
  public Vector getExtensions() {
    return this.extensions;
  }

  public EPPCommand getLastCommand() {
    return lastCommand;
  }

  /**
   * Get the <code>EPPResponse</code> associated with the last command. This
   * method can be used to retrieve the server error response in the catch
   * block of EPPCommandException.
   * @return <code>EPPResponse</code> associated with the last command
   */
  public EPPResponse getResponse() {
    return response;
  }

  /**
   * Retrieve the <code>EPPSession</code> associated with this EPPChange.
   * @return <code>EPPSession</code>
   */
  public EPPSession getSession() {
    return session;
  }

  public EPPChangeCheckResp sendCheck(String requestId) throws EPPCommandException {
    return sendCheck(null, requestId);
  }

  public EPPChangeCheckResp sendCheck(String clTrid, String requestId)
      throws EPPCommandException {
    EPPCommand command = new EPPChangeCheckCmd(clTrid, requestId);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    if (!(response instanceof EPPChangeCheckResp)) {
      unexpectedResponseType(response, EPPChangeCheckResp.class.getName());
    }
    clearExtensions();
    return (EPPChangeCheckResp) response;
  }

  public EPPResponse sendCreate(String requestId, String priority, String category,
      String description) throws EPPCommandException {
    return sendCreate(null, requestId, priority, category, description);
  }

  public EPPResponse sendCreate(String requestId, String category, String description)
      throws EPPCommandException {
    return sendCreate(null, requestId, null, category, description);
  }

  public EPPResponse sendCreate(String clTrid, String requestId, String priority,
      String category, String description) throws EPPCommandException {
    /** Creating with priority */
    EPPCommand command = new EPPChangeCreateCmd(clTrid, requestId, priority,
        category, description);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    clearExtensions();
    return response;
  }

  public EPPResponse sendCreate(String clTrid, String requestId, String priority,
      List categories, String description) throws EPPCommandException {
    EPPCommand command = new EPPChangeCreateCmd(clTrid, requestId, priority,
        categories, description);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    clearExtensions();
    return response;
  }

  public EPPResponse sendDelete(String requestId) throws EPPCommandException {
    return sendDelete(null, requestId);
  }

  public EPPResponse sendDelete(String clTrid, String requestId)
      throws EPPCommandException {
    EPPCommand command = new EPPChangeDeleteCmd(clTrid, requestId);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    clearExtensions();
    return response;
  }

  public EPPChangeInfoResp sendInfo(String requestId) throws EPPCommandException {
    return sendInfo(null, requestId);
  }

  public EPPChangeInfoResp sendInfo(String clTrid, String requestId)
      throws EPPCommandException {
    EPPCommand command = new EPPChangeInfoCmd(clTrid, requestId);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    if (!(response instanceof EPPChangeInfoResp)) {
      unexpectedResponseType(response, EPPChangeInfoResp.class.getName());
    }
    clearExtensions();
    return (EPPChangeInfoResp) response;
  }

  public EPPChangeUpdateResp sendUpdateAttrs(String requestId, String priority,
      String category, String description) throws EPPCommandException {
    return sendUpdateAttrs(null, requestId, priority, category, description);
  }

  public EPPChangeUpdateResp sendUpdateAttrs(String clTrid, String requestId,
      String priority, String category, String description)
      throws EPPCommandException {
    EPPChangeUpdateCmd command = new EPPChangeUpdateCmd(clTrid, requestId);
    /** Updating the priority */
    command.setAttributes(new EPPChangeUpdateAttributes(priority, category,
        description));
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    if (!(response instanceof EPPChangeUpdateResp)) {
      unexpectedResponseType(response, EPPChangeUpdateResp.class.getName());
    }
    clearExtensions();
    return (EPPChangeUpdateResp) response;
  }

  public EPPChangeUpdateResp sendUpdateClear(String requestId)
      throws EPPCommandException {
    return sendUpdateClear(null, requestId);
  }

  public EPPChangeUpdateResp sendUpdateClear(String clTrid, String requestId)
      throws EPPCommandException {
    EPPChangeUpdateCmd command = new EPPChangeUpdateCmd(clTrid, requestId);
    command.setClear(true);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    if (!(response instanceof EPPChangeUpdateResp)) {
      unexpectedResponseType(response, EPPChangeUpdateResp.class.getName());
    }
    clearExtensions();
    return (EPPChangeUpdateResp) response;
  }

  public EPPChangeUpdateResp sendUpdateSubmit(String requestId)
      throws EPPCommandException {
    return sendUpdateSubmit(null, requestId);
  }

  public EPPChangeUpdateResp sendUpdateSubmit(String clTrid, String requestId)
      throws EPPCommandException {
    EPPChangeUpdateCmd command = new EPPChangeUpdateCmd(clTrid, requestId);
    command.setSubmit(true);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    if (!(response instanceof EPPChangeUpdateResp)) {
      unexpectedResponseType(response, EPPChangeUpdateResp.class.getName());
    }
    clearExtensions();
    return (EPPChangeUpdateResp) response;
  }
  
  public EPPResponse sendUpdateWithdraw(String requestId) throws EPPCommandException {
    return sendUpdateWithdraw(null, requestId);
  }

  public EPPChangeUpdateResp sendUpdateWithdraw(String clTrid, String requestId)
      throws EPPCommandException {
    EPPChangeUpdateCmd command = new EPPChangeUpdateCmd(clTrid, requestId);
    command.setWithdraw(true);
    command.setExtensions(this.extensions);
    setLastCommand(command);
    response = session.processDocument(command);
    if (!(response instanceof EPPChangeUpdateResp)) {
      unexpectedResponseType(response, EPPChangeUpdateResp.class.getName());
    }
    clearExtensions();
    return (EPPChangeUpdateResp) response;
  }

  public void setExtensions(Vector aExtensions) {
    this.extensions = aExtensions;
  }

  public void setLastCommand(EPPCommand command) {
    this.lastCommand = command;
  }

  public void setSession(EPPSession aSession) {
    this.session = aSession;
  }

  /**
   * Reset the Change instance to its initial state.
   */
  private void clearExtensions() {
    extensions = null;
  }

}
