content: /*
   * Conditions Of Use
   *
   * This software was developed by employees of the National Institute of
   * Standards and Technology (NIST), an agency of the Federal Government.
   * Pursuant to title 15 Untied States Code Section 105, works of NIST
   * employees are not subject to copyright protection in the United States
   * and are considered to be in the public domain.  As a result, a formal
   * license is not needed to use the software.
   *
   * This software is provided by NIST as a service and is expressly
   * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
   * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
   * AND DATA ACCURACY.  NIST does not warrant or make any representations
   * regarding the use of the software or the results thereof, including but
   * not limited to the correctness, accuracy, reliability or usefulness of
   * the software.
   *
   * Permission to use this software is contingent upon your acceptance
   * of the terms of this agreement
   *
   * .
   *
   */
  /*******************************************************************************
   * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *
   *******************************************************************************/
  package gov2.nist.core;
  
  import java.util.*;
  import java.io.Serializable;
  
  /**
   * Implements a homogenous consistent linked list. All the objects in the linked
   * list must derive from the same root class. This is a useful constraint to
   * place on our code as this property is invariant.The list is created with the
   * superclass which can be specified as either a class name or a Class.
   *
   * @version 1.2
   *
   * @author M. Ranganathan <br/>
   *
   *
   *
   */
  public abstract class GenericObjectList extends LinkedList<GenericObject> implements
          Serializable, Cloneable{
      // Useful constants.
      protected static final String SEMICOLON = Separators.SEMICOLON;
  
      protected static final String COLON = Separators.COLON;
  
      protected static final String COMMA = Separators.COMMA;
  
      protected static final String SLASH = Separators.SLASH;
  
      protected static final String SP = Separators.SP;
  
      protected static final String EQUALS = Separators.EQUALS;
  
      protected static final String STAR = Separators.STAR;
  
      protected static final String NEWLINE = Separators.NEWLINE;
  
      protected static final String RETURN = Separators.RETURN;
  
      protected static final String LESS_THAN = Separators.LESS_THAN;
  
      protected static final String GREATER_THAN = Separators.GREATER_THAN;
  
      protected static final String AT = Separators.AT;
  
      protected static final String DOT = Separators.DOT;
  
      protected static final String QUESTION = Separators.QUESTION;
  
      protected static final String POUND = Separators.POUND;
  
      protected static final String AND = Separators.AND;
  
      protected static final String LPAREN = Separators.LPAREN;
  
      protected static final String RPAREN = Separators.RPAREN;
  
      protected static final String DOUBLE_QUOTE = Separators.DOUBLE_QUOTE;
  
      protected static final String QUOTE = Separators.QUOTE;
  
      protected static final String HT = Separators.HT;
  
      protected static final String PERCENT = Separators.PERCENT;
  
      protected int indentation;
  
      protected String listName; // For debugging
  
      private ListIterator<? extends GenericObject> myListIterator;
  
      private String stringRep;
  
      protected Class<?> myClass;
  
      protected String separator;
  
      protected String getIndentation() {
          char[] chars = new char[indentation];
          java.util.Arrays.fill(chars, ' ');
          return new String(chars);
      }
  
      /**
       * Return true if this supports reflection based cloning.
       */
      protected static boolean isCloneable(Object obj) {
          return obj instanceof Cloneable;
      }
  
      public static boolean isMySubclass(Class<?> other) {
          return GenericObjectList.class.isAssignableFrom(other);
  
      }
  
      /**
       * Makes a deep clone of this list.
       */
      public Object clone() {
          GenericObjectList retval = (GenericObjectList) super.clone();
          for (ListIterator<GenericObject> iter = retval.listIterator(); iter.hasNext();) {
              GenericObject obj = (GenericObject) ((GenericObject) iter.next())
                      .clone();
              iter.set(obj);
          }
          return retval;
      }
  
  
  
      public void setMyClass(Class cl) {
          myClass = cl;
      }
  
      protected GenericObjectList() {
          super();
          listName = null;
          stringRep = "";
          separator = ";";
      }
  
      protected GenericObjectList(String lname) {
          this();
          listName = lname;
      }
  
      /**
       * A Constructor which takes a list name and a class name (for assertion
       * checking).
       */
  
      protected GenericObjectList(String lname, String classname) {
          this(lname);
          try {
              myClass = Class.forName(classname);
          } catch (ClassNotFoundException ex) {
              InternalErrorHandler.handleException(ex);
          }
  
      }
  
      /**
       * A Constructor which takes a list name and a class (for assertion
       * checking).
       */
  
      protected GenericObjectList(String lname, Class objclass) {
          this(lname);
          myClass = objclass;
      }
  
      /**
       * Traverse the list given a list iterator
       */
      protected GenericObject next(ListIterator iterator) {
          try {
              return (GenericObject) iterator.next();
          } catch (NoSuchElementException ex) {
              return null;
          }
      }
  
      /**
       * This is the default list iterator.This will not handle nested list
       * traversal.
       */
      protected GenericObject first() {
          myListIterator = this.listIterator(0);
          try {
              return (GenericObject) myListIterator.next();
          } catch (NoSuchElementException ex) {
              return null;
          }
      }
  
      /**
       * Fetch the next object from the list based on the default list iterator
       */
      protected GenericObject next() {
          if (myListIterator == null) {
              myListIterator = this.listIterator(0);
          }
          try {
              return (GenericObject) myListIterator.next();
          } catch (NoSuchElementException ex) {
              myListIterator = null;
              return null;
          }
      }
  
      /**
       * Concatenate two compatible header lists, adding the argument to the tail
       * end of this list.
       *
       * @param <var>
       *            topFlag </var> set to true to add items to top of list
       */
      protected void concatenate(GenericObjectList objList) {
          concatenate(objList, false);
      }
  
      /**
       * Concatenate two compatible header lists, adding the argument either to
       * the beginning or the tail end of this list. A type check is done before
       * concatenation.
       *
       * @param <var>
       *            topFlag </var> set to true to add items to top of list else
       *            add them to the tail end of the list.
       */
      protected void concatenate(GenericObjectList objList, boolean topFlag) {
          if (!topFlag) {
              this.addAll(objList);
          } else {
              // add given items to the top end of the list.
              this.addAll(0, objList);
          }
      }
  
      /**
       * string formatting function.
       */
  
      private void sprint(String s) {
          if (s == null) {
              stringRep += getIndentation();
              stringRep += "<null>\n";
              return;
          }
  
          if (s.compareTo("}") == 0 || s.compareTo("]") == 0) {
              indentation--;
          }
          stringRep += getIndentation();
          stringRep += s;
          stringRep += "\n";
          if (s.compareTo("{") == 0 || s.compareTo("[") == 0) {
              indentation++;
          }
      }
  
      /**
       * Convert this list of headers to a formatted string.
       */
  
      public String debugDump() {
          stringRep = "";
          Object obj = this.first();
          if (obj == null)
              return "<null>";
          sprint("listName:");
          sprint(listName);
          sprint("{");
          while (obj != null) {
              sprint("[");
              sprint(((GenericObject) obj).debugDump(this.indentation));
              obj = next();
              sprint("]");
          }
          sprint("}");
          return stringRep;
      }
  
      /**
       * Convert this list of headers to a string (for printing) with an
       * indentation given.
       */
  
      public String debugDump(int indent) {
          int save = indentation;
          indentation = indent;
          String retval = this.debugDump();
          indentation = save;
          return retval;
      }
  
      public void addFirst(GenericObject objToAdd) {
          if (myClass == null) {
              myClass = objToAdd.getClass();
          } else {
              super.addFirst(objToAdd);
          }
      }
  
      /**
       * Do a merge of the GenericObjects contained in this list with the
       * GenericObjects in the mergeList. Note that this does an inplace
       * modification of the given list. This does an object by object merge of
       * the given objects.
       *
       * @param mergeList
       *            is the list of Generic objects that we want to do an object by
       *            object merge with. Note that no new objects are added to this
       *            list.
       *
       */
  
      public void mergeObjects(GenericObjectList mergeList) {
  
          if (mergeList == null)
              return;
          Iterator it1 = this.listIterator();
          Iterator it2 = mergeList.listIterator();
          while (it1.hasNext()) {
              GenericObject outerObj = (GenericObject) it1.next();
              while (it2.hasNext()) {
                  Object innerObj = it2.next();
                  outerObj.merge(innerObj);
              }
          }
      }
  
      /**
       * Encode the list in semicolon separated form.
       *
       * @return an encoded string containing the objects in this list.
       * @since v1.0
       */
      public String encode() {
          if (this.isEmpty())
              return "";
          StringBuffer encoding = new StringBuffer();
          ListIterator iterator = this.listIterator();
          if (iterator.hasNext()) {
              while (true) {
                  Object obj = iterator.next();
                  if (obj instanceof GenericObject) {
                      GenericObject gobj = (GenericObject) obj;
                      encoding.append(gobj.encode());
                  } else {
                      encoding.append(obj.toString());
                  }
                  if (iterator.hasNext())
                      encoding.append(separator);
                  else
                      break;
              }
          }
          return encoding.toString();
      }
  
      /**
       * Alias for the encode function above.
       */
      public String toString() {
          return this.encode();
      }
  
      /**
       * Set the separator (for encoding the list)
       *
       * @since v1.0
       * @param sep
       *            is the new seperator (default is semicolon)
       */
      public void setSeparator(String sep) {
          separator = sep;
      }
      
      /**
       * Hash code. We never expect to put this in a hash table so return a constant.
       */
      public int hashCode() { return 42; }
  
      /**
       * Equality checking predicate.
       *
       * @param other
       *            is the object to compare ourselves to.
       * @return true if the objects are equal.
       */
      public boolean equals(Object other) {
          if (other == null ) return false;
          if (!this.getClass().equals(other.getClass()))
              return false;
          GenericObjectList that = (GenericObjectList) other;
          if (this.size() != that.size())
              return false;
          ListIterator myIterator = this.listIterator();
          while (myIterator.hasNext()) {
              Object myobj = myIterator.next();
              ListIterator hisIterator = that.listIterator();
              try {
                  while (true) {
                      Object hisobj = hisIterator.next();
                      if (myobj.equals(hisobj))
                          break;
                  }
              } catch (NoSuchElementException ex) {
                  return false;
              }
          }
          ListIterator hisIterator = that.listIterator();
          while (hisIterator.hasNext()) {
              Object hisobj = hisIterator.next();
              myIterator = this.listIterator();
              try {
                  while (true) {
                      Object myobj = myIterator.next();
                      if (hisobj.equals(myobj))
                          break;
                  }
              } catch (NoSuchElementException ex) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Match with a template (return true if we have a superset of the given
       * template. This can be used for partial match (template matching of SIP
       * objects). Note -- this implementation is not unnecessarily efficient :-)
       *
       * @param other
       *            template object to compare against.
       */
  
      public boolean match(Object other) {
          if (!this.getClass().equals(other.getClass()))
              return false;
          GenericObjectList that = (GenericObjectList) other;
          ListIterator hisIterator = that.listIterator();
          outer: while (hisIterator.hasNext()) {
              Object hisobj = hisIterator.next();
              Object myobj = null;
              ListIterator myIterator = this.listIterator();
              while (myIterator.hasNext()) {
                  myobj = myIterator.next();
                  if (myobj instanceof GenericObject)
                      System.out.println("Trying to match  = "
                              + ((GenericObject) myobj).encode());
                  if (GenericObject.isMySubclass(myobj.getClass())
                          && ((GenericObject) myobj).match(hisobj))
                      break outer;
                  else if (GenericObjectList.isMySubclass(myobj.getClass())
                          && ((GenericObjectList) myobj).match(hisobj))
                      break outer;
              }
              System.out.println(((GenericObject) hisobj).encode());
              return false;
          }
          return true;
      }
  }
  