1
2
3
4
5
6
7
8
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
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 }