View Javadoc
1   /**
2    * Copyright 2012 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   *
15   * Created by Charles on 10/1/12
16   */
17  package org.kuali.student.r2.common.permutation;
18  
19  import org.aspectj.weaver.Lint;
20  import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingClusterInfo;
21  import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingSetInfo;
22  import org.kuali.student.enrollment.courseoffering.dto.RegistrationGroupInfo;
23  import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
24  
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  /**
33   * Used to generate permutations
34   *
35   * @author Kuali Student Team
36   */
37  public class PermutationCounter {
38      private int [] counter;
39      private int [] maxSizes;
40      private int totalIterations;
41  
42      public PermutationCounter(int numDigits) {
43          counter = new int[numDigits];
44          maxSizes = new int[numDigits];
45          for (int i = 0; i < counter.length; i++) {
46              counter[i] = 0;
47              maxSizes[i] = -1;
48          }
49          totalIterations = 0;
50      }
51  
52      public boolean isValid() {
53          for (int i = 0; i < counter.length; i++) {
54              if (maxSizes[i] == -1) {
55                  return false;
56              }
57          }
58          return true;
59      }
60      /**
61       *
62       * @param maxSize The max value for this "digit" is maxSize - 1
63       * @param index The digit position with 0 as the most significant digit
64       */
65      public void setMaxSizeAtIndex(int maxSize, int index) {
66          maxSizes[index] = maxSize;
67          totalIterations = _computerNumIterations();
68      }
69  
70      public int size() {
71          return counter.length;
72      }
73  
74      public void clear() {
75          for (int i = 0; i < counter.length; i++) {
76              counter[i] = 0;
77              maxSizes[i] = -1;
78          }
79      }
80  
81      public int getMaxSizeAtIndex(int index) {
82          return maxSizes[index];
83      }
84  
85      public int get(int index) {
86          return counter[index];
87      }
88  
89      public void increment() {
90          // Although it doesn't matter much, index 0 is being treated as the most significant "digit"
91          for (int i = counter.length - 1; i >= 0; i--) {
92              counter[i] += 1;
93              if (counter[i] >= maxSizes[i]) {
94                  counter[i] = 0;
95              } else {
96                  break;
97              }
98          }
99      }
100 
101     /**
102      * Number of iterations to go through the entire counter.
103      * @return number of iterations to go through entire counter once
104      */
105     public int numIterations() {
106         return totalIterations;
107     }
108 
109     private int _computerNumIterations() {
110         int prod = 1;
111         for (int i = 0; i < maxSizes.length; i++) {
112             int max = maxSizes[i];
113             if (max == -1){
114                 max = 0; // Force product to be zero
115             }
116             prod *= max;
117         }
118         return prod;
119     }
120 
121     // ============================== Static method ===============================
122     public static Set<List<String>> computeMissingRegGroupAoIdsInCluster(ActivityOfferingClusterInfo cluster,
123                                                                         List<RegistrationGroupInfo> currentRGs)
124             throws DataValidationErrorException {
125 
126         // Initialize counter
127         PermutationCounter counter = new PermutationCounter(cluster.getActivityOfferingSets().size());
128         List<ActivityOfferingSetInfo> aoSets = cluster.getActivityOfferingSets();
129 
130         for (int i = 0; i < aoSets.size(); i++) {
131             ActivityOfferingSetInfo setInfo = aoSets.get(i);
132             int aoSetSize = setInfo.getActivityOfferingIds().size();
133             counter.setMaxSizeAtIndex(aoSetSize, i);
134         }
135         // Make sure it's valid before going on
136         if (!counter.isValid()) {
137             throw new DataValidationErrorException("Counter is invalid: can't generate permutations");
138         }
139         // Find reg group AO sets for existing reg groups
140         Set<Set<String>> actualRegGroupAoSets = new HashSet<Set<String>>();
141         for (RegistrationGroupInfo rgInfo: currentRGs) {
142             Set<String> regGroupAoIds = new HashSet<String>();
143             regGroupAoIds.addAll(rgInfo.getActivityOfferingIds()); // Set of AO IDs in the reg group
144             actualRegGroupAoSets.add(regGroupAoIds);
145         }
146 
147         // Compute every permutation
148         Set<List<String>> missingRegGroupAoSets = new HashSet<List<String>>();
149         for (int i = 0; i < counter.numIterations(); i++, counter.increment()) {
150             // Put each permutation of a reg group AOs into a set called regGroupAoIdSetPermutation
151             List<String> regGroupAoIdListPermutation = _computeRegGroupAoPermutation(cluster, counter);
152             Set<String> aoIdsSet = new HashSet<String>(regGroupAoIdListPermutation); // make into a set
153             // If this set of AO Ids does not exist in one of the RGs, then add it to those that are missing
154             if (!actualRegGroupAoSets.contains(aoIdsSet)) {
155                 missingRegGroupAoSets.add(regGroupAoIdListPermutation);
156             }
157         }
158 
159         return missingRegGroupAoSets;
160     }
161 
162     private static List<String> _computeRegGroupAoPermutation(ActivityOfferingClusterInfo cluster, PermutationCounter counter) {
163         List<String> regGroupAoIdSetPermutation = new ArrayList<String>();
164         for (int aoSetIndex = 0; aoSetIndex < counter.size(); aoSetIndex++) {
165             // Picks an AO ID from each AO type
166             int aoIdIndex = counter.get(aoSetIndex);
167             String aoId = cluster.getActivityOfferingSets().get(aoSetIndex).getActivityOfferingIds().get(aoIdIndex);
168             regGroupAoIdSetPermutation.add(aoId);
169         }
170         return regGroupAoIdSetPermutation;
171     }
172 }