/***********************************************************
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-1307 USA

http://www.verisign.com/nds/naming/namestore/techdocs.html
 ***********************************************************/
package com.verisign.epp.codec.launchpolicy.v01;

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.EPPCodecComponent;
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;

/**
 * {@code EPPLaunchPolicyPhaseStatus} defines a supported launch status value.
 * The {@link Status} enumeration includes the possible set of status values
 * with the optional name attribute used when the status is
 * {@link Status#custom}.
 */
public class EPPLaunchPolicyPhaseStatus implements EPPCodecComponent {

	/**
	 * Logger
	 */
	    private static Logger cat = LoggerFactory.getLogger(EPPLaunchPolicyPhaseStatus.class);
	      

	/**
	 * Possible launch phase statuses used by the {@code statuses} attribute.
	 */
	public static enum Status implements java.io.Serializable,Cloneable {
		/**
		 * The initial state of a newly-created application or registration
		 * object.
		 */
		pendingValidation,

		/**
		 * The application or registration meets relevant registry rules.
		 */
		validated,
		/**
		 * The application or registration does not validate according to registry
		 * rules.
		 */
		invalid,
		/**
		 * The allocation of the application or registration is pending based on
		 * the results of some out- of-band process (for example, an auction).
		 */
		pendingAllocation,

		/**
		 * The object corresponding to the application or registration has been
		 * provisioned.
		 */
		allocated,
		/**
		 * The application or registration object was not provisioned.
		 */
		rejected,
		/**
		 * A custom status that is defined using the "name" attribute.
		 */
		custom
	}

	/**
	 * Default root element local name
	 */
	public static final String ELM_LOCALNAME = "status";

	/**
	 * Default Language -- English "en"
	 */
	public final static java.lang.String DEFAULT_LANG = "en";

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

	/**
	 * XML attribute name used for the {@code status} attribute.
	 */
	public static final String ATTR_STATUS = "s";

	/**
	 * XML attribute name used for the OPTIONAL {@code name} attribute.
	 */
	public static final String ATTR_NAME = "name";

	/**
	 * XML attribute name used for the OPTIONAL {@code lang} attribute.
	 */
	public static final String ATTR_LANG = "lang";

	/**
	 * Status value
	 */
	private Status status;

	/**
	 * OPTIONAL "name" attribute that can define a custom status name when the
	 * status has the {@link Status#custom} value.
	 */
	private String name;

	/**
	 * Language of the description with the default of {@link #DEFAULT_LANG}.
	 */
	private java.lang.String lang = DEFAULT_LANG;

	/**
	 * OPTIONAL Description of the status rationale
	 */
	private String description = null;

	/**
	 * Default constructor for {@code EPPLaunchPolicyPhaseStatus}. The
	 * {@code status} attribute must be set.
	 */
	public EPPLaunchPolicyPhaseStatus() {
	}

	/**
	 * {@code EPPLaunchPolicyPhaseStatus} constructor that takes the required
	 * {@code status} attribute value.
	 * 
	 * @param aStatus
	 *           Launch phase status value
	 */
	public EPPLaunchPolicyPhaseStatus(Status aStatus) {
		this.status = aStatus;
	}

	/**
	 * {@code EPPLaunchPolicyPhaseStatus} constructor that takes the required
	 * {@code status} attribute value along with a custom name attribute.
	 * 
	 * @param aStatus
	 *           Launch phase status value
	 * @param aName
	 *           Custom status name. Set to {@code null} if undefined.
	 */
	public EPPLaunchPolicyPhaseStatus(Status aStatus, String aName) {
		this.status = aStatus;
		this.name = aName;
	}

	/**
	 * {@code EPPLaunchPolicyPhaseStatus} constructor that takes attribute
	 * values.
	 *
	 * @param aStatus
	 *           Phase status value
	 * @param aName
	 *           OPTIONAL custom status name. Set to {@code null} if undefined.
	 * @param aLang
	 *           OPTIONAL language of the status description with a default of
	 *           {@link #DEFAULT_LANG}. Set to {@link #DEFAULT_LANG} or
	 *           {@code null} to use the default value.
	 * @param aDescription
	 *           Description of the status rationale
	 */
	public EPPLaunchPolicyPhaseStatus(Status aStatus, String aName, String aLang, String aDescription) {
		this.status = aStatus;
		this.name = aName;
		this.setLang(aLang);
		this.description = aDescription;
	}

	/**
	 * Gets the root element local name.
	 *
	 * @return Root element local name.
	 */
	protected String getRootName() {
		return ELM_LOCALNAME;
	}

	/**
	 * Encode a DOM Element tree from the attributes of the
	 * {@code EPPLaunchPolicyPhaseStatus} instance.
	 *
	 * @param aDocument
	 *           DOM Document that is being built. Used as an Element factory.
	 *
	 * @return Element Root DOM Element representing the
	 *         {@code EPPLaunchPolicyPhaseStatus} instance.
	 *
	 * @exception EPPEncodeException
	 *               - Unable to encode {@code EPPLaunchPolicyPhaseStatus}
	 *               instance.
	 */
	@Override
	public Element encode(Document aDocument) throws EPPEncodeException {
		if (!this.hasStatus()) {
			throw new EPPEncodeException("status is null in EPPLaunchPolicyPhaseStatus.encode(Document).");
		}

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

		// Status
		root.setAttribute(ATTR_STATUS, this.status.toString());

		// Name
		if (this.hasName()) {
			root.setAttribute(ATTR_NAME, this.name);
		}

		// Description
		if (this.hasDescription()) {
			root.setAttribute(ATTR_LANG, this.lang);

			Text theDescText = aDocument.createTextNode(this.description);
			root.appendChild(theDescText);
		}

		return root;
	}

	/**
	 * Decode the {@code EPPLaunchPolicyPhaseStatus} attributes from the aElement
	 * DOM Element tree.
	 *
	 * @param aElement
	 *           Root DOM Element to decode {@code EPPLaunchPolicyPhaseStatus}
	 *           from.
	 *
	 * @exception EPPDecodeException
	 *               Unable to decode aElement
	 */
	@Override
	public void decode(Element aElement) throws EPPDecodeException {
		// Status
		this.status = Status.valueOf(aElement.getAttribute(ATTR_STATUS));

		// Name
		this.name = EPPUtil.decodeStringAttr(aElement, ATTR_NAME);

		// Lang
		this.setLang(EPPUtil.decodeStringAttr(aElement, ATTR_LANG));

		// Description
		this.description = EPPUtil.getTextContent(aElement, true);
		if (this.description != null && this.description.isEmpty()) {
			this.description = null;
		}
	}

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

		EPPLaunchPolicyPhaseStatus theComp = (EPPLaunchPolicyPhaseStatus) aObject;

		// Status
		if (!EqualityUtil.equals(this.status, theComp.status)) {
			cat.error("EPPLaunchPolicyPhaseStatus.equals(): status not equal");
			return false;
		}

		// Name
		if (!EqualityUtil.equals(this.name, theComp.name)) {
			cat.error("EPPLaunchPolicyPhaseStatus.equals(): name not equal");
			return false;
		}

		// Lang
		if (!EqualityUtil.equals(this.lang, theComp.lang)) {
			cat.error("EPPLaunchPolicyPhaseStatus.equals(): lang not equal");
			return false;
		}

		// Description
		if (!EqualityUtil.equals(this.description, theComp.description)) {
			cat.error("EPPLaunchPolicyPhaseStatus.equals(): description not equal");
			return false;
		}

		return true;
	}

	/**
	 * Clone {@code EPPLaunchPolicyPhaseStatus}.
	 *
	 * @return clone of {@code EPPLaunchPolicyPhaseStatus}
	 *
	 * @exception CloneNotSupportedException
	 *               standard Object.clone exception
	 */
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.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);
	}

	/**
	 * Is the status value defined?
	 *
	 * @return {@code true} if the status is defined; {@code false} otherwise.
	 */
	public boolean hasStatus() {
		return (this.status != null ? true : false);
	}

	/**
	 * Gets the phase status value.
	 *
	 * @return Phase status value if defined; {@code null} otherwise.
	 */
	public Status getStatus() {
		return this.status;
	}

	/**
	 * Sets the phase status value.
	 *
	 * @param aStatus
	 *           The phase status value.
	 */
	public void setStatus(Status aStatus) {
		this.status = aStatus;
	}

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

	/**
	 * Gets the OPTIONAL custom status name.
	 *
	 * @return The custom phase name if defined; {@code null} otherwise.
	 */
	public String getName() {
		return this.name;
	}

	/**
	 * Sets the OPTIONAL custom status name.
	 *
	 * @param aName
	 *           Custom status name
	 */
	public void setName(String aName) {
		this.name = aName;
	}

	/**
	 * Gets the language of the status description with the default set to
	 * {@link #DEFAULT_LANG}.
	 *
	 * @return Language of description with the default value of
	 *         {@link #DEFAULT_LANG}.
	 */
	public String getLang() {
		return this.lang;
	}

	/**
	 * Sets the language of the status description with the default set to
	 * {@link #DEFAULT_LANG}.
	 *
	 * @param aLang
	 *           Language of description. If set to {@code null}, the value will
	 *           be set to the default of {@link #DEFAULT_LANG}.
	 */
	public void setLang(String aLang) {
		if (aLang == null) {
			this.lang = DEFAULT_LANG;
		}
		else {
			this.lang = aLang;
		}
	}

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

	/**
	 * Gets the status description, which is free form text describing the
	 * rationale for the status.
	 *
	 * @return Status description if defined; {@code null} otherwise.
	 */
	public String getDescription() {
		return this.description;
	}

	/**
	 * Sets the status description, which is free form text describing the
	 * rationale for the status.
	 *
	 * @param aDesc
	 *           Status description. Set to {@code null} if undefined.
	 */
	public void setDescription(String aDesc) {
		this.description = aDesc;
	}

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