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

import java.util.ArrayList;
import java.util.List;

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.codec.registry.v02.EPPRegistryServices.EPPRegistryURI;


/**
 * Class that represents the "registry:svcExtension" element that contains a
 * list of extension namespace URIs.
 */
public class EPPRegistryServicesExt implements EPPCodecComponent {

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

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

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

  /**
   * List of {@link EPPRegistryExtURI} instances that contain the extension
   * namespace URIs
   */
  private List extURIs = new ArrayList();

  /**
   * Default constructor. At least one extension namespace URI must be defined
   * prior to calling {@link #encode(Document)}.
   */
  public EPPRegistryServicesExt() {
  }

  /**
   * Encode a DOM Element tree from the attributes of the
   * {@code EPPRegistryServicesExt} instance.
   *
   * @param aDocument
   *           DOM Document that is being built. Used as an Element factory.
   *
   * @return Element Root DOM Element representing the
   *         {@code EPPRegistryServicesExt} instance.
   *
   * @exception EPPEncodeException
   *               - Unable to encode {@code EPPRegistryServices} instance.
   */
  @Override
  public Element encode(Document aDocument) throws EPPEncodeException {
    if (this.extURIs == null || this.extURIs.size() == 0) {
      throw new EPPEncodeException("Invalid state on EPPRegistryServicesExt.encode: extURIs is required.");
    }

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

    // Extension URIs
    EPPUtil.encodeCompList(aDocument, root, this.extURIs);

    return root;
  }

  /**
   * Decode the {@code EPPRegistryServicesExt} attributes from the aElement DOM
   * Element tree.
   *
   * @param aElement
   *           Root DOM Element to decode {@code EPPRegistryServicesExt} from.
   *
   * @exception EPPDecodeException
   *               Unable to decode aElement
   */
  @Override
  public void decode(Element aElement) throws EPPDecodeException {
    // Extension URIs
    this.extURIs = EPPUtil.decodeCompList(aElement, EPPRegistryMapFactory.NS, EPPRegistryURI.ELM_EXT_URI,
          EPPRegistryExtURI.class);
  }

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

    if (this.extURIs != null) {
      clone.extURIs = (List) ((ArrayList) this.extURIs).clone();
    }

    return clone;
  }

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

    EPPRegistryServicesExt theComp = (EPPRegistryServicesExt) aObject;

    if (!((this.extURIs == null) ? (theComp.extURIs == null) : EPPUtil.equalLists(this.extURIs, theComp.extURIs))) {
      cat.error("EPPRegistryServices.equals(): extURIs not equal");
      return false;
    }

    return true;
  }

  /**
   * 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 extension namespace URIs.
   *
   * @return {@link List} of {@link EPPRegistryExtURI} instances containing the
   *         extension namespace URIs.
   */
  public List getExtURIs() {
    return this.extURIs;
  }

  /**
   * Sets the extension namespace URIs.
   *
   * @param aExtURIs
   *           {@link List} of {@link EPPRegistryExtURI} instances containing
   *           the extension namespace URIs.
   */
  public void setExtURIs(List aExtURIs) {
    if (aExtURIs == null) {
      this.extURIs = new ArrayList();
    }
    else {
      this.extURIs = aExtURIs;
    }
  }

  /**
   * Adds an extension namespace URI to the list.
   *
   * @param aURI
   *           Extension namespace URI to add to the list.
   */
  public void addExtURI(EPPRegistryExtURI aURI) {
    this.extURIs.add(aURI);
  }

  /**
   * Extension service URI that includes the URI value and a "required"
   * attribute that indicates whether use of the extension service is required.
   */
  public static class EPPRegistryExtURI extends EPPRegistryURI {

    /**
     * Default constructor. The "required" attribute must be set and the URI
     * must be set prior to calling {@link #encode(Document)}.
     */
    public EPPRegistryExtURI() {
    }

    /**
     * Constructor that takes the two required attributes for the URI and the
     * required attribute.
     *
     * @param aUri
     *           The object URI
     * @param aRequired
     *           {@code true} if the use of the extension URI is required;
     *           {@code false} otherwise.
     */
    public EPPRegistryExtURI(String aUri, Boolean aRequired) {
      super(aUri, aRequired);
    }

    /**
     * Gets the name of the root XML element.
     *
     * @return {@link #ELM_EXT_URI} for the object URI.
     */
    @Override
    public String getRootName() {
      return EPPRegistryURI.ELM_EXT_URI;
    }

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

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

  }

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

}
