package annotator.specification;

import java.util.HashSet;
import java.util.Set;

import annotator.find.Criteria;
import annotator.find.Criterion;

/**
 * A CriterionList is a singly-linked list of Criterion meant to be treated
 * as a stack.  It is very useful for creating base criteria and passing
 * independent copies to different parts of a specification that creates
 * all the criterion.  A CriterionList is immutable, and so copies
 * created by the add() function can safely be passed anywhere.
 * It is supposed to be easier to manipulate than a Criteria.
 */
public class CriterionList {
  // This really is a simple data structure to facilitate creation
  //  of specifications.  TODO: make it a private class?
  private Criterion current;
  private CriterionList next;

  /**
   * Creates a new CriterionList with no criterion.
   */
  public CriterionList() {
    next = null;
    current = null;
  }

  /**
   * Creates a new CriterionList containing just the given Criterion.
   *
   * @param c the sole criterion the list contains at the moment
   */
  public CriterionList(Criterion c) {
    current = c;
    next = null;
  }

  private CriterionList(Criterion c, CriterionList n) {
    current = c;
    next = n;
  }

  /**
   * Adds the given criterion to the present list and returns a newly
   * allocated list containing the result.  Note that this will not lead to
   * a modification of the list this is called on.
   *
   * @param c the criterion to add
   * @return a new list containing the given criterion and the rest of the
   *  criterion already in this list
   */
  public CriterionList add(Criterion c) {
    return new CriterionList(c, this);
  }

  /**
   * Creates a Criteria object representing all the criterion in this list.
   *
   * @return a Criteria that contains all the criterion in this list
   */
  public Criteria criteria() {
    Criteria criteria = new Criteria();

    CriterionList c = this;
    Set<Criterion> criterion = new HashSet<Criterion>();
    while (c != null && c.current != null) {
      criteria.add(c.current);
      c = c.next;
    }

    return criteria;
  }

}

@@ -142,20 +142,906 @@
 erion;%0A%0A
+// The notion of a CriterionList as a list of independent elements (with the%0A// list being satisfied if each of its elements is) is broken.  For example, a%0A// class may have an inner class of the same name, and the list would be%0A// satisfied for either one.  The same goes for method names, and (most%0A// problematically, because it comes up most often) for relative location in%0A// GenericArrayLocationCriterion, where the criterion %5B1%5D would also match %5B2%0A// 1%5D because it is a suffix of it, or %5B2 1%5D would also match %5B3 2 1%5D.  A%0A// related problem is the idea of checking from the bottom to the top of a%0A// TreePath whether it satisfies a criterion.  I have put into place piecemeal%0A// fixes for some of these, but really the CriterionList needs to be turned%0A// into a path that is followed, and checking needs to start at the top of the%0A// tree (at the CompilationUnit). -MDE 9/2009%0A%0A
 /**%0A
-
  * A Cri
@@ -1134,13 +1134,8 @@
  is 
-very 
 usef
@@ -2186,20 +2186,20 @@
 ns a
+%0A   *
  newly
-%0A   * 
+-
 allo
@@ -2237,89 +2237,41 @@
 t.  
-Note that this will not lead to%0A   * a modification of the list this is called on
+Does not modify its%0A   * argument
 .%0A  

Update documentation to explain design flaw in CriterionList.