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

import org.apache.log4j.Logger;
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.EPPCatFactory;
import com.verisign.epp.util.EqualityUtil;

/**
 * This class is encoded to the &lt;loginSecPolicy:pw&gt; element that
 * represents the login password format policy. The &lt;loginSecPolicy:pw&gt;
 * element contains the following child elements:<br>
 * <ul>
 * <li>&lt;loginSecPolicy:expression&gt; - The login password format regular
 * expression.</li>
 * <li>&lt;oginSecPolicy:description&gt; - The OPTIONAL human readable
 * description of the login password format policy. The "lang" attribute MAY be
 * present to identify the language of the description if the negotiated value
 * is something other than the default value of "en" (English).</li>
 * </ul>
 */
public class EPPLoginSecPolicyPassword implements EPPCodecComponent {

	/**
	 * Logger
	 */
	private static Logger cat = Logger.getLogger(EPPLoginSecPolicyPassword.class.getName(),
	      EPPCatFactory.getInstance().getFactory());

	/**
	 * XML local name for {@code EPPLoginSecPolicyPassword}.
	 */
	public static final String ELM_LOCALNAME = "pw";

	/**
	 * XML root tag for {@code EPPLoginSecPolicyPassword}.
	 */
	public static final String ELM_NAME = EPPLoginSecPolicyExtFactory.NS_PREFIX + ":" + ELM_LOCALNAME;

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

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

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

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

	/**
	 * The login password format regular expression.
	 */
	private String expression = null;

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

	/**
	 * The OPTIONAL human readable description of the login password format
	 * policy. The "lang" attribute MAY be present to identify the language of
	 * the description if the negotiated value is something other than the
	 * default value of "en" (English).
	 */
	private String description = null;

	/**
	 * Default constructor for {@code EPPLoginSecPolicyPassword}. The expression
	 * must be set prior to calling {@link #encode(Document)}.
	 */
	public EPPLoginSecPolicyPassword() {
	}

	/**
	 * Constructor for {@code EPPLoginSecPolicyPassword} that takes the required
	 * expression attribute.
	 *
	 * @param aExpression
	 *           The login password format regular expression.
	 */
	public EPPLoginSecPolicyPassword(String aExpression) {
		this.expression = aExpression;
	}

	/**
	 * Constructor for {@code EPPLoginSecPolicyPassword} that takes all
	 * attributes.
	 *
	 * @param aExpression
	 *           The login password format regular expression.
	 * @param aLang
	 *           OPTIONAL language of the 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 password policy
	 *
	 */
	public EPPLoginSecPolicyPassword(String aExpression, String aLang, String aDescription) {
		this.expression = aExpression;
		this.setLang(aLang);
		this.description = aDescription;
	}

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

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

		// Expression
		EPPUtil.encodeString(aDocument, root, this.expression, EPPLoginSecPolicyExtFactory.NS,
		      EPPLoginSecPolicyExtFactory.NS_PREFIX + ":" + ELM_EXPRESSION);

		// Description
		if (this.hasDescription()) {
			Element theDescriptionElm = aDocument.createElementNS(EPPLoginSecPolicyExtFactory.NS,
			      EPPLoginSecPolicyExtFactory.NS_PREFIX + ":" + ELM_DESCRIPTION);

			theDescriptionElm.setAttribute(ATTR_LANG, this.lang);

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

		return root;
	}

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

		// Expression
		this.expression = EPPUtil.decodeString(aElement, EPPLoginSecPolicyExtFactory.NS, ELM_EXPRESSION);

		// Description
		Element theDescriptionElm = EPPUtil.getElementByTagNameNS(aElement, EPPLoginSecPolicyExtFactory.NS,
		      ELM_DESCRIPTION);

		if (theDescriptionElm != null) {
			// Lang
			this.setLang(EPPUtil.decodeStringAttr(theDescriptionElm, ATTR_LANG));

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

		}

	}

	/**
	 * implements a deep {@code EPPLoginSecPolicyPassword} compare.
	 *
	 * @param aObject
	 *           {@code EPPLoginSecPolicyPassword} 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 EPPLoginSecPolicyPassword)) {
			return false;
		}

		EPPLoginSecPolicyPassword theComp = (EPPLoginSecPolicyPassword) aObject;

		// Expression
		if (!EqualityUtil.equals(this.expression, theComp.expression)) {
			cat.error("EPPLoginSecPolicyPassword.equals(): expression not equal");
			return false;
		}

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

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

		return true;
	}

	/**
	 * Clone {@code EPPLoginSecPolicyPassword}.
	 *
	 * @return clone of {@code EPPLoginSecPolicyPassword}
	 *
	 * @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);
	}

	/**
	 * Gets the login password format regular expression.
	 *
	 * @return the expression if defined; {@code null} otherwise.
	 */
	public String getExpression() {
		return this.expression;
	}

	/**
	 * Sets the login password format regular expression.
	 *
	 * @param aExpression
	 *           the expression to set
	 */
	public void setExpression(String aExpression) {
		this.expression = aExpression;
	}

	/**
	 * 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 EPPLoginSecPolicyExtFactory.NS;
	}

}
