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

import org.w3c.dom.Document;
//----------------------------------------------
//
// imports...
//
//----------------------------------------------
// W3C Imports
import org.w3c.dom.Element;

// EPP Imports
import com.verisign.epp.codec.gen.EPPAuthInfo;
import com.verisign.epp.codec.gen.EPPCodecException;
import com.verisign.epp.codec.gen.EPPCommand;
import com.verisign.epp.codec.gen.EPPDecodeException;
import com.verisign.epp.codec.gen.EPPEncodeException;
import com.verisign.epp.codec.gen.EPPTransferCmd;
import com.verisign.epp.codec.gen.EPPUtil;


/**
 * Represents an EPP DefReg {@code <transfer>} command, which
 * provides either a query operation that allows a client to determine
 * real-time status of pending and completed transfer requests, or a transform operation that allows
 * a client to manage requests to transfer the sponsorship of a defReg object.  In addition
 * to the standard EPP
 * command elements, the {@code <transfer>} command MUST contain a
 * {@code <defReg:transfer>} element that identifies the defReg namespace.
 * The {@code <defReg:transfer>} element
 * contains the following child elements:
 * 
 * <ul>
 * <li>
 * A {@code <defReg:roid>} element that contains  that contains the repository object identifier
 * assigned to the defReg object when the object was created.
 * </li>
 * <li>
 * A {@code <defReg:period} element that contains the number of units to be added to the
 * registration period of the defReg object at completion of the transfer process. This element
 * is only applicable in a transform command where the "op" attribute of the EPP {@code <transfer>}
 * command is set to "request".
 * </li>
 * <li>
 * An OPTIONAL {@code <defReg:authInfo>} element that contains authorization information
 * associated with the defReg object or authorization information associated
 * with the defReg object's registrant or associated contacts. An OPTIONAL "roid" attribute
 * MUST be used to identify the registrant or contact object if and only if the given authInfo
 * is associated with a registrant or contact object and not the defReg itself. If this element
 * is not provided or if the authorization information is invalid, server policy determines if
 * the command is rejected or if response information will be returned to the client.
 * </li>
 * </ul>
 *
 * @see com.verisign.epp.codec.defReg.EPPDefRegTransferResp
 */
public class EPPDefRegTransferCmd extends EPPTransferCmd {
  /** XML Element Name of <code>EPPDefRegTransferCmd</code> root element. */
  final static String ELM_NAME = "defReg:transfer";

  /** DefReg roid of defReg to query. */
  private final static String ELM_DEFREG_ROID = "defReg:roid";

  /** XML Element Name of <code>period</code> root element. */
  private final static String ELM_DEFREG_PERIOD = "defReg:period";

  /** DefReg Roid of defReg to update. */
  private String roid = null;

  /** Registration Period */
  private EPPDefRegPeriod period = null;

  /** Authorization information. */
  private EPPAuthInfo authInfo = null;

  /**
   * Allocates a new <code>EPPDefRegTransferCmd</code> with default attribute
   * values.     the defaults include the following:     <br><br>
   * 
   * <ul>
   * <li>
   * roid is set to <code>null</code>
   * </li>
   * <li>
   * period is set to <code>null</code>
   * </li>
   * <li>
   * authInfo  is set to to <code>null</code>
   * </li>
   * </ul>
   * 
   * <br>     The transaction ID, operation, name, and authInfo must be set
   * before invoking <code>encode</code>.
   */
  public EPPDefRegTransferCmd() {
    roid     = null;
    period     = null;
    authInfo     = null;
  }

  /**
   * <code>EPPDefRegTransferCmd</code> constructor that takes the required
   * attributes as arguments.  The     period attribute is set to
   * <code>UNSPEC_PERIOD</code> and will not be included when
   * <code>encode</code> is invoked.
   *
   * @param aTransId Transaction Id associated with the command.
   * @param aOp One of the <code>EPPCommand.OP_</code> constants associated
   *      with the transfer command.
   * @param aRoid DefReg roid to create.
   */
  public EPPDefRegTransferCmd(String aTransId, String aOp, String aRoid) {
    super(aTransId, aOp);

    roid     = aRoid;
    authInfo     = null;
    period     = null;
  }

  /**
   * <code>EPPDefRegTransferCmd</code> constructor that takes the required
   * attributes plus the     optional attibute <code>aPeriod</code>.
   *
   * @param aTransId Transaction Id associated with the command.
   * @param aOp One of the <code>EPPCommand.OP_</code> constants associated
   *      with the transfer command.
   * @param aRoid DefReg roid to create.
   * @param aAuthInfo Authorization Information for operating with the
   *      defReg.
   * @param aPeriod Registration period to be added to the defReg upon
   *      transfer.
   */
  public EPPDefRegTransferCmd(
                String aTransId, String aOp, String aRoid,
                EPPAuthInfo aAuthInfo, EPPDefRegPeriod aPeriod) {
    super(aTransId, aOp);

    roid     = aRoid;
    period     = aPeriod;
    setAuthInfo(aAuthInfo);
  }

  /**
   * Gets the EPP command Namespace associated with
   * <code>EPPDefRegTransferCmd</code>.
   *
   * @return <code>EPPDefRegMapFactory.NS</code>
   */
  public String getNamespace() {
    return EPPDefRegMapFactory.NS;
  }

  /**
   * Gets the key for the defensive registration object, which is the defensive registration ROID.
   * 
   * @return The defensive registration ROID if set; {@code null} otherwise.
   */
  @Override
  public String getKey() {
	  return this.getRoid();
  }

  /**
   * Get authorization information
   *
   * @return EPPAuthInfo
   */
  public EPPAuthInfo getAuthInfo() {
    return authInfo;
  }

  // End EPPDefRegTransferCmd.getAuthInfo()

  /**
   * Set authorization information
   *
   * @param newAuthInfo java.lang.String
   */
  public void setAuthInfo(EPPAuthInfo newAuthInfo) {
    if (newAuthInfo != null) {
      authInfo = newAuthInfo;
      authInfo.setRootName(EPPDefRegMapFactory.NS, EPPDefRegMapFactory.ELM_DEFREG_AUTHINFO);
    }
  }

  /**
   * Validate the state of the <code>EPPDefRegTransferCmd</code> instance.  A
   * valid state means that all of the required attributes have been set. If
   * validateState     returns without an exception, the state is valid. If
   * the state is not     valid, the EPPCodecException will contain a
   * description of the error.     throws     EPPCodecException    State
   * error.  This will contain the name of the     attribute that is not
   * valid.
   *
   * @throws EPPCodecException DOCUMENT ME!
   * @throws EPPEncodeException DOCUMENT ME!
   */
  void validateState() throws EPPCodecException {
    if (super.getOp() == null) {
      throw new EPPCodecException("op required attribute is not set");
    }

    if (roid == null) {
      throw new EPPEncodeException("roid required attribute is not set");
    }

    if (super.getOp().equals(EPPCommand.OP_REQUEST) && (authInfo == null)) {
      throw new EPPCodecException("authInfo required attribute is not set");
    }
  }

  /**
   * Encode a DOM Element tree from the attributes of the
   * <code>EPPDefRegTransferCmd</code> instance.
   *
   * @param aDocument DOM Document that is being built.  Used as an Element
   *      factory.
   *
   * @return Root DOM Element representing the
   *       <code>EPPDefRegTransferCmd</code> instance.
   *
   * @exception EPPEncodeException Unable to encode
   *        <code>EPPDefRegTransferCmd</code> instance.
   */
  protected Element doEncode(Document aDocument) throws EPPEncodeException {
    try {
      validateState();
    }
     catch (EPPCodecException e) {
      throw new EPPEncodeException("EPPDefRegTransferCmd invalid state: "
                     + e);
    }

    Element root =
      aDocument.createElementNS(EPPDefRegMapFactory.NS, ELM_NAME);

    root.setAttribute("xmlns:defReg", EPPDefRegMapFactory.NS);

    // Roid
    EPPUtil.encodeString(
               aDocument, root, roid, EPPDefRegMapFactory.NS,
               ELM_DEFREG_ROID);

    // Period with Attribute of Unit
    if ((period != null) && !period.isPeriodUnspec()) {
      EPPUtil.encodeComp(aDocument, root, period);
    }

    // authInfo
    EPPUtil.encodeComp(aDocument, root, authInfo);

    return root;
  }

  /**
   * Decode the <code>EPPDefRegTransferCmd</code> attributes from the
   * aElement DOM Element tree.
   *
   * @param aElement Root DOM Element to decode
   *      <code>EPPDefRegTransferCmd</code> from.
   *
   * @exception EPPDecodeException Unable to decode aElement
   */
  protected void doDecode(Element aElement) throws EPPDecodeException {
    //
    // DefReg Name
    roid =
      EPPUtil.decodeString(
                 aElement, EPPDefRegMapFactory.NS,
                 ELM_DEFREG_ROID);

    // Period
    period =
      (EPPDefRegPeriod) EPPUtil.decodeComp(
                         aElement,
                         EPPDefRegMapFactory.NS,
                         EPPDefRegPeriod.ELM_NAME,
                         EPPDefRegPeriod.class);

    // authInfo
    authInfo =
      (EPPAuthInfo) EPPUtil.decodeComp(
                       aElement, EPPDefRegMapFactory.NS,
                       EPPDefRegMapFactory.ELM_DEFREG_AUTHINFO,
                       EPPAuthInfo.class);
  }

  /**
   * Gets the defReg name to query.
   *
   * @return DefReg Name if defined; <code>null</code> otherwise.
   */
  public String getRoid() {
    return roid;
  }

  /**
   * Sets the defReg name to query.
   *
   * @param aRoid DefReg Name
   */
  public void setRoid(String aRoid) {
    roid = aRoid;
  }

  /**
   * Gets the registration period of the transfer command in years.
   *
   * @return Registration Period in years if defined; <code>null</code>
   *       otherwise.
   */
  public EPPDefRegPeriod getPeriod() {
    return period;
  }

  /**
   * Sets the registration period of the transfer command.
   *
   * @param aPeriod Registration Period.
   */
  public void setPeriod(EPPDefRegPeriod aPeriod) {
    period = aPeriod;
  }

  /**
   * Compare an instance of <code>EPPDefRegTransferCmd</code> with this
   * instance.
   *
   * @param aObject Object to compare with.
   *
   * @return DOCUMENT ME!
   */
  public boolean equals(Object aObject) {
    if (!(aObject instanceof EPPDefRegTransferCmd)) {
      return false;
    }

    // EPPTransferCmd
    if (!super.equals(aObject)) {
      return false;
    }

    EPPDefRegTransferCmd theMap = (EPPDefRegTransferCmd) aObject;

    //Roid
    if (
      !(
          (roid == null) ? (theMap.roid == null)
                     : roid.equals(theMap.roid)
        )) {
      return false;
    }

    // Period
    if (
      !(
          (period == null) ? (theMap.period == null)
                     : period.equals(theMap.period)
        )) {
      return false;
    }

    // AuthInfo
    if (
      !(
          (authInfo == null) ? (theMap.authInfo == null)
                       : authInfo.equals(theMap.authInfo)
        )) {
      return false;
    }

    return true;
  }

  /**
   * Clone <code>EPPDefRegTransferCmd</code>.
   *
   * @return clone of <code>EPPDefRegTransferCmd</code>
   *
   * @exception CloneNotSupportedException standard Object.clone exception
   */
  public Object clone() throws CloneNotSupportedException {
    EPPDefRegTransferCmd clone = (EPPDefRegTransferCmd) super.clone();

    if (authInfo != null) {
      clone.authInfo = (EPPAuthInfo) authInfo.clone();
    }

    if (period != null) {
      clone.period = (EPPDefRegPeriod) period.clone();
    }

    return clone;
  }

  /**
   * Implementation of <code>Object.toString</code>, which will result in an
   * indented XML <code>String</code> representation of the concrete
   * <code>EPPCodecComponent</code>.
   *
   * @return Indented XML <code>String</code> if successful;
   *       <code>ERROR</code> otherwise.
   */
  public String toString() {
    return EPPUtil.toString(this);
  }
}
