//______________________________________________________________________________
//   |       |
//   | knipp |           Knipp Medien und Kommunikation GmbH
//    -------
//
//
//     Knipp RRI Toolkit
//
//
//     Copyright (C) 2005 by Knipp Medien und Kommunikation GmbH
//
//     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 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 
//
//
//     initial author:    Klaus Malorny
//
//     version:           1.3 (15112), 2011/05/27 16:00:14
//                        $Revision: 15112 $ 
//                        $Date: 2011-05-27 15:48:22 +0200 (Fri, 27 May 2011) $
//                        $Author: Klaus.Malorny $
//

package de.knipp.rritoolkit.dns;

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;

import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.DOMException;

import de.knipp.rritoolkit.KVList;
import de.knipp.rritoolkit.XmlBuilder;
import de.knipp.rritoolkit.ResponseParseException;
import de.knipp.rritoolkit.EncodeException;

import static de.knipp.rritoolkit.DenicConstants.NS_DNS_ENTRY;
import static de.knipp.rritoolkit.DenicConstants.NS_XSI;
import static de.knipp.rritoolkit.DenicConstants.PREFIX_DNS_ENTRY;
import static de.knipp.rritoolkit.DenicConstants.PREFIX_XSI;

import static de.knipp.rritoolkit.XmlHelper.getElements;
import static de.knipp.rritoolkit.XmlHelper.getFirstElement;
import static de.knipp.rritoolkit.XmlHelper.getFirstElementText;




/**
 *  class that stores the name server information. Although it is named "NS",
 *  it actually represents both the NS record and the glue records (A or AAAA)
 *
 *  @version  $Revision: 15112 $
 *  @author   Klaus Malorny
 */

public class DnsEntryNS extends DnsEntry
{
  /** the name server name */
  
  private String nsName;
  
  
  /** the list of IPv4 addresses */
  
  private List<String> addrsIPv4;


  /** the list of IPv6 addresses */

  private List<String> addrsIPv6;
  
  




  
  /**
   *  constructor
   *
   *  @param name                     the name of the name server
   *  @param addrs                    the IP addresses
   */
  
  public DnsEntryNS (String name, String... addrs)
  {
    nsName = name;
    addrsIPv4 = new ArrayList<String> ();
    addrsIPv6 = new ArrayList<String> ();

    for (String addr: addrs)
      if (isIPv6 (addr))
        addrsIPv6.add (addr);
       else
        addrsIPv4.add (addr);
  }


  /**
   *  constructor
   *
   *  @param name                     the name of the name server
   *  @param addrs                    the IP addresses
   */

  public DnsEntryNS (String name, List<String> addrs)
  {
    nsName = name;
    addrsIPv4 = new ArrayList<String> ();
    addrsIPv6 = new ArrayList<String> ();

    for (String addr: addrs)
      if (isIPv6 (addr))
        addrsIPv6.add (addr);
       else
        addrsIPv4.add (addr);
  }


  /**
   *  constructor
   *
   *  @param name                      the name of the name server
   *  @param ipv4                      the IPv4 addresses
   *  @param ipv6                      the IPv6 addresses
   */

  public DnsEntryNS (String name, String[] ipv4, String[] ipv6)
  {
    nsName = name;
    addrsIPv4 = new ArrayList<String> ();
    addrsIPv6 = new ArrayList<String> ();

    for (String addr: ipv4)
      addrsIPv4.add (addr);

    for (String addr: ipv6)
      addrsIPv6.add (addr);
  }

  
  /**
   *  constructor
   *
   *  @param name                      the name of the name server
   *  @param ipv4                      the IPv4 addresses
   *  @param ipv6                      the IPv6 addresses
   */

  public DnsEntryNS (String name, Collection<String> ipv4,
    Collection<String> ipv6)
  {
    nsName = name;
    addrsIPv4 = new ArrayList<String> (ipv4);
    addrsIPv6 = new ArrayList<String> (ipv6);
  }



  
  /**
   *  constructor
   *
   *  @param encodedDomainName        the encoded domain name
   *  @param name                     the name server
   *  @param ips                      the mixed list of IPv4 and IPv6 addresses
   *  @throws ResponseParseException  on syntactical errors
   */
  
  protected DnsEntryNS (String encodedDomainName, String name, List<String> ips)
    throws ResponseParseException
  {
    nsName = name;

    if (ips.isEmpty ())
    {
      addrsIPv4 = Collections.emptyList ();
      addrsIPv6 = Collections.emptyList ();

    } else
    {
      addrsIPv4 = new ArrayList<String> ();
      addrsIPv6 = new ArrayList<String> ();

      for (String addr: ips)
      {
        if (isIPv6 (addr))
          addrsIPv6.add (addr);
         else
          addrsIPv4.add (addr);
      }
    }
    
    setOwner (encodedDomainName);
  }

  
  
  /**
   *  constructor
   *
   *  @param el                       the element
   *  @throws DOMException            on DOM exceptions
   *  @throws ResponseParseException  on wrong content
   */
  
  protected DnsEntryNS (Element el)
    throws DOMException, ResponseParseException
  {
    String owner = getFirstElementText (el, NS_DNS_ENTRY, "owner");
    
    if (owner == null)
      throw new ResponseParseException ("missing <owner> element", el);
    
    Element rdata = getFirstElement (el, NS_DNS_ENTRY, "rdata");
    
    if (rdata == null)
      throw new ResponseParseException ("missing <rdata> element", el);
    
    nsName = getFirstElementText (rdata, NS_DNS_ENTRY, "nameserver");
    
    if (nsName == null)
      throw new ResponseParseException ("missing <nameserver> element", rdata);
    
    List<Element> list = getElements (rdata, NS_DNS_ENTRY, "address");

    if (!list.isEmpty ())
    {
      addrsIPv4 = new ArrayList <String> ();
      for (Element temp: list) addrsIPv4.add (temp.getTextContent ());
      
    } else
    {
      addrsIPv4 = Collections.emptyList ();
    }

    list = getElements (rdata, NS_DNS_ENTRY, "addressV6");

    if (!list.isEmpty ())
    {
      addrsIPv6 = new ArrayList<String> ();
      for (Element temp: list) addrsIPv6.add (temp.getTextContent ());

    } else
    {
      addrsIPv6 = Collections.emptyList ();
    }
  }
  

  

  
  /**
   *  convert the instance to an entry in the given list
   *
   *  @param list                     the list
   *  @throws EncodeException         if the encoding fails
   */

  @Override
  public void toList (KVList list)
    throws EncodeException
  {
    if (addrsIPv4.isEmpty () && addrsIPv6.isEmpty ())
    {
      list.add ("nserver", nsName);

    } else
    {
      for (String addr: addrsIPv4)
        list.add ("nserver", nsName + " " + addr);

      for (String addr: addrsIPv6)
        list.add ("nserver", nsName + " " + addr);
    }
  }
  
  
  
  /**
   *  convert the instance to XML
   *
   *  @param node                     the node to append to
   *  @param encodedDomainName        the encoded domain name from the domain
   *                                  info data
   *  @throws DOMException            on DOM exceptions
   *  @throws EncodeException         if the encoding fails
   */

  @Override
  public void toXml (Node node, String encodedDomainName)
    throws DOMException, EncodeException
  {
    XmlBuilder xb = new XmlBuilder (node);
    
    xb.es (NS_DNS_ENTRY, PREFIX_DNS_ENTRY, "dnsentry");
    
    Node current = xb.getCurrent ();
    String prefix = current.getPrefix ();
    
    xb.attr (NS_XSI, PREFIX_XSI, "type", 
      prefix != null && prefix.length () > 0 ? prefix + ":NS" : "NS");
    
    xb.elt (NS_DNS_ENTRY, PREFIX_DNS_ENTRY, "owner", getOwner () == null ? 
      encodedDomainName : getOwner ());
      
    xb.es (NS_DNS_ENTRY, PREFIX_DNS_ENTRY, "rdata");
    xb.elt (NS_DNS_ENTRY, "nameserver", nsName);
    
    for (String addr: addrsIPv4)
      xb.elt (NS_DNS_ENTRY, PREFIX_DNS_ENTRY, "address", addr);

    for (String addr: addrsIPv6)
      xb.elt (NS_DNS_ENTRY, PREFIX_DNS_ENTRY, "addressV6", addr);

    xb.ee ().ee ();
  }
  
  
  /**
   *  accept the given visitor
   *
   *  @param visitor                  the visitor
   */

  @Override
  public void accept (DnsEntryVisitor visitor)
  {
    visitor.visit (this);
  }
  

  

 
  /**
   *  create a clone of this instance.
   *
   *  @return                         the clone
   */

  @Override
  public DnsEntryNS clone ()
  {
    DnsEntryNS copy = (DnsEntryNS) super.clone ();
    copy.addrsIPv4 = new ArrayList<String> (addrsIPv4);
    copy.addrsIPv6 = new ArrayList<String> (addrsIPv6);
    return copy;
  }
  
  
  
  /**
   *  create a string representation (for debugging purposes)
   *
   *  @return                    the string representation
   */

  @Override
  public String toString ()
  {
    StringBuilder sb = new StringBuilder ();
    sb.append ("name server ");
    sb.append (nsName);
    
    if (!addrsIPv4.isEmpty () || !addrsIPv6.isEmpty ())
    {
      sb.append (" (");
      boolean first = true;
      
      for (String addr: addrsIPv4)
      {
        if (first)
          first = false;
         else
          sb.append (", ");
        
        sb.append (addr);
      }

      for (String addr: addrsIPv6)
      {
        if (first)
          first = false;
         else
          sb.append (", ");

        sb.append (addr);
      }
      
      sb.append (")");
    }
    
    return sb.toString ();
  }

  
  
  //--- access methods ---------------------------------------------------------
  
  /**
   *  return the list of addresses assigned to the name server
   *
   *  @return                the list
   */
  
  public List<String> getAddresses ()
  {
    List<String> all = new ArrayList<String> ();
    all.addAll (addrsIPv4);
    all.addAll (addrsIPv6);
    return Collections.unmodifiableList (all);
  }
  

  /**
   *  return the list of IPv4 addresses assigned to the name server
   * 
   *  @return               the list
   */

  public List<String> getIPv4Addresses ()
  {
    return Collections.unmodifiableList (addrsIPv4);
  }

  
  /**
   *  return the list of IPv6 addresses assigned to the name server
   *
   *  @return               the list
   */

  public List<String> getIPv6Addresses ()
  {
    return Collections.unmodifiableList (addrsIPv6);
  }


  /**
   *  return the name server name
   *
   *  @return                the name server name
   */
  
  public String getNameserverName ()
  {
    return nsName;
  }
  
}



