/***********************************************************
Copyright (C) 2024 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.addlemail;

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;

/**
 * A second email can be set using the {@code EPPEAIEmail} extension with the
 * option for defining the "primary" attribute to indicate that the extension
 * email should be treated as the primary email address.
 */
public class EPPAddlEmail implements EPPCodecComponent {

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

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

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

  /**
   * XML local name for the email
   */
  private static final String ELM_EMAIL = "email";

  /**
   * Primary attribute name
   */
  private static final String ATTR_PRIMARY = "primary";

  /**
   * Second email address
   */
  private String email;

  /**
   * Is the second email the primary email?
   */
  private boolean primary = false;

  /**
   * Default constructor for {@code EPPEAIEmail}.
   */
  public EPPAddlEmail() {
    this.email = null;
  }

  /**
   * Constructor for {@code EPPEAIEmail} that takes the second email value.
   *
   * @param aEmail
   *           Second email. Set to {@code null} to explicitly indicate that
   *           there is no second email.
   */
  public EPPAddlEmail(String aEmail) {
    this.email = aEmail;
  }

  /**
   * Constructor for {@code EPPEAIEmail} that takes the second email value.
   *
   * @param aEmail
   *           Second email. Set to {@code null} to explicitly indicate that
   *           there is no second email.
   * @param aPrimary
   *           Is the second email the primary email?
   * 
   */
  public EPPAddlEmail(String aEmail, boolean aPrimary) {
    this.email = aEmail;
    this.primary = aPrimary;
  }

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

  /**
   * Gets the second email value.
   *
   * @return second email value if defined; {@code null} otherwise.
   */
  public String getEmail() {
    return this.email;
  }

  /**
   * Sets the second email value.
   *
   * @param aEmail
   *           Second email. Set to {@code null} to explicitly indicate that
   *           there is no second email.
   */
  public void setEmail(String aEmail) {
    this.email = aEmail;
  }

  /**
   * Is the second email the primary email? The default value is {@code false}.
   * 
   * @return {@code true} if the second email is the primary email;
   *         {@code false} otherwise.
   */
  public boolean isPrimary() {
    return primary;
  }

  /**
   * Sets the primary attribute for the second email.
   * 
   * @param aPrimary
   *           Set to {@code true} if the second email is the primary email;
   *           {@code false} otherwise.
   */
  public void setPrimary(boolean aPrimary) {
    this.primary = aPrimary;
  }

  /**
   * encode instance into a DOM element tree. A DOM Document is passed as an
   * argument and functions as a factory for DOM objects. The root element
   * associated with the instance is created and each instance attribute is
   * appended as a child node.
   *
   * @param aDocument
   *           DOM Document, which acts is an Element factory
   *
   * @return Element Root element associated with the object
   *
   * @exception EPPEncodeException
   *               Error encoding {@code EPPEAIEmail}
   */
  @Override
  public Element encode(Document aDocument) throws EPPEncodeException {

    // Create root element
    Element root = aDocument.createElementNS(EPPAddlEmailExtFactory.NS, ELM_NAME);

    // Email
    Element theEmailElm = aDocument.createElementNS(EPPAddlEmailExtFactory.NS,
          EPPAddlEmailExtFactory.NS_PREFIX + ":" + ELM_EMAIL);
    root.appendChild(theEmailElm);

    if (this.email != null) {
      Text theEmailVal = aDocument.createTextNode(this.email);
      theEmailElm.appendChild(theEmailVal);
    }

    // Primary
    EPPUtil.encodeBooleanAttr(theEmailElm, ATTR_PRIMARY, this.primary);

    return root;
  }

  /**
   * decode a DOM element tree to initialize the instance attributes. The
   * {@code aElement} argument represents the root DOM element and is used to
   * traverse the DOM nodes for instance attribute values.
   *
   * @param aElement
   *           {@code Element} to decode
   *
   * @exception EPPDecodeException
   *               Error decoding {@code Element}
   */
  @Override
  public void decode(Element aElement) throws EPPDecodeException {

    // Email
    Element theEmailElm = EPPUtil.getElementByTagNameNS(aElement, EPPAddlEmailExtFactory.NS, ELM_EMAIL);
    if (theEmailElm == null) {
      throw new EPPDecodeException("addrEmail element must have a child email element");
    }
    
    this.email = EPPUtil.decodeStringValue(theEmailElm);

    if (this.email != null && this.email.isEmpty()) {
      this.email = null;
    }

    // Primary
    if (theEmailElm.getAttribute(ATTR_PRIMARY) != null) {
      this.primary = EPPUtil.decodeBooleanAttr(theEmailElm, ATTR_PRIMARY);
    }
  }

  /**
   * clone an {@code EPPCodecComponent}.
   *
   * @return clone of concrete {@code EPPEAIEmail}
   *
   * @exception CloneNotSupportedException
   *               standard Object.clone exception
   */
  @Override
  public Object clone() throws CloneNotSupportedException {
    EPPAddlEmail clone = (EPPAddlEmail) super.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);
  }

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

    EPPAddlEmail theComp = (EPPAddlEmail) aObject;

    // Email
    if (!EqualityUtil.equals(this.email, theComp.email)) {
      cat.error("EPPEAIEmail.equals(): email not equal");
      return false;
    }

    // Primary
    if (this.primary != theComp.primary) {
      cat.error("EPPEAIEmail.equals(): primary not equal");
      return false;
    }

    return true;
  }

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

}
