/***********************************************************
Copyright (C) 2018 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.registry.v01;

import java.security.InvalidParameterException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.verisign.epp.codec.gen.EPPCodecComponent;
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.EPPUtil;
import com.verisign.epp.util.EqualityUtil;

/**
 * Represents the optional contact object policy information per RFC 5733. The
 * &lt;registry:contact&gt; element contains the following child elements: <br>
 * <ul>
 * <li>&lt;registry:contactIdRegEx&gt; - The OPTIONAL regular expression used to
 * validate the &lt;contact:id&gt; element defined in RFC 5733.</li>
 * <li>&lt;registry:sharePolicy&gt; - The OPTIONAL policy for the sharing of
 * contacts in the server. The possible shared policy values include:
 * <ul>
 * <li>"perZone" - The contacts are shared across all objects of the zone. There
 * is a single pool of contacts defined for the zone.</li>
 * <li>"perSystem" - The contacts are shared across all zones of the system.
 * There is a single pool of contacts across all of the zones supported by the
 * system.</li>
 * </ul>
 * </li>
 * <li>&lt;registry:postalInfoTypeSupport&gt; - The policy associated with the
 * postal-address information, represented by the &lt;contact:postalInfo&gt;
 * element in [RFC5733]</li>
 * <li>&lt;registry:postalInfo&gt; - The postal-address information policy
 * information.</li>
 * <li>&lt;registry:maxCheckContact&gt; - The maximum number of contact
 * identifiers (&lt;contact:id&gt; elements) that can be included in a contact
 * check command defined in RFC 5733.</li>
 * <li>&lt;registry:authInfoRegex&gt; - The OPTIONAL regular expression used to
 * validate the contact object authorization information value.</li>
 * <li>&lt;registry:clientDisclosureSupported&gt; - The OPTIONAL flag that
 * indicates whether the server supports the client to identify elements that
 * require exception server-operator handling to allow or restrict disclosure to
 * third parties defined in RFC 5733. Default value is {@code false}.</li>
 * <li>&lt;registry:supportedStatus&gt; - The OPTIONAL set of supported contact
 * statuses defined in RFC 5733.</li>
 * <li>&lt;registry:transferHoldPeriod&gt; - The OPTIONAL period of time a
 * contact object is in the pending transfer before the transfer is auto
 * approved by the server. The &lt;registry:transferHoldPeriod&gt; element MUST
 * have the "unit" attribute with the possible values of "y" for year, "m" for
 * month, and "d" for day.</li>
 * <li>&lt;registry:customData&gt; - The OPTIONAL set of custom data using key,
 * value pairs.</li>
 * </ul>
 * 
 * @see com.verisign.epp.codec.registry.v01.EPPRegistryRegex
 * @see com.verisign.epp.codec.registry.v01.EPPRegistryPostal
 * @see com.verisign.epp.codec.registry.v01.EPPRegistrySupportedStatus
 * @see com.verisign.epp.codec.registry.v01.EPPRegistryTransferHoldPeriodType
 */
public class EPPRegistryContact implements EPPCodecComponent {

	/**
	 * Log4j category for logging
	 */
	private static Logger cat = Logger.getLogger(EPPRegistryContact.class);

	/**
	 * Possible values for the {@code sharePolicy} attribute.
	 */
	public static enum SharePolicy {

		/**
		 * Constant for share policy where contacts are shared across all objects
		 * of the zone. There is a single pool of contacts defined for the zone.
		 */
		perZone,

		/**
		 * Constant for share policy where contacts are shared across all zones of
		 * the system. There is a single pool of contacts across all of the zones
		 * supported by the system.
		 */
		perSystem
	}

	/**
	 * Possible values for the {@code postalInfoTypeSupport} attribute. The
	 * "Support" suffix is removed when setting the value in the element.
	 */
	public static enum PostalInfoTypeSupport {

		/**
		 * Indicates that a single &lt;contact:postalInfo&gt; element is supported
		 * with the type "loc".
		 */
		locSupport("loc"),

		/**
		 * Indicates that a single &lt;contact:postalInfo&gt; element is supported
		 * with the type "int".
		 */
		intSupport("int"),

		/**
		 * Indicates that a single &lt;contact:postalInfo&gt; element is supported
		 * with the type "loc" or "int".
		 */
		locOrIntSupport("locOrInt"),

		/**
		 * Indicates that up to two &lt;contact:postalInfo&gt; elements is
		 * supported for defining both the "loc" and the "int" type. This policy
		 * does not indicate that both must be provided.
		 */
		locAndIntSupport("locAndInt");

		private final String supportStr;

		/**
		 * Define the string value for the enumerated value.
		 *
		 * @param aSupportStr
		 *           Enumerated value string
		 */
		PostalInfoTypeSupport(String aSupportStr) {
			this.supportStr = aSupportStr;
		}

		/**
		 * Get the type enumerated value given the matching string.
		 *
		 * @param aSupportStr
		 *           {@code PostalInfoTypeSupport} enumerated string to convert to
		 *           an enumerated {@code PostalInfoTypeSupport} instance.
		 *
		 * @return Enumerated {@code PostalInfoTypeSupport} value matching the
		 *         {@code String}.
		 *
		 * @throws InvalidParameterException
		 *            If {@code aSupportStr} does not match an enumerated
		 *            {@code PostalInfoTypeSupport} string value.
		 */
		public static PostalInfoTypeSupport getSupport(String aSupportStr) {
			if (aSupportStr == null) {
				throw new InvalidParameterException("null PostalInfoTypeSupport enum value is not valid.");
			}

			if (aSupportStr.equals(locSupport.supportStr)) {
				return locSupport;
			}
			else if (aSupportStr.equals(intSupport.supportStr)) {
				return intSupport;
			}
			else if (aSupportStr.equals(locOrIntSupport.supportStr)) {
				return locOrIntSupport;
			}
			else if (aSupportStr.equals(locAndIntSupport.supportStr)) {
				return locAndIntSupport;
			}
			else {
				throw new InvalidParameterException(
				      "PostalInfoTypeSupport enum value of " + aSupportStr + " is not valid.");
			}

		}

		/**
		 * Convert the enumerated {@code PostalInfoTypeSupport} value to a
		 * {@code String} .
		 */
		@Override
		public String toString() {
			return this.supportStr;
		}

	}

	/**
	 * Constant for the status local name
	 */
	public static final String ELM_LOCALNAME = "contact";

	/**
	 * Constant for the contact (prefix and local name)
	 */
	public static final String ELM_NAME = EPPRegistryMapFactory.NS_PREFIX + ":" + ELM_LOCALNAME;

	/**
	 * XML local name for the contactIdRegex
	 */
	public final static String ELM_CONTACT_ID_REGEX = "contactIdRegex";

	/**
	 * XML local name for the sharePolicy
	 */
	public static final String ELM_SHARE_POLICY = "sharePolicy";

	/**
	 * XML local name for the {@code postalInfoTypeSupport} attribute
	 */
	public static final String ELM_POSTAL_INFO_TYPE_SUPPORT = "postalInfoTypeSupport";

	/**
	 * XML local name for the maxCheckContact
	 */
	public static final String ELM_MAX_CHECK = "maxCheckContact";

	/**
	 * XML local name for the authInfoRegex
	 */
	public final static String ELM_AUTH_INFO_REGEX = "authInfoRegex";

	/**
	 * XML local name for the customData
	 */
	public final static String ELM_CUSTOM_DATA = "customData";

	/**
	 * XML local name for the clientDisclosureSupported
	 */
	public final static String ELM_CUSTOM_CLIENT_DISCLOSURE_SUPPORTED = "clientDisclosureSupported";

	/**
	 * Optional contact Id regular expression
	 */
	private EPPRegistryRegex contactIdRegex = null;

	/**
	 * The policy for the sharing of contacts in the server.
	 */
	private SharePolicy sharePolicy = null;

	/**
	 * The policy associated with the postal-address information, represented by
	 * the &lt;contact:postalInfo&gt; element in [RFC5733]
	 */
	private PostalInfoTypeSupport postalInfoTypeSupport = null;

	/** The postal-address information policy information */
	private EPPRegistryPostal postalInfo = null;

	/**
	 * The maximum number of contact identifiers (&lt;contact:id&gt; elements)
	 * that can be included in a contact check command defined in RFC 5733.
	 */
	private Integer maxCheckContact = null;

	/**
	 * The regular expression used to validate the contact object authorization
	 * information value
	 */
	private EPPRegistryRegex authInfoRegex = null;

	/**
	 * Whether the server supports the client to identify elements that require
	 * exception server-operator handling to allow or restrict disclosure to
	 * third parties defined in RFC 5733.
	 */
	private Boolean clientDisclosureSupported = Boolean.FALSE;

	/** 
	 * Transfer hold policy attribute 
	 */
	private EPPRegistryTransferHoldPeriodType transferHoldPeriod = null;

	/** 
	 * {@code List} of contact status supported by the server 
	 */
	private EPPRegistrySupportedStatus supportedStatus = null;

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

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

		// Contact Id Regex
		EPPUtil.encodeComp(aDocument, root, this.contactIdRegex);

		// Share Policy
		if (this.hasSharePolicy()) {
			EPPUtil.encodeString(aDocument, root, this.sharePolicy.toString(), EPPRegistryMapFactory.NS,
			      EPPRegistryMapFactory.NS_PREFIX + ":" + ELM_SHARE_POLICY);
		}

		// Postal Info Type Support
		EPPUtil.encodeString(aDocument, root, this.postalInfoTypeSupport.toString(), EPPRegistryMapFactory.NS,
		      EPPRegistryMapFactory.NS_PREFIX + ":" + ELM_POSTAL_INFO_TYPE_SUPPORT);

		// Postal Info
		EPPUtil.encodeComp(aDocument, root, postalInfo);

		// Max Check Contact
		EPPUtil.encodeString(aDocument, root, this.maxCheckContact.toString(), EPPRegistryMapFactory.NS,
		      EPPRegistryMapFactory.NS_PREFIX + ":" + ELM_MAX_CHECK);

		// Auth Info Regex
		if (authInfoRegex != null) {
			EPPUtil.encodeComp(aDocument, root, authInfoRegex);
		}

		// Client Disclosure Supported
		if (clientDisclosureSupported == null) {
			clientDisclosureSupported = Boolean.FALSE;
		}
		EPPUtil.encodeString(aDocument, root, clientDisclosureSupported.toString(), EPPRegistryMapFactory.NS,
		      EPPRegistryMapFactory.NS_PREFIX + ":" + ELM_CUSTOM_CLIENT_DISCLOSURE_SUPPORTED);

		// Supported Status
		if (supportedStatus != null) {
			EPPUtil.encodeComp(aDocument, root, supportedStatus);
		}

		// Transfer Hold Period
		EPPUtil.encodeComp(aDocument, root, transferHoldPeriod);

		return root;
	}

	/**
	 * Decode the {@code EPPRegistryContact} attributes from the aElement DOM
	 * Element tree.
	 * 
	 * @param aElement
	 *           Root DOM Element to decode {@code EPPRegistryContact} from.
	 * 
	 * @exception EPPDecodeException
	 *               Unable to decode aElement
	 */
	public void decode(Element aElement) throws EPPDecodeException {

		// Contact Id Regex
		this.setContactIdRegex((EPPRegistryRegex) EPPUtil.decodeComp(aElement, EPPRegistryMapFactory.NS,
		      ELM_CONTACT_ID_REGEX, EPPRegistryRegex.class));

		// Share Policy
		String theSharePolicyStr = EPPUtil.decodeString(aElement, EPPRegistryMapFactory.NS, ELM_SHARE_POLICY);
		if (theSharePolicyStr == null) {
			this.sharePolicy = null;
		}
		else {
			this.sharePolicy = SharePolicy.valueOf(theSharePolicyStr);
		}

		// Postal Info Type Support
		this.postalInfoTypeSupport = PostalInfoTypeSupport
		      .getSupport(EPPUtil.decodeString(aElement, EPPRegistryMapFactory.NS, ELM_POSTAL_INFO_TYPE_SUPPORT));

		// Postal Info
		postalInfo = (EPPRegistryPostal) EPPUtil.decodeComp(aElement, EPPRegistryMapFactory.NS,
		      EPPRegistryPostal.ELM_NAME, EPPRegistryPostal.class);

		// Max Check Contact
		maxCheckContact = EPPUtil.decodeInteger(aElement, EPPRegistryMapFactory.NS, ELM_MAX_CHECK);

		// Auth Info Regex
		this.setAuthInfoRegex((EPPRegistryRegex) EPPUtil.decodeComp(aElement, EPPRegistryMapFactory.NS,
		      ELM_AUTH_INFO_REGEX, EPPRegistryRegex.class));

		// Client Disclosure Supported
		clientDisclosureSupported = EPPUtil.decodeBoolean(aElement, EPPRegistryMapFactory.NS,
		      ELM_CUSTOM_CLIENT_DISCLOSURE_SUPPORTED);
		if (clientDisclosureSupported == null) {
			clientDisclosureSupported = Boolean.FALSE;
		}

		// Supported Status
		supportedStatus = (EPPRegistrySupportedStatus) EPPUtil.decodeComp(aElement, EPPRegistryMapFactory.NS,
		      EPPRegistrySupportedStatus.ELM_NAME, EPPRegistrySupportedStatus.class);

		// Transfer Hold Period
		transferHoldPeriod = (EPPRegistryTransferHoldPeriodType) EPPUtil.decodeComp(aElement, EPPRegistryMapFactory.NS,
		      EPPRegistryTransferHoldPeriodType.ELM_LOCALNAME, EPPRegistryTransferHoldPeriodType.class);
	}

	/**
	 * Validate the state of the {@code EPPRegistryContact} 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
	 */
	void validateState() throws EPPCodecException {

		if (this.postalInfoTypeSupport == null) {
			throw new EPPCodecException("postalInfoTypeSupport required element is not set");
		}

		if (this.postalInfo == null) {
			throw new EPPCodecException("postalInfo required element is not set");
		}

		if (this.maxCheckContact == null || this.maxCheckContact.intValue() <= 0) {
			throw new EPPCodecException("maxCheckContact is required and should be greater than 0");
		}
	}

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

		if (this.contactIdRegex != null) {
			clone.contactIdRegex = (EPPRegistryRegex) contactIdRegex.clone();
		}

		if (authInfoRegex != null) {
			clone.authInfoRegex = (EPPRegistryRegex) authInfoRegex.clone();
		}

		if (supportedStatus != null) {
			clone.supportedStatus = (EPPRegistrySupportedStatus) supportedStatus.clone();
		}

		if (transferHoldPeriod != null) {
			clone.transferHoldPeriod = (EPPRegistryTransferHoldPeriodType) this.transferHoldPeriod.clone();
		}

		return clone;
	}

	/**
	 * implements a deep {@code EPPRegistryContact} compare.
	 * 
	 * @param aObject
	 *           {@code EPPRegistryContact} instance to compare with
	 * 
	 * @return {@code true} if this object is the same as the aObject argument;
	 *         {@code false} otherwise
	 */
	public boolean equals(Object aObject) {
		if (!(aObject instanceof EPPRegistryContact)) {
			return false;
		}

		EPPRegistryContact other = (EPPRegistryContact) aObject;

		// Contact Id Regex
		if (!EqualityUtil.equals(this.contactIdRegex, other.contactIdRegex)) {
			cat.error("EPPRegistryContact.equals(): contactIdRegex not equal");
			return false;
		}

		// Share Policy
		if (!EqualityUtil.equals(this.sharePolicy, other.sharePolicy)) {
			cat.error("EPPRegistryContact.equals(): sharePolicy not equal");
			return false;
		}

		// Postal Info Type Support
		if (!EqualityUtil.equals(this.postalInfoTypeSupport, other.postalInfoTypeSupport)) {
			cat.error("EPPRegistryContact.equals(): postalInfoTypeSupport not equal");
			return false;
		}

		// Postal Info
		if (!EqualityUtil.equals(this.postalInfo, other.postalInfo)) {
			cat.error("EPPRegistryContact.equals(): postalInfo not equal");
			return false;
		}

		// Max Check Contact
		if (!EqualityUtil.equals(this.maxCheckContact, other.maxCheckContact)) {
			cat.error("EPPRegistryContact.equals(): maxCheckContact not equal");
			return false;
		}

		// Auth Info Regex
		if (!EqualityUtil.equals(this.authInfoRegex, other.authInfoRegex)) {
			cat.error("EPPRegistryContact.equals(): authInfoRegex not equal");
			return false;
		}

		// Supported Status
		if (!EqualityUtil.equals(this.supportedStatus, other.supportedStatus)) {
			cat.error("EPPRegistryContact.equals(): supportedStatus not equal");
			return false;
		}

		// Transfer Hold Period
		if (!EqualityUtil.equals(this.transferHoldPeriod, other.transferHoldPeriod)) {
			cat.error("EPPRegistryContact.equals(): transferHoldPeriod not equal");
			return false;
		}

		return true;
	}

	/**
	 * 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);
	}

	/**
	 * Get info about regular expression used to validate the contact object
	 * contact Id value.
	 * 
	 * @return instance of {@link EPPRegistryRegex} that specifies regular
	 *         expression used to validate the domain object authorization
	 *         information value
	 */
	public EPPRegistryRegex getContactIdRegex() {
		return this.contactIdRegex;
	}

	/**
	 * Set info about regular expression used to validate the contact object
	 * contact Id value.
	 * 
	 * @param aContactIdRegex
	 *           instance of {@link EPPRegistryRegex} that specifies regular
	 *           expression used to validate the contact object contact Id value
	 */
	public void setContactIdRegex(EPPRegistryRegex aContactIdRegex) {
		if (aContactIdRegex != null) {
			aContactIdRegex.setRootName(ELM_CONTACT_ID_REGEX);
		}
		this.contactIdRegex = aContactIdRegex;
	}

	/**
	 * Is the share policy defined?
	 *
	 * @return {@code true} if the share policy is defined; {@code false}
	 *         otherwise.
	 */
	public boolean hasSharePolicy() {
		return (this.sharePolicy != null ? true : false);
	}

	/**
	 * Gets the share policy.
	 *
	 * @return share policy if defined; {@code null} otherwise.
	 */
	public SharePolicy getSharePolicy() {
		return this.sharePolicy;
	}

	/**
	 * Sets the share policy.
	 *
	 * @param aSharePolicy
	 *           Share policy. Set to {@code null} to clear it.
	 */
	public void setSharePolicy(SharePolicy aSharePolicy) {
		this.sharePolicy = aSharePolicy;
	}

	/**
	 * Gets the policy associated with the postal-address information,
	 * represented by the &lt;contact:postalInfo&gt; element.
	 * 
	 * @return The policy based on the {@link PostalInfoTypeSupport} enumerated
	 *         values if defined; {@code null} otherwise.
	 */
	public PostalInfoTypeSupport getPostalInfoTypeSupport() {
		return this.postalInfoTypeSupport;
	}

	/**
	 * Sets the policy associated with the postal-address information,
	 * represented by the &lt;contact:postalInfo&gt; element.
	 * 
	 * @param aPostalInfoTypeSupport
	 *           The policy based on the {@link PostalInfoTypeSupport} enumerated
	 *           values
	 */
	public void setIntPostalInfoTypeSupport(PostalInfoTypeSupport aPostalInfoTypeSupport) {
		this.postalInfoTypeSupport = aPostalInfoTypeSupport;
	}

	/**
	 * Gets maximum number of contacts allowed in the check command.
	 * 
	 * @return maximum number of contact identifiers (&lt;contact:id&gt;
	 *         elements) that can be included in a contact check command defined
	 *         in RFC 5733
	 */
	public Integer getMaxCheckContact() {
		return maxCheckContact;
	}

	/**
	 * Gets maximum number of contacts allowed in the check command.
	 * 
	 * @param maxCheckContact maximum number of contact identifiers
	 * (&lt;contact:id&gt; elements) that can be included in a contact check
	 * command defined in RFC 5733
	 */
	public void setMaxCheckContact(Integer maxCheckContact) {
		this.maxCheckContact = maxCheckContact;
	}

	/**
	 * Gets authInfo regular expression.
	 * 
	 * @return regular expression used to validate the contact object
	 *         authorization information value
	 */
	public EPPRegistryRegex getAuthInfoRegex() {
		return authInfoRegex;
	}

	/**
	 * Gets authInfo regular expression.
	 * 
	 * @param authInfoRegex
	 *           regular expression used to validate the contact object
	 *           authorization information value
	 */
	public void setAuthInfoRegex(EPPRegistryRegex authInfoRegex) {
		if (authInfoRegex != null) {
			authInfoRegex.setRootName(ELM_AUTH_INFO_REGEX);
		}

		this.authInfoRegex = authInfoRegex;
	}

	/**
	 * Gets postal-address information policy information.
	 * 
	 * @return the postal-address information policy information
	 */
	public EPPRegistryPostal getPostalInfo() {
		return postalInfo;
	}

	/**
	 * Sets postal-address information policy information.
	 * 
	 * @param postalInfo
	 *           the postal-address information policy information
	 */
	public void setPostalInfo(EPPRegistryPostal postalInfo) {
		this.postalInfo = postalInfo;
	}

	/**
	 * Gets client disclosure flag.
	 * 
	 * @return {@code true} if the server supports the client to identify
	 *         elements that require exception server-operator handling to allow
	 *         or restrict disclosure to third parties defined in RFC 5733.
	 *         {@code false} otherwise
	 */
	public Boolean getClientDisclosureSupported() {
		return clientDisclosureSupported;
	}

	/**
	 * Sets client disclosure flag.
	 * 
	 * @param clientDisclosureSupported
	 *           {@code true} if the server supports the client to identify
	 *           elements that require exception server-operator handling to
	 *           allow or restrict disclosure to third parties defined in RFC
	 *           5733. {@code false} otherwise
	 */
	public void setClientDisclosureSupported(Boolean clientDisclosureSupported) {
		this.clientDisclosureSupported = clientDisclosureSupported;
	}

	/**
	 * Gets a set of supported host statuses defined in RFC 5733.
	 * 
	 * @return set of supported host statuses defined in RFC 5733
	 */
	public EPPRegistrySupportedStatus getSupportedStatus() {
		return supportedStatus;
	}

	/**
	 * Sets a set of supported host statuses defined in RFC 5733.
	 * 
	 * @param supportedStatus
	 *           set of supported host statuses defined in RFC 5733
	 */
	public void setSupportedStatus(EPPRegistrySupportedStatus supportedStatus) {
		this.supportedStatus = supportedStatus;
	}

	/**
	 * Get the period of time a contact object is in the pending transfer before
	 * the transfer is auto approved by the server
	 * 
	 * @return instance of {@link EPPRegistryTransferHoldPeriodType}
	 */
	public EPPRegistryTransferHoldPeriodType getTransferHoldPeriod() {
		return transferHoldPeriod;
	}

	/**
	 * Set the period of time a contact object is in the pending transfer before
	 * the transfer is auto approved by the server
	 * 
	 * @param transferHoldPeriod
	 *           instance of {@link EPPRegistryTransferHoldPeriodType}
	 */
	public void setTransferHoldPeriod(EPPRegistryTransferHoldPeriodType transferHoldPeriod) {
		this.transferHoldPeriod = transferHoldPeriod;
	}

	/**
	 * Returns the XML namespace associated with the {@code EPPCodecComponent}.
	 * 
	 * @return XML namespace for the {@code EPPCodecComponent}.
	 */
	@Override
	public String getNamespace() {
		return EPPRegistryMapFactory.NS;
	}

}
