/***********************************************************
Copyright (C) 2021 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.maintenance.v1_0;

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

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;

/**
 * Server unique id for the maintenance with an optional human-readable
 * description of the maintenance.
 */
public class EPPMaintenanceId implements EPPCodecComponent {

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

  /** XML Element Local Name of {@code EPPMaintenenceId} root element. */
  final static String ELM_LOCALNAME = "id";

  /** Default lang value **/
  private static final String DEFAULT_LANG = "en";

  /** XML Element Name of {@code EPPMaintenenceId} root element. */
  public static final String ELM_NAME = EPPMaintenanceMapFactory.NS_PREFIX + ":" + ELM_LOCALNAME;

  /**
   * XML attribute for the name attribute.
   */
  private static final String ATTR_NAME = "name";

  /**
   * XML attribute for the lang attribute.
   */
  private static final String ATTR_LANG = "lang";

  /**
   * Maintenance id value.
   */
  private String id;

  /**
   * Optional name that includes a human-readable name of the maintenance.
   */
  private String name = null;

  /**
   * OPTIONAL language of the name.
   */
  private String nameLang = DEFAULT_LANG;

  /**
   * Default constructor for {@code EPPMaintenenceId}. The id attribute must be
   * set using {@code setId} before invoking {@link #encode(Document)}.
   */
  public EPPMaintenanceId() {
  }

  /**
   * Constructor for {@code EPPMaintenenceId} that the takes the required id
   * value.
   *
   * @param aId
   *           Id value for the maintenance
   */
  public EPPMaintenanceId(String aId) {
    this.id = aId;
  }

  /**
   * Constructor for {@code EPPMaintenenceId} that takes all attributes.
   *
   * @param aId
   *           Id value for the maintenance
   * @param aName
   *           Optional id description that provides a human-readable
   *           description of the maintenance. Set to {@code null} to undefine.
   * @param aNameLang
   *           Optional id description language. Set to {@code null} to
   *           undefine.
   *
   */
  public EPPMaintenanceId(String aId, String aName, String aNameLang) {
    this.id = aId;
    this.name = aName;
    this.setNameLang(aNameLang);
  }

  /**
   * Gets the id value of the maintenance.
   *
   * @return Maintenance id value if defined; {@code null} otherwise.
   */
  public String getId() {
    return this.id;
  }

  /**
   * Sets the id value of the maintenance.
   *
   * @param aId
   *           Id value of the maintenance
   */
  public void getId(String aId) {
    this.id = aId;
  }

  /**
   * 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 human-readable name of the maintenance.
   *
   * @return The human-readable name of the maintenance if defined;
   *         {@code null} otherwise.
   */
  public String getName() {
    return this.name;
  }

  /**
   * Sets the human-readable name of the maintenance without having to
   * create an external resource.
   *
   * @param aName
   *           Free-form name of the maintenance without having to
   *           create an external resource.
   */
  public void setName(String aName) {
    this.name = aName;
  }

  /**
   * Is the name language defined with a non-default value?
   *
   * @return <code>true</code> if the name language is defined;
   *         <code>false</code> otherwise.
   */
  public boolean hasNameLang() {
    return (!this.nameLang.equals(DEFAULT_LANG) ? true : false);
  }

  /**
   * Gets the name language value.
   *
   * @return Name language if defined; <code>DEFAULT_LANG</code>
   *         otherwise.
   */
  public String getNameLang() {
    return this.nameLang;
  }

  /**
   * Sets the name language value.
   *
   * @param aNameLang
   *           Name language.
   */
  public void setNameLang(String aNameLang) {
    if (aNameLang == null) {
      this.nameLang = DEFAULT_LANG;
    }
    else {
      this.nameLang = aNameLang;
    }
  }

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

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

    // id
    root.appendChild(aDocument.createTextNode(this.id));

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

      // lang
      if (this.hasNameLang()) {
        root.setAttribute(ATTR_LANG, this.nameLang);
      }
    }

    return root;
  }

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

    // id
    this.id = EPPUtil.decodeStringValue(aElement);

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

    // lang
    this.setNameLang(EPPUtil.decodeStringAttr(aElement, ATTR_LANG));
  }

  /**
   * implements a deep {@code EPPMaintenenceId} compare.
   *
   * @param aObject
   *           {@code EPPMaintenenceId} instance to compare with
   *
   * @return {@code true} if {@code aObject} is equal; {@code false} otherwise.
   */
  @Override
  public boolean equals(Object aObject) {
    if (!(aObject instanceof EPPMaintenanceId)) {
      return false;
    }

    EPPMaintenanceId theComp = (EPPMaintenanceId) aObject;

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

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

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

    return true;
  }

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

    clone = (EPPMaintenanceId) 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);
  }

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

}
