001    package edu.nrao.sss.sort;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.Comparator;
006    import java.util.List;
007    
008    /**
009     * A {@link Comparator comparator} that is a chain of other comparators.
010     * <p>
011     * The first comparator in this one's list functions as the primary key,
012     * the next as a secondary key (in case of a tie in primary keys),
013     * and so on.</p>
014     * <p>
015     * Rather than wrapping its internal list, this comparator provides
016     * its list of components for its clients to access directly.</p> 
017     * <p>
018     * <b>Version Info:</b>
019     * <table style="margin-left:2em">
020     *   <tr><td>$Revision: 593 $</td></tr>
021     *   <tr><td>$Date: 2007-05-07 15:54:14 -0600 (Mon, 07 May 2007) $</td></tr>
022     *   <tr><td>$Author: dharland $</td></tr>
023     * </table></p>
024     * 
025     * @author David M. Harland
026     * @since 2007-05-03
027     */
028    public class CompoundComparator<T>
029      implements Comparator<T>
030    {
031      private List<Comparator<T>> comparators;
032      
033      /** Creates a new instance with no contained comparators. */
034      public CompoundComparator()
035      {
036        this((Comparator<T>[])null);
037      }
038      
039      /**
040       * Creates a new compound comparator with the given elements.
041       * The constituent comparators are placed onto this one in the
042       * same order they are given to this constructor.
043       * 
044       * @param newComparators the comparators held by this one.
045       */
046      public CompoundComparator(Comparator<T>... newComparators)
047      {
048        comparators = new ArrayList<Comparator<T>>();
049        
050        if (newComparators != null)
051        {
052          for (Comparator<T> c : newComparators)
053            if (c != null)
054              comparators.add(c);
055        }
056      }
057      
058      /**
059       * Creates a new compound comparator with the given elements.
060       * The constituent comparators are placed onto this one in the
061       * same order they inhabit in the given collection.
062       * 
063       * @param newComparators the comparators held by this one.
064       */
065      public CompoundComparator(Collection<? extends Comparator<T>> newComparators)
066      {
067        comparators = new ArrayList<Comparator<T>>();
068        
069        if (newComparators != null)
070        {
071          for (Comparator<T> c : newComparators)
072            if (c != null)
073              comparators.add(c);
074        }
075      }
076      
077      /**
078       * Returns the list of component comparators held by this one.
079       * <p>
080       * The returned list is the one actually held by this comparator.
081       * Clients who wish to add, remove, or otherwise manipulate the components,
082       * or their status in the list, should work directly with this list.</p>
083       * 
084       * @return the list of component comparators held by this one.
085       */
086      public List<Comparator<T>> getComponents()
087      {
088        return comparators;
089      }
090      
091      /* (non-Javadoc)
092       * @see Comparator#compare(Object, Object)
093       */
094      public int compare(T o1, T o2)
095      {
096        int result = 0;
097        
098        for (Comparator<T> c : comparators)
099        {
100          if (c == null || c == this)
101            continue;
102          
103          result = c.compare(o1, o2);
104        
105          //Stop comparing the first time a comparator detects a difference
106          if (result != 0)
107            break;
108        }
109        
110        return result;
111      }
112    }