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 Daniel on 6/7/12
16   */
17  package org.kuali.student.enrollment.class2.courseoffering.service.impl;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.student.enrollment.class2.courseoffering.service.CourseOfferingCodeGenerator;
21  import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingInfo;
22  import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
23  
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.Comparator;
27  import java.util.List;
28  
29  /**
30   * This class //TODO ...
31   *
32   * @author Kuali Student Team
33   */
34  public class CourseOfferingCodeGeneratorImpl implements CourseOfferingCodeGenerator {
35  
36  
37      @Override
38      public String generateActivityOfferingCode(String courseOfferingCode, List<ActivityOfferingInfo> existingActivityOfferings) {
39  
40          // If this is the first code, send back "A"
41          if (existingActivityOfferings == null || existingActivityOfferings.isEmpty()) {
42              return "A";
43          }
44  
45          List<String> aoCodes = new ArrayList<String>();
46          for (ActivityOfferingInfo aoInfo : existingActivityOfferings) {
47              aoCodes.add(aoInfo.getActivityCode());
48          }
49  
50          return calculateNextCode(aoCodes);
51      }
52  
53      @Override
54      public String generateCourseOfferingInternalCode(List<CourseOfferingInfo> existingCourseOfferings) {
55  
56          //If this is the first code, send back "A"
57          if (existingCourseOfferings == null || existingCourseOfferings.isEmpty()) {
58              return "A";
59          }
60  
61          List<String> internalCodes = new ArrayList<String>();
62          for (CourseOfferingInfo coInfo : existingCourseOfferings) {
63              if (coInfo.getCourseNumberSuffix() != null) {
64                  internalCodes.add(coInfo.getCourseNumberSuffix());
65              }
66          }
67  
68          return calculateNextCode(internalCodes);
69      }
70  
71      public String calculateNextCode(List<String> codes){
72          // Always start with A if it's not there
73          if (!codes.contains("A")) {
74              return "A";
75          }
76  
77          // Sort the list so we can fill in gaps
78          Collections.sort(codes, new Comparator<String>() {
79              @Override
80              public int compare(String o1, String o2) {
81                  if (o1.length() == o2.length()) {
82                      return o1.compareTo(o2);
83                  } else {
84                      return o1.length() - o2.length();
85                  }
86              }
87          });
88  
89          // Fill in the gaps of letters
90          for (String s : codes) {
91              //For each existing code, find the next valid generated code and see if it exists
92              String nextCode = getNextCode(s);
93              if (!codes.contains(nextCode)) {
94                  return nextCode;
95              }
96          }
97  
98          // This should never be reached unless there is an infinite list of strings passed in
99          throw new RuntimeException("Error generating codes");
100     }
101     /**
102      * Gets the next letter of the alphabet in caps in the form A,B...Z,AA,AB...AZ,BA,BB..BZ,CA,CB....ZZ,AAA,AAB...
103      *
104      * Make sure it's public as it's needed for Test class
105      *
106      * @param source source code string
107      * @return next code
108      */
109     public String getNextCode(String source){
110         if (StringUtils.isEmpty(source)) {
111             return "A";
112         } else if (StringUtils.endsWithIgnoreCase(source, "Z")) {
113             return getNextCode(StringUtils.substringBeforeLast(source, "Z")) + "A";
114         } else {
115             char lastLetter = source.charAt(source.length() - 1);
116             return StringUtils.substringBeforeLast(source, "" + lastLetter) + ++lastLetter;
117         }
118     }
119 }