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

import java.util.Date;
import java.util.Vector;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.verisign.epp.codec.gen.EPPCodecException;
import com.verisign.epp.codec.gen.EPPDecodeException;
import com.verisign.epp.codec.gen.EPPEncodeException;
import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.gen.EPPTransId;
import com.verisign.epp.codec.gen.EPPUtil;

/**
 * Represents an EPP Host &lt;host:infData&gt; response to an
 * {@code EPPHostInfoCmd}. When an &lt;info&gt; command has been processed
 * successfully, the EPP &lt;resData&gt; element MUST contain a child
 * &lt;host:infData&gt; element that identifies the host namespace and the
 * location of the host schema. The &lt;host:infData&gt; element contains the
 * following child elements: <br>
 * 
 * <ul>
 * <li>A &lt;host:name&gt; element that contains the fully qualified name of the
 * host. Use {@code getName} and {@code setName} to get and set the element.
 * </li>
 * <li>A &lt;host:roid&gt; element that contains the Respoitory Object
 * IDentifier assigned to the host object when the object was created.</li>
 * <li>One or more &lt;host:status&gt; elements that describe the status of the
 * host object. Use {@code getStatuses} and {@code setStatuses} to get and set
 * the element.</li>
 * <li>Zero or more &lt;host:addr&gt; elements that contain the IP addresses
 * associated with the host object. Use {@code getAddresses} and
 * {@code setAddresses} to get and set the element.</li>
 * <li>A &lt;host:clID&gt; element that contains the identifier of the
 * sponsoring client. Use {@code getClientId} and {@code setClientId} to get and
 * set the element.</li>
 * <li>A &lt;host:crID&gt; element that contains the identifier of the client
 * that created the host name. Use {@code getCreatedBy} and {@code setCreatedBy}
 * to get and set the element.</li>
 * <li>A &lt;host:crDate&gt; element that contains the date and time of host
 * creation. Use {@code getCreatedDate} and {@code setCreatedDate} to get and
 * set the element.</li>
 * <li>A &lt;host:upID&gt; element that contains the identifier of the client
 * that last updated the host name. This element MUST NOT be present if the host
 * has never been modified. Use {@code getLastUpdatedBy} and
 * {@code setLastUpdatedBy} to get and set the element.</li>
 * <li>A &lt;host:upDate&gt; element that contains the date and time of the most
 * recent host modification. This element MUST NOT be present if the host has
 * never been modified. Use {@code getUpdatedDate} and {@code setUpdatedDate} to
 * get and set the element.</li>
 * <li>A &lt;host:trDate&gt; element that contains the date and time of the most
 * recent successful transfer. This element MUST NOT be provided if the host has
 * never been transferred. Note that host objects MUST NOT be transferred
 * directly; host objects MUST be transferred implicitly when the host object's
 * superordinate domain object is transferred. Host objects that are subject to
 * transfer when transferring a domain object are listed in the response to an
 * EPP &lt;info&gt; command performed on the domain object. Use
 * {@code getTrDate} and {@code setTrDate} to get and set the element.</li>
 * <li>A &lt;host:authInfo&gt; element derived from either the original creation
 * transaction or the most recent successful parent domain transfer transaction.
 * This element MUST NOT be provided if the querying client is not the current
 * sponsoring client. Use {@code getAuthInfo} and {@code setAuthInfo} to get and
 * set the element.</li>
 * </ul>
 *
 * @see com.verisign.epp.codec.host.EPPHostInfoCmd
 */
public class EPPHostInfoResp extends EPPResponse {
  /**
   * XML local name for {@code EPPHostInfoResp}.
   */
  public static final String ELM_LOCALNAME = "infData";

  /**
   * XML Element Name of {@code EPPHostInfoResp} root element.
   */
  public static final String ELM_NAME = EPPHostMapFactory.NS_PREFIX + ":" + ELM_LOCALNAME;

  /** XML Element Name of {@code EPPHostInfoResp} root element. */
  final static String ELM_LINKED = "linked";

  /** XML Element Name of {@code EPPHostInfoResp} root element. */
  final static String ELM_ROID = "roid";

  /** XML tag name for the {@code name} attribute. */
  private final static String ELM_HOST_NAME = "name";

  /** XML tag name for the {@code clientId} attribute. */
  private final static String ELM_CLIENT_ID = "clID";

  /** XML tag name for the {@code createdBy} attribute. */
  private final static String ELM_CREATED_BY = "crID";

  /** XML tag name for the {@code createdDate} attribute. */
  private final static String ELM_CREATED_DATE = "crDate";

  /** XML tag name for the {@code lastUpdatedBy} attribute. */
  private final static String ELM_LAST_UPDATED_BY = "upID";

  /** XML tag name for the {@code lastUpdatedDate} attribute. */
  private final static String ELM_LAST_UPDATED_DATE = "upDate";

  /** XML tag name for the {@code clientId} attribute. */
  private final static String ELM_TRDATE = "trDate";

  /** fully qualified name of the host */
  private String name = null;

  /** identifier of sponsoring client */
  private String clientId = null;

  /**
   * {@code Vector} of {@code EPPHostAddress} instances associated with host.
   */
  private Vector<EPPHostAddress> addresses = new Vector<EPPHostAddress>();

  /** identifier of the client that created the host name */
  private String createdBy = null;

  /** date and time of host creation */
  private Date createdDate = null;

  /** identifier of the client that last updated the host name */
  private String lastUpdatedBy = null;

  /** date and time of the most recent host modification */
  private Date lastUpdatedDate = null;

  /** Host statuses */
  private Vector<EPPHostStatus> statuses = null;

  /** Host transfer date */
  private java.util.Date trDate = null;

  /** roid */
  private java.lang.String roid = null;

  /**
   * {@code EPPHostInfoResp} default constructor. Must call required setter
   * methods before invoking {@code encode}, which include:<br>
   * <br>
   * 
   * <ul>
   * <li>name - {@code setName}</li>
   * <li>roid - {@code setRoid}</li>
   * <li>status - {@code setStatuses}</li>
   * <li>client id - {@code setClientId}</li>
   * <li>created by - {@code setCreatedBy}</li>
   * <li>created date - {@code setCreatedDate}</li>
   * </ul>
   */
  public EPPHostInfoResp() {
    // Default values set in attribute definitions.
  }

  /**
   * {@code EPPHostInfoResp} constuctor that takes the required attribute
   * values as parameters. The setter methods of the optional attributes can be
   * called before invoking {@code encode}.
   *
   * @param aTransId
   *           Transaction Id associated with response.
   * @param aName
   *           Host name
   * @param aRoid
   *           roid
   * @param aHostStatus
   *           EPP Host Status
   * @param aClientId
   *           Owning Client Id
   * @param aCreatedBy
   *           Client Id of Registrar that created the host
   * @param aCreatedDate
   *           Date the host was created
   */
  public EPPHostInfoResp(EPPTransId aTransId, String aName, String aRoid, EPPHostStatus aHostStatus, String aClientId,
        String aCreatedBy, Date aCreatedDate) {
    super(aTransId);

    name = aName;
    roid = aRoid;
    this.addStatus(aHostStatus);
    clientId = aClientId;
    createdBy = aCreatedBy;
    createdDate = aCreatedDate;
  }

  /**
   * Gets the EPP response type associated with {@code EPPHostInfoResp}.
   *
   * @return {@code EPPHostInfoResp.ELM_NAME}
   */
  public String getType() {
    return ELM_NAME;
  }

  /**
   * Gets the EPP command namespace associated with {@code EPPHostInfoResp}.
   *
   * @return {@code EPPHostMapFactory.NS}
   */
  public String getNamespace() {
    return EPPHostMapFactory.NS;
  }

  /**
   * Validate the state of the {@code EPPHostInfoResp} 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!
   */
  void validateState() throws EPPCodecException {
    if (name == null) {
      throw new EPPCodecException("required attribute name is not set");
    }

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

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

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

    if (createdBy == null) {
      throw new EPPCodecException("createBy required attribute is not set");
    }

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

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

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

    root.setAttribute("xmlns:host", EPPHostMapFactory.NS);

    // Name
    EPPUtil.encodeString(aDocument, root, name, EPPHostMapFactory.NS,
          EPPHostMapFactory.NS_PREFIX + ":" + ELM_HOST_NAME);

    // roid
    EPPUtil.encodeString(aDocument, root, roid, EPPHostMapFactory.NS, EPPHostMapFactory.NS_PREFIX + ":" + ELM_ROID);

    // statuses
    EPPUtil.encodeCompVector(aDocument, root, statuses);

    // Addresses
    EPPUtil.encodeCompVector(aDocument, root, addresses);

    // Client Id
    EPPUtil.encodeString(aDocument, root, clientId, EPPHostMapFactory.NS,
          EPPHostMapFactory.NS_PREFIX + ":" + ELM_CLIENT_ID);

    // Created By
    EPPUtil.encodeString(aDocument, root, createdBy, EPPHostMapFactory.NS,
          EPPHostMapFactory.NS_PREFIX + ":" + ELM_CREATED_BY);

    // Created Date
    EPPUtil.encodeTimeInstant(aDocument, root, createdDate, EPPHostMapFactory.NS,
          EPPHostMapFactory.NS_PREFIX + ":" + ELM_CREATED_DATE);

    // Last Updated By
    if (lastUpdatedBy != null) {
      EPPUtil.encodeString(aDocument, root, lastUpdatedBy, EPPHostMapFactory.NS,
            EPPHostMapFactory.NS_PREFIX + ":" + ELM_LAST_UPDATED_BY);
    }

    // Last Updated Date
    if (lastUpdatedDate != null) {
      EPPUtil.encodeTimeInstant(aDocument, root, lastUpdatedDate, EPPHostMapFactory.NS,
            EPPHostMapFactory.NS_PREFIX + ":" + ELM_LAST_UPDATED_DATE);
    }

    // trDate
    if (trDate != null) {
      EPPUtil.encodeTimeInstant(aDocument, root, trDate, EPPHostMapFactory.NS,
            EPPHostMapFactory.NS_PREFIX + ":" + ELM_TRDATE);
    }

    return root;
  }

  /**
   * Decode the {@code EPPHostInfoResp} attributes from the aElement DOM
   * Element tree.
   *
   * @param aElement
   *           Root DOM Element to decode {@code EPPHostInfoResp} from.
   *
   * @exception EPPDecodeException
   *               Unable to decode aElement
   */
  protected void doDecode(Element aElement) throws EPPDecodeException {
    // Name
    name = EPPUtil.decodeString(aElement, EPPHostMapFactory.NS, ELM_HOST_NAME);

    // roid
    roid = EPPUtil.decodeString(aElement, EPPHostMapFactory.NS, ELM_ROID);

    // statuses
    statuses = EPPUtil.decodeCompVector(aElement, EPPHostMapFactory.NS, EPPHostStatus.ELM_NAME, EPPHostStatus.class);

    // Addresses
    addresses = EPPUtil.decodeCompVector(aElement, EPPHostMapFactory.NS, EPPHostAddress.ELM_NAME,
          EPPHostAddress.class);

    // Client Id
    clientId = EPPUtil.decodeString(aElement, EPPHostMapFactory.NS, ELM_CLIENT_ID);

    // Created By
    createdBy = EPPUtil.decodeString(aElement, EPPHostMapFactory.NS, ELM_CREATED_BY);

    // Created Date
    createdDate = EPPUtil.decodeTimeInstant(aElement, EPPHostMapFactory.NS, ELM_CREATED_DATE);

    // Last Updated By
    lastUpdatedBy = EPPUtil.decodeString(aElement, EPPHostMapFactory.NS, ELM_LAST_UPDATED_BY);

    // Last Updated Date
    lastUpdatedDate = EPPUtil.decodeTimeInstant(aElement, EPPHostMapFactory.NS, ELM_LAST_UPDATED_DATE);

    // trDate
    trDate = EPPUtil.decodeTimeInstant(aElement, EPPHostMapFactory.NS, ELM_TRDATE);
  }

  /**
   * Compare an instance of {@code EPPHostInfoResp} with this instance.
   *
   * @param aObject
   *           Object to compare with.
   *
   * @return {@code true} if equal; {@code false} otherwise
   */
  public boolean equals(Object aObject) {
    if (!(aObject instanceof EPPHostInfoResp)) {
      return false;
    }

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

    EPPHostInfoResp theInfoData = (EPPHostInfoResp) aObject;

    // Name
    if (!((name == null) ? (theInfoData.name == null) : name.equals(theInfoData.name))) {
      return false;
    }

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

    // statuses
    if (!EPPUtil.equalVectors(statuses, theInfoData.statuses)) {
      return false;
    }

    // Addresses
    if (!EPPUtil.equalVectors(addresses, theInfoData.addresses)) {
      return false;
    }

    // Client Id
    if (!((clientId == null) ? (theInfoData.clientId == null) : clientId.equals(theInfoData.clientId))) {
      return false;
    }

    // Created By
    if (!((createdBy == null) ? (theInfoData.createdBy == null) : createdBy.equals(theInfoData.createdBy))) {
      return false;
    }

    // Created Date
    if (!((createdDate == null) ? (theInfoData.createdDate == null) : createdDate.equals(theInfoData.createdDate))) {
      return false;
    }

    // Last Updated By
    if (!((lastUpdatedBy == null) ? (theInfoData.lastUpdatedBy == null) :
          lastUpdatedBy.equals(theInfoData.lastUpdatedBy))) {
      return false;
    }

    // Last Updated Date
    if (!((lastUpdatedDate == null) ? (theInfoData.lastUpdatedDate == null) :
          lastUpdatedDate.equals(theInfoData.lastUpdatedDate))) {
      return false;
    }

    // trDate
    if (!((trDate == null) ? (theInfoData.trDate == null) : trDate.equals(theInfoData.trDate))) {
      return false;
    }

    return true;
  }

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

    // Addresses
    if (this.hasAddresses()) {
      clone.addresses = (Vector<EPPHostAddress>) this.addresses.clone();

      for (int i = 0; i < this.addresses.size(); i++) {
        clone.addresses.setElementAt((EPPHostAddress) (this.addresses.elementAt(i)).clone(), i);
      }
    }

    // Statuses
    if (this.hasStatuses()) {
      clone.statuses = (Vector<EPPHostStatus>) this.statuses.clone();

      for (int i = 0; i < this.statuses.size(); i++) {
        clone.statuses.setElementAt((EPPHostStatus) (this.statuses.elementAt(i)).clone(), i);
      }
    }

    return clone;
  }

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

  /**
   * Gets the host name
   *
   * @return Host Name if defined; {@code null} otherwise.
   */
  public String getName() {
    return name;
  }

  /**
   * Sets the host name.
   *
   * @param aName
   *           Host Name
   */
  public void setName(String aName) {
    name = aName;
  }

  /**
   * Gets the host owning Client Id.
   *
   * @return Client Id if defined; {@code null} otherwise.
   */
  public String getClientId() {
    return clientId;
  }

  /**
   * Sets the host owning Client Id.
   *
   * @param aClientId
   *           Client Id
   */
  public void setClientId(String aClientId) {
    clientId = aClientId;
  }

  /**
   * Are addresses set?
   *
   * @return {@code true} if addresses are set; {@code false} otherwise.
   */
  public boolean hasAddresses() {
    if (this.addresses != null) {
      return true;
    }
    else {
      return false;
    }
  }

  /**
   * Add an address to the list of addresses.
   * 
   * @param aAddress
   *           Address to add
   */
  public void addAddress(EPPHostAddress aAddress) {
    if (this.addresses == null) {
      this.addresses = new Vector<EPPHostAddress>();
    }

    this.addresses.add(aAddress);
  }

  /**
   * Gets the list (Vector) of host addresses. Each host address is an instance
   * of {@code EPPHostAddress}.
   *
   * @return {@code Vector} of {@code EPPHostAddress} instances if defined;
   *         {@code null} otherwise.
   */
  public Vector<EPPHostAddress> getAddresses() {
    return addresses;
  }

  /**
   * Sets the list (Vector) of host addresses. Each host address is an instance
   * of {@code EPPHostAddress}.
   *
   * @param aAddresses
   *           {@code Vector} of {@code EPPHostAddress} instances
   */
  public void setAddresses(Vector<EPPHostAddress> aAddresses) {
    addresses = aAddresses;
  }

  /**
   * Gets Client Id that created the host.
   *
   * @return Client Id if defined; {@code null} otherwise.
   */
  public String getCreatedBy() {
    return createdBy;
  }

  /**
   * Sets Client Id that created the host.
   *
   * @param aCreatedBy
   *           Client Id that created the host.
   */
  public void setCreatedBy(String aCreatedBy) {
    createdBy = aCreatedBy;
  }

  /**
   * Gets the date and time the host was created.
   *
   * @return Date and time the host was created if defined; {@code null}
   *         otherwise.
   */
  public Date getCreatedDate() {
    return createdDate;
  }

  /**
   * Sets the date and time the host was created.
   *
   * @param aDate
   *           Date and time the host was created.
   */
  public void setCreatedDate(Date aDate) {
    createdDate = aDate;
  }

  /**
   * Gets the Client Id that last updated the host. This will be null if the
   * host has not been updated since creation.
   *
   * @return Client Id that last updated the host has been updated;
   *         {@code null} otherwise.
   */
  public String getLastUpdatedBy() {
    return lastUpdatedBy;
  }

  /**
   * Sets the Client Id that last updated the host.
   *
   * @param aLastUpdatedBy
   *           Client Id String that last updated the host.
   */
  public void setLastUpdatedBy(String aLastUpdatedBy) {
    lastUpdatedBy = aLastUpdatedBy;
  }

  /**
   * Gets the date and time of the last host update. This will be {@code null}
   * if the host has not been updated since creation.
   *
   * @return date and time of the last host update if defined; {@code null}
   *         otherwise.
   */
  public Date getLastUpdatedDate() {
    return lastUpdatedDate;
  }

  /**
   * Sets the last date and time the host was updated.
   *
   * @param aLastUpdatedDate
   *           Date and time of the last host update.
   */
  public void setLastUpdatedDate(Date aLastUpdatedDate) {
    lastUpdatedDate = aLastUpdatedDate;
  }

  /**
   * Get transfer date.
   *
   * @return java.util.Date
   */
  public java.util.Date getTrDate() {
    return trDate;
  }

  /**
   * Are statuses set?
   *
   * @return {@code true} if statuses are set; {@code false} otherwise.
   */
  public boolean hasStatuses() {
    if (this.statuses != null) {
      return true;
    }
    else {
      return false;
    }
  }

  /**
   * Get host statuses.
   *
   * @return {@code Vector} of {@code EPPHostStatus} if defined; {@code null}
   *         if undefined.
   */
  public Vector<EPPHostStatus> getStatuses() {
    return statuses;
  }

  /**
   * Add a status to the list of statuses.
   * 
   * @param aStatus
   *           Status to add
   */
  public void addStatus(EPPHostStatus aStatus) {
    if (this.statuses == null) {
      this.statuses = new Vector<EPPHostStatus>();
    }

    this.statuses.add(aStatus);
  }

  /**
   * Add an individual status to the list of statuses.
   *
   * @param aHostStatus
   *           com.verisign.epp.codec.host.EPPHostStatus
   *           
   * @deprecated Use {@link #addStatus(EPPHostStatus)}
   */
  @Deprecated 
  public void setStatuses(EPPHostStatus aHostStatus) {
    if (statuses != null) {
      statuses.addElement(aHostStatus);
    }
    else {
      statuses = new Vector<EPPHostStatus>();
      statuses.addElement(aHostStatus);
    }
  }

  /**
   * Set host statuses.
   *
   * @param newStatuses
   *           Vector
   */
  public void setStatuses(Vector<EPPHostStatus> newStatuses) {
    statuses = newStatuses;
  }

  /**
   * Set transfer date.
   *
   * @param newTrDate
   *           java.util.Date
   */
  public void setTrDate(java.util.Date newTrDate) {
    trDate = newTrDate;
  }

  /**
   * Get roid.
   *
   * @return java.lang.String
   */
  public java.lang.String getRoid() {
    return roid;
  }

  /**
   * Set roid.
   *
   * @param newRoid
   *           java.lang.String
   */
  public void setRoid(String newRoid) {
    roid = newRoid;
  }

}
