View Javadoc

1   /* ===================================================================
2    * Copyright 2002-04 SRI International.
3    * Released under the MOZILLA PUBLIC LICENSE Version 1.1
4    * which can be obtained at http://www.mozilla.org/MPL/MPL-1.1.html
5    * This software is distributed on an "AS IS"
6    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
7    * See the License for the specific language governing rights and
8    * limitations under the License.
9    * =================================================================== */
10  
11  package com.sri.common.util;
12  
13  import java.lang.reflect.Array;
14  import java.util.Iterator;
15  
16  /***
17   * This class allows the generation of all combinations of Object items
18   * available throughout the wizard steps.  It is used to generate the
19   * decision matrix in the Wizard controller.  It works by keeping an
20   * array of counters
21   *
22   * @author Michael Rimov
23   */
24  public class ObjectCombinator {
25  
26  
27      /***
28       * All values, where dimension one represents each page in a wizard
29       * with a menu, dimension two represents all menu items.
30       */
31      private final Object[][] allValues;
32  
33      /***
34       * The class of the object that we're iterating.
35       */
36      private final Class objectClass;
37  
38      /***
39       * Constructs a PicklistCombinator object given a two dimensional array
40       * representing all choices available during the execution of a wizard.
41       *
42       * @param allObjectValues an array of valid value items.
43       *                        The first dimension
44       *                        represents each page.  The second dimension represents all the choices
45       *                        present in each page.
46       * @param arrayClass      the class of the object that is in the array.
47       */
48      public ObjectCombinator(final Object[][] allObjectValues, final Class arrayClass) {
49          super();
50          assert allObjectValues != null;
51          allValues = allObjectValues;
52          objectClass = arrayClass;
53  
54      }
55  
56      /***
57       * Iterate over the picklists.
58       *
59       * @return Iterator
60       */
61      public Iterator iterator() {
62          return new PicklistIterator(getAllValues(), objectClass);
63      }
64  
65      /***
66       * Retrieves where we are in the current iteration for a particular column.
67       * For example, when we start, column 0 is at 0, column 1 is at zero, etc.
68       * Then if we have a 2x2 grid, after iterator it.next() we have colum 0
69       * at 0, column 1 at 1.
70       *
71       * @param i      Iterator The current PicklistIterator.
72       * @param column int the column to query.
73       * @return int the current location in the column index. (zero based)
74       * @throws ArrayIndexOutOfBoundsException if column number is too high
75       *                                        for the combination matrix.
76       */
77      public int getRowIndex(final Iterator i, final int column) {
78          ObjectCombinator.PicklistIterator it = (ObjectCombinator.PicklistIterator) i;
79          int counters[] = it.getCounters();
80          return counters[column];
81      }
82  
83      /***
84       * Protected getter.
85       *
86       * @return Object[][]
87       */
88      protected Object[][] getAllValues() {
89          return allValues;
90      }
91  
92      /***
93       * Used to iterate over a Object to retrieve all combinations
94       * of menut items available.
95       *
96       * @author Michael Rimov
97       */
98      private static class PicklistIterator implements Iterator {
99  
100         /***
101          * The data we're iterating.
102          */
103         private final Object data[][];
104 
105         /***
106          * The class of the data we're iterating.  Necessary so we know
107          * what kind of array to instantiate.
108          */
109         private final Class objectClass;
110 
111         /***
112          * The pointers into the array.
113          */
114         private final int counters[];
115 
116         /***
117          * Purposeful package protected.
118          *
119          * @return int[] the current set of counters.
120          */
121         int[] getCounters() {
122             return counters;
123         }
124 
125         /***
126          * Constructor that takes references to the data matix.
127          *
128          * @param allValues   Object[][]
129          * @param objectClass the class of the object array.
130          */
131         PicklistIterator(final Object allValuesToIterate[][], final Class objectClass) {
132             data = allValuesToIterate;
133             counters = new int[data.length];
134             this.objectClass = objectClass;
135 
136             if (counters.length == 0) {
137                 return;
138             }
139 
140             for (int i = 0; i < counters.length; i++) {
141                 counters[i] = 0;
142             }
143 
144             //Make the last counter BEFORE the starting point.
145             counters[counters.length - 1] = -1;
146         }
147 
148         /***
149          * {@inheritDoc}
150          *
151          * @return <tt>true</tt> if the iterator has more elements.
152          */
153         public boolean hasNext() {
154             for (int i = 0; i < counters.length; i++) {
155                 if (counters[i] < (data[i].length - 1)) {
156                     return true;
157                 }
158             }
159             return false;
160         }
161 
162         /***
163          * {@inheritDoc}
164          *
165          * @return A PicklistCombinationRow instance.
166          */
167         public Object next() {
168             if (!hasNext()) {
169                 throw new java.lang.ArrayIndexOutOfBoundsException("No more combinations");
170             }
171 
172             incrementCounters();
173             Object[] returnValue = (Object[]) Array.newInstance(objectClass, data.length);
174             for (int i = 0; i < data.length; i++) {
175                 returnValue[i] = data[i][counters[i]];
176             }
177             return returnValue;
178         }
179 
180 
181         /***
182          * Increments the counters by performing a rollover addition
183          * of the data registers.
184          */
185         private void incrementCounters() {
186             for (int i = (counters.length - 1); i >= 0; i--) {
187                 counters[i]++;
188                 if (counters[i] >= data[i].length) {
189                     if (i == 0) {
190                         throw new ArrayIndexOutOfBoundsException("Register Wraparound");
191                     }
192                     counters[i] = 0;
193                 } else {
194                     break;
195                 }
196             }
197         }
198 
199         /***
200          * Not supported.
201          *
202          * @throws java.lang.UnsupportedOperationException
203          *
204          */
205         public void remove() {
206             throw new java.lang.UnsupportedOperationException("Function \"remove\" not "
207                     + "implemented for Object permutations");
208         }
209     }
210 
211 }