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

import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import com.verisign.epp.codec.gen.EPPAuthInfo;
import com.verisign.epp.codec.gen.EPPCodecComponent;
import com.verisign.epp.codec.gen.EPPDecodeException;
import com.verisign.epp.codec.gen.EPPEncodeException;
import com.verisign.epp.codec.gen.EPPUtil;

/**
 * Represents attributes to add, remove or change with a
 * {@code EPPContactUpdateCmd}. In {@code EPPContactUpdateCmd}, an instance of
 * {@code EPPContactAddRemove} is used to specify the attributes to add, an
 * instance of {@code EPPContactAddRemove} is used to specify the attributes to
 * remove and an instance of {@code EPPContactAddRemove} is used o specify the
 * attributes to change. <br>
 * <br>
 * <br>
 * The &lt;contact:add&gt; and &lt;contact:rem&gt; elements SHALL contain the
 * following child elements: <br>
 *
 * <ul>
 * <li>One or more &lt;contact:status&gt; elements that contain status values to
 * be associated with or removed from the object. When specifying a value to be
 * removed, only the attribute value is significant; element text is not
 * required to match a value for removal.</li>
 * </ul>
 *
 * <br>
 * <br>
 * A &lt;contact:chg&gt; element SHALL contain the following OPTIONAL child
 * elements: <br>
 * <br>
 *
 * <ul>
 * <li>A &lt;contact:postalInfo&gt; element that contains the postal contacts.
 * Use {@code getPostalInfo}, {@code addPostalInfo} and {@code setPostalInfo} to
 * get, add and set the elements.</li>
 * <li>An &lt;contact:voice&gt; element that contains the contact's voice
 * telephone number. Use {@code getVoice} and {@code setVoice} to get and set
 * the elements.</li>
 * <li>An &lt;contact:fax&gt; element that contains the contact's facsimile
 * telephone number. Use {@code getFax} and {@code setFax} to get and set the
 * elements.</li>
 * <li>A &lt;contact:email&gt; element that contains the contact's e-mail
 * address. Use {@code getEmail} and {@code setEmail} to get and set the
 * elements.</li>
 * </ul>
 *
 * @see com.verisign.epp.codec.contact.EPPContactUpdateCmd
 * @see com.verisign.epp.codec.contact.EPPContactAddress
 */
public class EPPContactAddChange implements EPPCodecComponent {
	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_ADD}. This is a package constant, so the
	 * container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	/** mode of {@code EPPContactAddRemove} is not specified. */
	final static short MODE_NONE = 0;

	/** mode of {@code EPPContactAddRemove} is to add attributes. */
	final static short MODE_ADD = 1;

	/** mode of {@code EPPContactAddRemove} is to remove attributes. */
	final static short MODE_REMOVE = 2;

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_ADD}. This is a package constant, so the
	 * container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	final static String ELM_ADD = "contact:add";

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	final static String ELM_REMOVE = "contact:rem";

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	final static String ELM_CHANGE = "contact:chg";

	/** mode of {@code EPPContactAddRemove} is to change attributes. */
	final static short MODE_CHANGE = 3;

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	private final static String ELM_CONTACT_POSTAL_INFO = "contact:postalInfo";

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	private final static String ELM_CONTACT_AUTHINFO = "contact:authInfo";

	/** XML tag name for the {@code disclose} element. */
	private final static String ELM_CONTACT_DISCLOSE = "contact:disclose";

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	private final static String ELM_CONTACT_EMAIL = "contact:email";

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	private final static String ELM_CONTACT_FAX = "contact:fax";

	/**
	 * XML tag name when the {@code mode} attribute is
	 * {@code EPPContactAddRemove.MODE_REMOVE}. This is a package constant, so
	 * the container {@code EPPCodecComponent} can use it on a decode operation.
	 */
	private final static String ELM_CONTACT_VOICE = "contact:voice";

	/**
	 * XML Attribute Name for a phone extension, which applies to fax and voice
	 * numbers.
	 */
	private final static String ATTR_EXT = "x";

	/** Category for logging */
	private static Logger cat = LoggerFactory.getLogger(EPPContactAddChange.class);

	/** postal contacts */
	private java.util.Vector postalContacts = new Vector();

	/** authorization information for contact change */
	private com.verisign.epp.codec.gen.EPPAuthInfo authInfo = null;

	/** disclose information of contact */
	private com.verisign.epp.codec.contact.EPPContactDisclose disclose = null;

	/** email */
	private String email = null;

	/** fax number */
	private String fax = null;

	/** fax extension number for contact */
	private String faxExt = null;

	/** contact statuses */
	private Vector statuses = null;

	/** voice number */
	private String voice = null;

	/** voice extension number */
	private String voiceExt = null;

	/**
	 * Mode of EPPContactAddRemove. Must be {@code MODE_ADD} or
	 * {@code MODE_REMOVE} to be valid. This attribute will be set by the parent
	 * container {@code EPPCodecComponent}. For example,
	 * {@code EPPContactUpdateCmd} will set the mode for its
	 * {@code EPPContactAddRemove} instances.
	 */
	private short mode = MODE_NONE;

	/**
	 * Default constructor for {@code EPPContactAddChange}.
	 */
	public EPPContactAddChange() {
	}

	/**
	 * Constructor for {@code EPPContactAddChange}.
	 *
	 * @param newStatuses
	 *           Vector of statuses for contact add.
	 */
	public EPPContactAddChange(Vector newStatuses) {
		this.statuses = newStatuses;
	}

	/**
	 * Constructor for {@code EPPContactAddChange}.
	 *
	 * @param aPostalInfo
	 *           EPPContactPostalDefinition, defining a series objects for
	 *           contact changes.
	 * @param aVoice
	 *           Voice number
	 * @param aAuthInfo
	 *           Authorization information for contact change.
	 */
	public EPPContactAddChange(EPPContactPostalDefinition aPostalInfo, String aVoice, EPPAuthInfo aAuthInfo) {
		this.voice = aVoice;
		this.fax = null;
		this.email = null;

		addPostalInfo(aPostalInfo);
		setAuthInfo(aAuthInfo);
	}

	/**
	 * Constructor for {@code EPPContactAddChange}.
	 *
	 * @param aPostalInfo
	 *           EPPContactPostalDefinition, defining a series objects for
	 *           contact changes.
	 * @param aVoice
	 *           Voice number
	 * @param aFax
	 *           Fax number
	 * @param aEmail
	 *           Email
	 * @param aAuthInfo
	 *           Authorization information for contact change.
	 */
	public EPPContactAddChange(EPPContactPostalDefinition aPostalInfo, String aVoice, String aFax, String aEmail,
	      EPPAuthInfo aAuthInfo) {
		this.voice = aVoice;
		this.fax = aFax;
		this.email = aEmail;

		addPostalInfo(aPostalInfo);
		setAuthInfo(aAuthInfo);
	}

	/**
	 * Constructor for {@code EPPContactAddChange}.
	 *
	 * @param aPostalInfo
	 *           Vector, defining a series objects for contact changes.
	 * @param aVoice
	 *           Voice number
	 * @param aFax
	 *           Fax number
	 * @param aEmail
	 *           Email
	 * @param aAuthInfo
	 *           Authorization information for contact change.
	 */
	public EPPContactAddChange(Vector aPostalInfo, String aVoice, String aFax, String aEmail, EPPAuthInfo aAuthInfo) {
		this.voice = aVoice;
		this.fax = aFax;
		this.email = aEmail;

		setPostalInfo(aPostalInfo);
		setAuthInfo(aAuthInfo);
	}

	/**
	 * Encode a DOM Element tree from the attributes of the
	 * {@code EPPContactAddChange} instance.
	 *
	 * @param aDocument
	 *           DOM Document that is being built. Used as an Element factory.
	 *
	 * @return Root DOM Element representing the {@code EPPContactAddChange}
	 *         instance.
	 *
	 * @exception EPPEncodeException
	 *               Unable to encode {@code EPPContactAddChange} instance.
	 */
	public Element encode(Document aDocument) throws EPPEncodeException {
		Element currElm = null;
		Text currVal = null;

		Element root;

		// Add or Remove node
		if (this.mode == MODE_ADD) {
			root = aDocument.createElementNS(EPPContactMapFactory.NS, ELM_ADD);
		}
		else if (this.mode == MODE_REMOVE) {
			root = aDocument.createElementNS(EPPContactMapFactory.NS, ELM_REMOVE);
		}
		else if (this.mode == MODE_CHANGE) {
			root = aDocument.createElementNS(EPPContactMapFactory.NS, ELM_CHANGE);
		}
		else {
			throw new EPPEncodeException("Invalid EPPContactAddRemove mode of " + this.mode);
		}

		if (this.mode == MODE_CHANGE) {
			// postalInfo
			EPPUtil.encodeCompVector(aDocument, root, this.postalContacts);

			// voice
			if (this.voice != null) {
				currElm = aDocument.createElementNS(EPPContactMapFactory.NS, ELM_CONTACT_VOICE);
				currVal = aDocument.createTextNode(this.voice);

				// voiceExt
				if (this.voiceExt != null) {
					currElm.setAttribute(ATTR_EXT, this.voiceExt);
				}

				currElm.appendChild(currVal);
				root.appendChild(currElm);
			}

			// fax
			if (this.fax != null) {
				currElm = aDocument.createElementNS(EPPContactMapFactory.NS, ELM_CONTACT_FAX);
				currVal = aDocument.createTextNode(this.fax);

				// faxExt
				if (this.faxExt != null) {
					currElm.setAttribute(ATTR_EXT, this.faxExt);
				}

				currElm.appendChild(currVal);
				root.appendChild(currElm);
			}

			// email
			if (this.email != null) {
				EPPUtil.encodeString(aDocument, root, this.email, EPPContactMapFactory.NS, ELM_CONTACT_EMAIL);
			}

			// authInfo
			if (this.authInfo != null) {
				EPPUtil.encodeComp(aDocument, root, this.authInfo);
			}

			// disclose
			EPPUtil.encodeComp(aDocument, root, this.disclose);
		}
		else {
			// statuses
			if (this.statuses == null) {
				throw new EPPEncodeException("statuses required attribute is not set");
			}

			EPPUtil.encodeCompVector(aDocument, root, this.statuses);
		}

		return root;
	}

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

		if (aElement.getLocalName().equals(EPPUtil.getLocalName(ELM_ADD))) {
			this.mode = MODE_ADD;
		}
		else if (aElement.getLocalName().equals(EPPUtil.getLocalName(ELM_REMOVE))) {
			this.mode = MODE_REMOVE;
		}
		else if (aElement.getLocalName().equals(EPPUtil.getLocalName(ELM_CHANGE))) {
			this.mode = MODE_CHANGE;
		}
		else {
			throw new EPPDecodeException("Invalid EPPContactAddRemove mode of " + aElement.getLocalName());
		}

		if (this.mode == MODE_CHANGE) {
			// postalInfo
			this.postalContacts = EPPUtil.decodeCompVector(aElement, EPPContactMapFactory.NS, ELM_CONTACT_POSTAL_INFO,
			      EPPContactPostalDefinition.class);

			// voice
			this.voice = EPPUtil.decodeString(aElement, EPPContactMapFactory.NS, ELM_CONTACT_VOICE);

			// voiceExt
			if (this.voice != null) {
				currElm = EPPUtil.getElementByTagNameNS(aElement, EPPContactMapFactory.NS, ELM_CONTACT_VOICE);
				this.voiceExt = currElm.getAttribute(ATTR_EXT);

				if (this.voiceExt.length() == 0) {
					this.voiceExt = null;
				}
			}
			else {
				this.voiceExt = null;
			}

			// fax
			this.fax = EPPUtil.decodeString(aElement, EPPContactMapFactory.NS, ELM_CONTACT_FAX);

			// faxExt
			if (this.fax != null) {
				currElm = EPPUtil.getElementByTagNameNS(aElement, EPPContactMapFactory.NS, ELM_CONTACT_FAX);
				this.faxExt = currElm.getAttribute(ATTR_EXT);

				if (this.faxExt.length() == 0) {
					this.faxExt = null;
				}
			}
			else {
				this.faxExt = null;
			}

			// email
			this.email = EPPUtil.decodeString(aElement, EPPContactMapFactory.NS, ELM_CONTACT_EMAIL);

			// authInfo
			this.authInfo = (EPPAuthInfo) EPPUtil.decodeComp(aElement, EPPContactMapFactory.NS, ELM_CONTACT_AUTHINFO,
			      EPPAuthInfo.class);

			// disclose
			this.disclose = (EPPContactDisclose) EPPUtil.decodeComp(aElement, EPPContactMapFactory.NS,
			      ELM_CONTACT_DISCLOSE, EPPContactDisclose.class);
		}
		else {
			// statuses
			this.statuses = EPPUtil.decodeCompVector(aElement, EPPContactMapFactory.NS, EPPContactStatus.ELM_NAME,
			      EPPContactStatus.class);
		}
	}

	/**
	 * implements a deep {@code EPPContactAddChange} compare.
	 *
	 * @param aObject
	 *           {@code EPPContactAddChange} instance to compare with
	 *
	 * @return {@code true} if the objects are equal; {@code false} otherwise
	 */
	@Override
	public boolean equals(Object aObject) {
		cat.debug("equals(Object): enter");

		if (!(aObject instanceof EPPContactAddChange)) {
			cat.error("equals(Object): aObject not EPPContactAddChange");
			return false;
		}

		EPPContactAddChange theComp = (EPPContactAddChange) aObject;

		// Mode
		if (this.mode != theComp.mode) {
			cat.error("equals(Object): mode not equal");
			return false;
		}

		// statuses
		if (!EPPUtil.equalVectors(this.statuses, theComp.statuses)) {
			cat.error("equals(Object): statuses not equal");
			return false;
		}

		// postalContacts
		if (!EPPUtil.equalVectors(this.postalContacts, theComp.postalContacts)) {
			cat.error("equals(Object): postalContacts not equal");
			return false;
		}

		// voice
		if (!((this.voice == null) ? (theComp.voice == null) : this.voice.equals(theComp.voice))) {
			cat.error("equals(Object): voice not equal");
			return false;
		}

		// voiceExt
		if (!((this.voiceExt == null) ? (theComp.voiceExt == null) : this.voiceExt.equals(theComp.voiceExt))) {
			cat.error("equals(Object): voiceExt not equal");
			return false;
		}

		// fax
		if (!((this.fax == null) ? (theComp.fax == null) : this.fax.equals(theComp.fax))) {
			cat.error("equals(Object): fax not equal");
			return false;
		}

		// faxExt
		if (!((this.faxExt == null) ? (theComp.faxExt == null) : this.faxExt.equals(theComp.faxExt))) {
			cat.error("equals(Object): faxExt not equal");
			return false;
		}

		// email
		if (!((this.email == null) ? (theComp.email == null) : this.email.equals(theComp.email))) {
			cat.error("equals(Object): email not equal");
			return false;
		}

		// authInfo
		if (!((this.authInfo == null) ? (theComp.authInfo == null) : this.authInfo.equals(theComp.authInfo))) {
			cat.error("equals(Object): authInfo not equal");
			return false;
		}

		// disclose
		if (!((this.disclose == null) ? (theComp.disclose == null) : this.disclose.equals(theComp.disclose))) {
			cat.error("equals(Object): disclose not equal");
			return false;
		}

		return true;
	}

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

		clone = (EPPContactAddChange) super.clone();

		if (this.statuses != null) {
			clone.statuses = (Vector) this.statuses.clone();

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

		if (this.postalContacts != null) {
			clone.postalContacts = (Vector) this.postalContacts.clone();

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

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

		if (this.disclose != null) {
			clone.disclose = (EPPContactDisclose) this.disclose.clone();
		}

		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.
	 */
	@Override
	public String toString() {
		return EPPUtil.toString(this);
	}

	/**
	 * Gets the mode of {@code EPPContactAddChange}. There are two valid modes
	 * {@code EPPContactAddChange.MODE_ADD} and
	 * {@code EPPContactAddChange.MODE_REMOVE}. If no mode has been satisfied,
	 * than the mode is set to {@code EPPContactAddChange.MODE_NONE}.
	 *
	 * @return One of the {@code EPPContactAddChange_MODE} constants.
	 */
	short getMode() {
		return this.mode;
	}

	/**
	 * Sets the mode of {@code EPPContactAddChange}. There are two valid modes
	 * {@code EPPContactAddChange.MODE_ADD} and
	 * {@code EPPContactAddChange.MODE_REMOVE}. If no mode has been satisfied,
	 * than the mode is set to {@code EPPContactAddChange.MODE_NONE}
	 *
	 * @param aMode
	 *           {@code EPPContactAddChange.MODE_ADD} or
	 *           {@code EPPContactAddChange.MODE_REMOVE}.
	 */
	void setMode(short aMode) {
		this.mode = aMode;
	}

	/**
	 * Gets the postalInfo elements of contact change.
	 *
	 * @return {@code Vector} of {@code EPPContactPostalDefinition} instances
	 */
	public Vector getPostalInfo() {
		return this.postalContacts;
	}

	/**
	 * Sets list of contact postal information.
	 *
	 * @param aPostalContacts
	 *           java.util.Vector of {@link EPPContactPostalDefinition}
	 *           instances. If {@code null}, the list will be reset.
	 */
	public void setPostalInfo(Vector aPostalContacts) {
		this.postalContacts = new Vector();

		if (aPostalContacts != null) {
			for (int i = 0; i < aPostalContacts.size(); i++) {
				if (aPostalContacts.elementAt(i) != null) {
					addPostalInfo((EPPContactPostalDefinition) aPostalContacts.elementAt(i));
				}
			}
		}

	}

	/**
	 * Adds contact postalInfo.
	 *
	 * @param aPostalInfo
	 *           Postal information to add
	 */
	public void addPostalInfo(EPPContactPostalDefinition aPostalInfo) {
		// clone necessary here
		EPPContactPostalDefinition thePostalInfo = null;

		if (aPostalInfo != null) {
			try {
				thePostalInfo = (EPPContactPostalDefinition) aPostalInfo.clone();
			}
			catch (CloneNotSupportedException e) {
				// Nothing needs to be done here
			}

			// postalInfo = aPostalInfo;
			// postalInfo.setRootName(EPPContactPostalDefinition.ELM_NAME_POSTAL_INFO);
			aPostalInfo.setValidatedFlag(false);
			this.postalContacts.add(aPostalInfo);
		}
	}

	/**
	 * Returns {@code true} if auth info exists.
	 *
	 * @return {@code true} if auth info exists; otherwise {@code false}.
	 */
	public boolean hasAuthInfo() {
		return (this.authInfo != null);
	}

	/**
	 * Get authorization information for contact change.
	 *
	 * @return The authorization information is set; {@code null} otherwise
	 */
	public EPPAuthInfo getAuthInfo() {
		return this.authInfo;
	}

	/**
	 * Set authorization information for contact change.
	 *
	 * @param aAuthInfo
	 *           Authorization information to set. The
	 */
	public void setAuthInfo(EPPAuthInfo aAuthInfo) {
		this.authInfo = aAuthInfo;
		if (aAuthInfo != null) {
			this.authInfo.setRootName(EPPContactMapFactory.NS, ELM_CONTACT_AUTHINFO);
		}
	}

	/**
	 * Returns {@code true} if disclose exists.
	 *
	 * @return {@code true} if disclose exists; otherwise {@code false}.
	 */
	public boolean hasDisclose() {
		return (this.disclose != null);
	}

	/**
	 * Get disclose information.
	 *
	 * @return Disclose information if defined; {@code null} otherwise;
	 */
	public EPPContactDisclose getDisclose() {
		return this.disclose;
	}

	/**
	 * Sets the disclose information.
	 *
	 * @param aDisclose
	 *           Disclose information to set.
	 */
	public void setDisclose(EPPContactDisclose aDisclose) {
		this.disclose = aDisclose;
		if (aDisclose != null) {
			this.disclose.setRootName(ELM_CONTACT_DISCLOSE);
		}
	}

	/**
	 * Returns {@code true} if email exists.
	 *
	 * @return {@code true} if email exists; otherwise {@code false}.
	 */
	public boolean hasEmail() {
		return (this.email != null);
	}

	/**
	 * Gets email.
	 *
	 * @return Email if set; {@code null} otherwise
	 */
	public String getEmail() {
		return this.email;
	}

	/**
	 * Sets the email.
	 *
	 * @param aEmail
	 *           Email to set
	 */
	public void setEmail(String aEmail) {
		this.email = aEmail;
	}

	/**
	 * Returns {@code true} if fax exists.
	 *
	 * @return {@code true} if fax exists; otherwise {@code false}.
	 */
	public boolean hasFax() {
		return (this.fax != null);
	}

	/**
	 * Get fax number.
	 *
	 * @return String fax number
	 */
	public String getFax() {
		return this.fax;
	}

	/**
	 * Sets the fax number.
	 *
	 * @param aFax
	 *           Fax number to set
	 */
	public void setFax(String aFax) {
		this.fax = aFax;
	}

	/**
	 * Returns {@code true} if fax extension exists.
	 *
	 * @return {@code true} if fax extension exists; otherwise {@code false}.
	 */
	public boolean hasFaxExt() {
		return (this.faxExt != null);
	}

	/**
	 * Gets the fax extension.
	 *
	 * @return fax extension if defined; {@code null} otherwise.
	 */
	public String getFaxExt() {
		return this.faxExt;
	}

	/**
	 * Sets the fax extension.
	 *
	 * @param aFaxExt
	 *           Fax extension
	 */
	public void setFaxExt(String aFaxExt) {
		this.faxExt = aFaxExt;
	}

	/**
	 * Returns {@code true} if statuses exist.
	 *
	 * @return {@code true} if statuses exist; otherwise {@code false}.
	 */
	public boolean hasStatuses() {
		return (this.statuses != null);
	}

	/**
	 * Get a list of contact statuses.
	 *
	 * @return Contact statuses if defined; {@code null} otherwise
	 */
	public Vector getStatuses() {
		return this.statuses;
	}

	/**
	 * Sets the list of contact statuses.
	 *
	 * @param aStatuses
	 *           List of contact statuses
	 */
	public void setStatuses(Vector aStatuses) {
		this.statuses = aStatuses;
	}

	/**
	 * Returns {@code true} if voice exists.
	 *
	 * @return {@code true} if voice exists; otherwise {@code false}.
	 */
	public boolean hasVoice() {
		return (this.voice != null);
	}

	/**
	 * Get voice number.
	 *
	 * @return String fax number
	 */
	public String getVoice() {
		return this.voice;
	}

	/**
	 * Sets the voice number.
	 *
	 * @param aVoice
	 *           The voice number to set
	 */
	public void setVoice(String aVoice) {
		this.voice = aVoice;
	}

	/**
	 * Returns {@code true} if voice extension exists.
	 *
	 * @return {@code true} if voice extension exists; otherwise {@code false}.
	 */
	public boolean hasVoiceExt() {
		return (this.voiceExt != null);
	}

	/**
	 * Get voice number extension.
	 *
	 * @return Voice number extension if defined; {@code null} otherwise.
	 */
	public String getVoiceExt() {
		return this.voiceExt;
	}

	/**
	 * Sets the contact voice extension.
	 *
	 * @param aVoiceExt
	 *           voice extension
	 */
	public void setVoiceExt(String aVoiceExt) {
		this.voiceExt = aVoiceExt;
	}

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

}
