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   */
16  package org.kuali.student.enrollment.class2.courseoffering.service.impl;
17  
18  import org.apache.commons.lang.BooleanUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.criteria.PredicateFactory;
21  import org.kuali.rice.core.api.criteria.QueryByCriteria;
22  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
23  import org.kuali.rice.kim.api.KimConstants;
24  import org.kuali.rice.kim.api.permission.PermissionService;
25  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
26  import org.kuali.rice.krad.util.GlobalVariables;
27  import org.kuali.rice.krad.util.KRADConstants;
28  import org.kuali.student.enrollment.class2.courseoffering.dto.ActivityOfferingWrapper;
29  import org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingListSectionWrapper;
30  import org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingWrapper;
31  import org.kuali.student.enrollment.class2.courseoffering.form.CourseOfferingManagementForm;
32  import org.kuali.student.enrollment.class2.courseoffering.service.CourseOfferingManagementViewHelperService;
33  import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingConstants;
34  import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingResourceLoader;
35  import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingViewHelperUtil;
36  import org.kuali.student.enrollment.class2.courseoffering.util.ToolbarUtil;
37  import org.kuali.student.enrollment.class2.scheduleofclasses.dto.ActivityOfferingDisplayWrapper;
38  import org.kuali.student.enrollment.class2.scheduleofclasses.util.ScheduleOfClassesConstants;
39  import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingDisplayInfo;
40  import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingInfo;
41  import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
42  import org.kuali.student.enrollment.courseoffering.dto.FormatOfferingInfo;
43  import org.kuali.student.enrollment.courseoffering.service.CourseOfferingService;
44  import org.kuali.student.enrollment.courseofferingset.dto.SocInfo;
45  import org.kuali.student.enrollment.courseofferingset.service.CourseOfferingSetService;
46  import org.kuali.student.enrollment.uif.util.GrowlIcon;
47  import org.kuali.student.enrollment.uif.util.KSUifUtils;
48  import org.kuali.student.r2.common.constants.CommonServiceConstants;
49  import org.kuali.student.r2.common.dto.ContextInfo;
50  import org.kuali.student.r2.common.dto.StatusInfo;
51  import org.kuali.student.r2.common.util.ContextUtils;
52  import org.kuali.student.r2.common.util.constants.CourseOfferingServiceConstants;
53  import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants;
54  import org.kuali.student.r2.common.util.constants.LuiServiceConstants;
55  import org.kuali.student.r2.common.util.date.DateFormatters;
56  import org.kuali.student.r2.core.acal.dto.KeyDateInfo;
57  import org.kuali.student.r2.core.acal.dto.TermInfo;
58  import org.kuali.student.r2.core.acal.service.AcademicCalendarService;
59  import org.kuali.student.r2.core.atp.dto.AtpInfo;
60  import org.kuali.student.r2.core.atp.service.AtpService;
61  import org.kuali.student.r2.core.class1.search.CourseOfferingManagementSearchImpl;
62  import org.kuali.student.r2.core.class1.state.dto.StateInfo;
63  import org.kuali.student.r2.core.class1.type.dto.TypeInfo;
64  import org.kuali.student.r2.core.constants.AcademicCalendarServiceConstants;
65  import org.kuali.student.r2.core.constants.AtpServiceConstants;
66  import org.kuali.student.r2.core.scheduling.constants.SchedulingServiceConstants;
67  import org.kuali.student.r2.core.scheduling.dto.ScheduleComponentDisplayInfo;
68  import org.kuali.student.r2.core.scheduling.infc.ScheduleComponentDisplay;
69  import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
70  import org.kuali.student.r2.core.search.dto.SearchResultCellInfo;
71  import org.kuali.student.r2.core.search.dto.SearchResultInfo;
72  import org.kuali.student.r2.core.search.dto.SearchResultRowInfo;
73  import org.kuali.student.r2.core.search.service.SearchService;
74  import org.kuali.student.r2.lum.course.dto.ActivityInfo;
75  import org.kuali.student.r2.lum.course.dto.CourseInfo;
76  import org.kuali.student.r2.lum.course.dto.CourseJointInfo;
77  import org.kuali.student.r2.lum.course.dto.FormatInfo;
78  import org.kuali.student.r2.lum.course.service.CourseService;
79  import org.kuali.student.r2.lum.lrc.service.LRCService;
80  
81  import javax.xml.namespace.QName;
82  import java.util.ArrayList;
83  import java.util.Arrays;
84  import java.util.Calendar;
85  import java.util.Date;
86  import java.util.HashMap;
87  import java.util.List;
88  import java.util.Map;
89  @Deprecated
90  /**
91   * @deprecated
92   * @see org.kuali.student.enrollment.class2.autogen.service.impl.ARGCourseOfferingManagementViewHelperServiceImpl
93   */
94  public class CourseOfferingManagementViewHelperServiceImpl extends CO_AO_RG_ViewHelperServiceImpl implements CourseOfferingManagementViewHelperService{
95      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CourseOfferingManagementViewHelperServiceImpl.class);
96  
97      private AcademicCalendarService acalService = null;
98      private CourseOfferingService coService = null;
99      private SearchService searchService = null;
100 
101     private CourseService courseService;
102     private LRCService lrcService;
103     private AtpService atpService;
104     private CourseOfferingSetService socService;
105     private static PermissionService permissionService;
106 
107     /**
108      * This method fetches the <code>TermInfo</code> and validate for exact match
109      *
110      * @param form
111      * @throws Exception
112      */
113     public void populateTerm(CourseOfferingManagementForm form) throws Exception {
114 
115         String termCode = form.getTermCode();
116 
117         form.getCourseOfferingResultList().clear();
118 
119         QueryByCriteria.Builder qbcBuilder = QueryByCriteria.Builder.create();
120         qbcBuilder.setPredicates(PredicateFactory.equal("atpCode", termCode));
121 
122         QueryByCriteria criteria = qbcBuilder.build();
123 
124         List<TermInfo> terms = getAcalService().searchForTerms(criteria, createContextInfo());
125 
126         if (terms.isEmpty()){
127             GlobalVariables.getMessageMap().putError("termCode", CourseOfferingConstants.COURSEOFFERING_MSG_ERROR_NO_TERM_IS_FOUND, termCode);
128         } else if (terms.size() > 1){
129             GlobalVariables.getMessageMap().putError("termCode", CourseOfferingConstants.COURSEOFFERING_MSG_ERROR_FOUND_MORE_THAN_ONE_TERM, termCode);
130         } else {
131             form.setTermInfo(terms.get(0));
132 
133             // setting term first day of classes
134             List<KeyDateInfo> keyDateInfoList = getAcalService().getKeyDatesForTerm(form.getTermInfo().getId(), createContextInfo());
135             Date termClassStartDate = null;
136             for (KeyDateInfo keyDateInfo : keyDateInfoList) {
137                 if (keyDateInfo.getTypeKey().equalsIgnoreCase(AtpServiceConstants.MILESTONE_SEATPOOL_FIRST_DAY_OF_CLASSES_TYPE_KEY) && keyDateInfo.getStartDate() != null) {
138                     termClassStartDate = keyDateInfo.getStartDate();
139                     break;
140                 }
141             }
142             form.setTermClassStartDate(termClassStartDate);
143         }
144 
145     }
146 
147     /**
148      * This method loads all the course offerings for a term and course code.
149      *
150      * @param termId
151      * @param courseCode
152      * @param form
153      * @throws Exception
154      */
155     public void loadCourseOfferingsByTermAndCourseCode(String termId, String courseCode, CourseOfferingManagementForm form) throws Exception {
156 
157         SearchRequestInfo searchRequest = new SearchRequestInfo(CourseOfferingManagementSearchImpl.CO_MANAGEMENT_SEARCH.getKey());
158         searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.COURSE_CODE, courseCode);
159         searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.ATP_ID, termId);
160         searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.CROSS_LIST_SEARCH_ENABLED, BooleanUtils.toStringTrueFalse(true));
161 
162         loadCourseOfferings(searchRequest, form);
163 
164         if (form.getCourseOfferingResultList().isEmpty()){
165             LOG.error("Error: Can't find any Course Offering for a Course Code: " + courseCode + " in term: " + termId);
166             GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS, CourseOfferingConstants.COURSEOFFERING_MSG_ERROR_NO_COURSE_OFFERING_IS_FOUND, "Course Code", courseCode, termId);
167         }
168 
169     }
170 
171     /**
172      * This method loads all the course offerings for a term and subject area/code.
173      *
174      * @param termId term id
175      * @param subjectCode subject area
176      * @param form course offering management form
177      * @throws Exception
178      */
179     public void loadCourseOfferingsByTermAndSubjectCode(String termId, String subjectCode, CourseOfferingManagementForm form) throws Exception {
180 
181         SearchRequestInfo searchRequest = new SearchRequestInfo(CourseOfferingManagementSearchImpl.CO_MANAGEMENT_SEARCH.getKey());
182         searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.SUBJECT_AREA, subjectCode);
183         searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.ATP_ID, termId);
184         searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.CROSS_LIST_SEARCH_ENABLED, BooleanUtils.toStringTrueFalse(true));
185 
186         loadCourseOfferings(searchRequest, form);
187 
188         if (form.getCourseOfferingResultList().isEmpty()){
189             LOG.error("Error: Can't find any Course Offering for a Subject Code: " + subjectCode + " in term: " + termId);
190             GlobalVariables.getMessageMap().putError(KRADConstants.GLOBAL_ERRORS, CourseOfferingConstants.COURSEOFFERING_MSG_ERROR_NO_COURSE_OFFERING_IS_FOUND, "Subject Code", subjectCode, termId);
191         }
192 
193     }
194 
195     /**
196      * This method fetches all the course offerings for a term and course/subject code.
197      *
198      * @see CourseOfferingManagementSearchImpl Actual CO search happens here
199      * @param searchRequest
200      * @param form
201      * @throws Exception
202      */
203     protected void loadCourseOfferings(SearchRequestInfo searchRequest,CourseOfferingManagementForm form) throws Exception {
204 
205         ContextInfo contextInfo = createContextInfo();
206 
207         SearchResultInfo searchResult = getSearchService().search(searchRequest, contextInfo);
208 
209         form.getCourseOfferingResultList().clear();
210 
211         for (SearchResultRowInfo row : searchResult.getRows()) {
212             CourseOfferingListSectionWrapper coListWrapper = new CourseOfferingListSectionWrapper();
213 
214             for(SearchResultCellInfo cellInfo : row.getCells()){
215 
216                 String value = StringUtils.EMPTY;
217                 if(cellInfo.getValue() != null)  {
218                     value = new String(cellInfo.getValue());
219                 }
220 
221                 if(CourseOfferingManagementSearchImpl.SearchResultColumns.CODE.equals(cellInfo.getKey())){
222                     coListWrapper.setCourseOfferingCode(value);
223                 }
224                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.DESC.equals(cellInfo.getKey())){
225                     coListWrapper.setCourseOfferingDesc(value);
226                 }
227                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.STATE.equals(cellInfo.getKey())){
228                     coListWrapper.setCourseOfferingStateKey(value);
229                     coListWrapper.setCourseOfferingStateDisplay(getStateInfo(value).getName());
230                 }
231                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.CREDIT_OPTION.equals(cellInfo.getKey())){
232                     coListWrapper.setCourseOfferingCreditOptionKey(value);
233                 }
234                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.GRADING_OPTION.equals(cellInfo.getKey())){
235                     coListWrapper.setCourseOfferingGradingOptionKey(value);
236                 }
237                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.GRADING_OPTION_NAME.equals(cellInfo.getKey())){
238                     coListWrapper.setCourseOfferingGradingOptionDisplay(cellInfo.getValue());
239                 }
240                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.CREDIT_OPTION_NAME.equals(cellInfo.getKey())){
241                     coListWrapper.setCourseOfferingCreditOptionDisplay(cellInfo.getValue());
242                 }
243                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.DEPLOYMENT_ORG_ID.equals(cellInfo.getKey())){
244                     coListWrapper.setAdminOrg(cellInfo.getValue());
245                 }
246                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.CO_ID.equals(cellInfo.getKey())){
247                     coListWrapper.setCourseOfferingId(value);
248                 }
249                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.SUBJECT_AREA.equals(cellInfo.getKey())){
250                     coListWrapper.setSubjectArea(value);
251                 }
252                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.IS_CROSS_LISTED.equals(cellInfo.getKey())){
253                     coListWrapper.setCrossListed(BooleanUtils.toBoolean(value));
254                 }
255                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.CROSS_LISTED_COURSES.equals(cellInfo.getKey())){
256                     coListWrapper.setAlternateCOCodes(Arrays.asList(StringUtils.split(value, ",")));
257                 }
258                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.OWNER_CODE.equals(cellInfo.getKey())){
259                    coListWrapper.setOwnerCode(value);
260                }
261                 else if(CourseOfferingManagementSearchImpl.SearchResultColumns.OWNER_ALIASES.equals(cellInfo.getKey())){
262                     coListWrapper.setOwnerAliases(Arrays.asList(StringUtils.split(value, ",")));
263                }
264 
265             }
266             form.getCourseOfferingResultList().add(coListWrapper);
267         }
268 
269         setSocStateKeys(form);
270     }
271 
272 
273     /**
274      * This method loads the previous and next course offerings for navigation purpose.
275      *
276      * @param form
277      */
278     public void loadPreviousAndNextCourseOffering(CourseOfferingManagementForm form){
279         try{
280             ContextInfo contextInfo = createContextInfo();
281 
282             /**
283              * Get all the course offerings for a term and subject area.
284              */
285             SearchRequestInfo searchRequest = new SearchRequestInfo(CourseOfferingManagementSearchImpl.CO_MANAGEMENT_SEARCH.getKey());
286             searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.SUBJECT_AREA, form.getSubjectCode());
287             searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.ATP_ID, form.getTermInfo().getId());
288             searchRequest.addParam(CourseOfferingManagementSearchImpl.SearchParameters.CROSS_LIST_SEARCH_ENABLED, BooleanUtils.toStringTrueFalse(true));
289 
290             SearchResultInfo searchResult = getSearchService().search(searchRequest, contextInfo);
291             List<CourseOfferingWrapper> availableCOs = new ArrayList<CourseOfferingWrapper>();
292 
293             for (SearchResultRowInfo row : searchResult.getRows()) {
294 
295                 String courseOfferingCode = "";
296                 String courseOfferingId = "";
297                 String courseOfferingDesc = "";
298                 boolean isCrossListed = false;
299                 List<String> alternateCodes = null;
300 
301                 for(SearchResultCellInfo cellInfo : row.getCells()){
302 
303                     String value = StringUtils.EMPTY;
304                     if(cellInfo.getValue() != null)  {
305                         value = new String(cellInfo.getValue());
306                     }
307 
308                     if(CourseOfferingManagementSearchImpl.SearchResultColumns.CODE.equals(cellInfo.getKey())){
309                         courseOfferingCode = value;
310                     }
311                     else if(CourseOfferingManagementSearchImpl.SearchResultColumns.CO_ID.equals(cellInfo.getKey())){
312                         courseOfferingId = value;
313                     }
314                     else if(CourseOfferingManagementSearchImpl.SearchResultColumns.DESC.equals(cellInfo.getKey())){
315                         courseOfferingDesc = value;
316                     }
317                     else if(CourseOfferingManagementSearchImpl.SearchResultColumns.IS_CROSS_LISTED.equals(cellInfo.getKey())){
318                         isCrossListed = BooleanUtils.toBoolean(value);
319                     }
320                     else if(CourseOfferingManagementSearchImpl.SearchResultColumns.CROSS_LISTED_COURSES.equals(cellInfo.getKey())){
321                         alternateCodes = Arrays.asList(StringUtils.split(value, ","));
322                     }
323 
324                 }
325 
326                 CourseOfferingWrapper coWrapper = new CourseOfferingWrapper(isCrossListed,courseOfferingCode,courseOfferingDesc,alternateCodes,courseOfferingId);
327                 availableCOs.add(coWrapper);
328             }
329 
330             /**
331              * Find the current course offering index and set the previous and next course offerings if exists.
332              */
333             for (CourseOfferingWrapper coWrapper : availableCOs) {
334                 if (StringUtils.equals(coWrapper.getCourseOfferingCode(),form.getCurrentCourseOfferingWrapper().getCourseOfferingCode())){
335                     int currentIndex = availableCOs.indexOf(coWrapper);
336                     form.setInputCode(coWrapper.getCourseOfferingCode());
337                     if (currentIndex > 0){
338                         form.setPreviousCourseOfferingWrapper(availableCOs.get(currentIndex-1));
339                     }else{
340                         form.setPreviousCourseOfferingWrapper(null);
341                     }
342                     if (currentIndex < availableCOs.size()-1){
343                         form.setNextCourseOfferingWrapper(availableCOs.get(currentIndex+1));
344                     }else{
345                         form.setNextCourseOfferingWrapper(null);
346                     }
347                     break;
348                 }
349             }
350 
351         } catch(Exception e) {
352             throw new RuntimeException(e);
353         }
354     }
355 
356     public void createActivityOfferings(String formatId, String activityId, int noOfActivityOfferings, CourseOfferingManagementForm form){
357         String termcode;
358         FormatInfo format = null;
359         CourseInfo course;
360         CourseOfferingInfo courseOffering = form.getCurrentCourseOfferingWrapper().getCourseOfferingInfo();
361 
362         ContextInfo contextInfo = createContextInfo();
363 
364         // Get the format object for the id selected
365         try {
366             course = getCourseService().getCourse(courseOffering.getCourseId(), contextInfo);
367             for (FormatInfo f : course.getFormats()) {
368                 if(f.getId().equals(formatId)) {
369                     format = f;
370                     break;
371                 }
372             }
373         } catch (Exception e) {
374             throw new RuntimeException(e);
375         }
376 
377         // find the format offering object for the selected format
378         FormatOfferingInfo formatOfferingInfo = null;
379         try {
380             List<FormatOfferingInfo> courseOfferingFOs = getCourseOfferingService().getFormatOfferingsByCourseOffering(courseOffering.getId(), contextInfo);
381             for(FormatOfferingInfo fo : courseOfferingFOs) {
382                 if (fo.getFormatId().equals(formatId)) {
383                     formatOfferingInfo = fo;
384                     break;
385                 }
386             }
387         } catch (Exception e) {
388             throw new RuntimeException(e);
389         }
390 
391         // find the Activity object that matches the activity id selected
392         ActivityInfo activity = null;
393         //FindBugs: getActivities() null check is in FormatInfo
394         List<ActivityInfo> activities = format.getActivities();
395         for (ActivityInfo info : activities) {
396             if (StringUtils.equals(activityId, info.getId())) {
397                 activity = info;
398             }
399         }
400 
401         // Get the matching activity offering type for the selected activity
402         TypeInfo activityOfferingType;
403         try {
404             List<TypeInfo> types = getTypeService().getAllowedTypesForType(activity.getTypeKey(), contextInfo);
405             // only one AO type should be mapped to each Activity type
406             if(types.size() > 1) {
407                 throw new RuntimeException("More than one allowed type is matched to activity type of: " + activity.getTypeKey());
408             }
409             if(types.isEmpty()){
410                 throw new RuntimeException("No Clu to Lui type mapping found in TypeService for: " + activity.getTypeKey());
411             }
412 
413             activityOfferingType = types.get(0);
414         } catch (Exception e) {
415             throw new RuntimeException(e);
416         }
417 
418         try {
419             AtpInfo termAtp = getAtpService().getAtp(courseOffering.getTermId(), contextInfo);
420             termcode = termAtp.getCode();
421         } catch (Exception e) {
422             throw new RuntimeException(e);
423         }
424 
425         for (int i=0;i<noOfActivityOfferings;i++){
426             ActivityOfferingInfo aoInfo = new ActivityOfferingInfo();
427             aoInfo.setActivityId(activityId);
428             aoInfo.setFormatOfferingId(formatOfferingInfo.getId());
429             aoInfo.setTypeKey(activityOfferingType.getKey());
430             aoInfo.setCourseOfferingId(courseOffering.getId());
431             aoInfo.setStateKey(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY);
432             aoInfo.setTermId(courseOffering.getTermId());
433             aoInfo.setTermCode(termcode);
434             aoInfo.setFormatOfferingName(formatOfferingInfo.getName());
435             aoInfo.setCourseOfferingTitle(courseOffering.getCourseOfferingTitle());
436             aoInfo.setCourseOfferingCode(courseOffering.getCourseOfferingCode());
437 
438             try {
439                 ActivityOfferingInfo activityOfferingInfo = _getCourseOfferingService().createActivityOffering(formatOfferingInfo.getId(), activityId, activityOfferingType.getKey(), aoInfo, contextInfo);
440                 ActivityOfferingWrapper wrapper = new ActivityOfferingWrapper(activityOfferingInfo);
441                 StateInfo state = getStateService().getState(wrapper.getAoInfo().getStateKey(), contextInfo);
442                 wrapper.setStateName(state.getName());
443                 TypeInfo typeInfo = getTypeInfo(wrapper.getAoInfo().getTypeKey());
444                 wrapper.setTypeName(typeInfo.getName());
445                 form.getActivityWrapperList().add(wrapper);
446             } catch (Exception e) {
447                 throw new RuntimeException(e);
448             }
449         }
450 
451         ToolbarUtil.processAoToolbarForUser(form.getActivityWrapperList(), form);
452         if(noOfActivityOfferings == 1){
453             KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_ADD_1_SUCCESS);
454         } else {
455             KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_ADD_N_SUCCESS);
456         }
457     }
458 
459     public void loadActivityOfferingsByCourseOffering (CourseOfferingInfo theCourseOfferingInfo, CourseOfferingManagementForm form) throws Exception{
460         String courseOfferingId = theCourseOfferingInfo.getId();
461         List<ActivityOfferingInfo> activityOfferingInfoList;
462         List<ActivityOfferingWrapper> activityOfferingWrapperList;
463 
464         try {
465             activityOfferingInfoList =_getCourseOfferingService().getActivityOfferingsByCourseOffering(courseOfferingId, createContextInfo());
466             activityOfferingWrapperList = new ArrayList<ActivityOfferingWrapper>(activityOfferingInfoList.size());
467 
468             for (ActivityOfferingInfo info : activityOfferingInfoList) {
469                 ActivityOfferingWrapper aoWrapper = convertAOInfoToWrapper(info);
470                 activityOfferingWrapperList.add(aoWrapper);
471             }
472         } catch (Exception e) {
473             throw new RuntimeException(String.format("Could not load AOs for course offering [%s].", courseOfferingId), e);
474         }
475         form.setActivityWrapperList(activityOfferingWrapperList);
476     }
477 
478     public List<ActivityOfferingWrapper> getActivityOfferingsByCourseOfferingId (String courseOfferingId, CourseOfferingManagementForm form) throws Exception{
479         List<ActivityOfferingInfo> activityOfferingInfoList;
480         List<ActivityOfferingWrapper> activityOfferingWrapperList;
481 
482         try {
483             activityOfferingInfoList =_getCourseOfferingService().getActivityOfferingsByCourseOffering(courseOfferingId, createContextInfo());
484             activityOfferingWrapperList = new ArrayList<ActivityOfferingWrapper>(activityOfferingInfoList.size());
485 
486             for (ActivityOfferingInfo info : activityOfferingInfoList) {
487                 ActivityOfferingWrapper aoWrapper = new ActivityOfferingWrapper(info);
488                 activityOfferingWrapperList.add(aoWrapper);
489             }
490         } catch (Exception e) {
491             throw new RuntimeException(String.format("Could not load AOs for course offering [%s].", courseOfferingId), e);
492         }
493         return activityOfferingWrapperList;
494     }
495 
496     public void approveCourseOfferings(CourseOfferingManagementForm form) throws Exception{
497         List<CourseOfferingListSectionWrapper> coList = form.getCourseOfferingResultList();
498         ContextInfo contextInfo = createContextInfo();
499         int checked = 0;
500         int enabled = 0;
501         for(CourseOfferingListSectionWrapper co : coList) {
502             if(co.getIsChecked()){
503                 checked++;
504                  if(co.isEnableApproveButton()) {
505                      enabled++;
506                      List<ActivityOfferingWrapper> aos = getActivityOfferingsByCourseOfferingId(co.getCourseOfferingId(), form);
507                      if(aos != null && !aos.isEmpty()){
508                          ToolbarUtil.processAoToolbarForUser(aos, form);
509                          for(ActivityOfferingWrapper ao : aos){
510                             if(ao.isEnableApproveButton()){
511                                 getCourseOfferingService().changeActivityOfferingState(ao.getAoInfo().getId(), LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, contextInfo);
512                             }
513                         }
514                     }
515                 }
516             }
517          }
518 
519         if(checked > enabled){
520             KSUifUtils.addGrowlMessageIcon(GrowlIcon.WARNING, CourseOfferingConstants.COURSEOFFERING_TOOLBAR_APPROVED);
521         }else{
522             if(enabled == 1){
523                 KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.COURSEOFFERING_TOOLBAR_APPROVED_1_SUCCESS);
524             }else {
525                 KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.COURSEOFFERING_TOOLBAR_APPROVED_N_SUCCESS);
526             }
527         }
528     }
529 
530     public void deleteCourseOfferings(CourseOfferingManagementForm form) throws Exception {
531         List<CourseOfferingListSectionWrapper> coList = form.getCourseOfferingResultList();
532         int checked = 0;
533         int enabled = 0;
534         int totalCosToDelete = 0;
535         int totalColocatedCos = 0;
536         int totalColocatedAos = 0;
537         boolean iscolocated = false;
538         int totalCrossListedCosToDelete = 0;
539         int totalJointDefinedCosToDelete = 0;
540 
541         form.setNumOfColocatedCosToDelete(0);
542         form.setNumOfColocatedAosToDelete(0);
543         form.setNumOfCrossListedCosToDelete(0);
544         form.setNumOfJointDefinedCosToDelete(0);
545 
546         List<CourseOfferingListSectionWrapper> qualifiedToDeleteList = form.getSelectedCoToDeleteList();
547         qualifiedToDeleteList.clear();
548         ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();
549 
550         int totalAos = 0;
551         form.setCrossListedCO(false);
552         form.setColocatedCO(false);
553         for (CourseOfferingListSectionWrapper co : coList) {
554             boolean hasDeletion = true;
555             if (co.getIsChecked()) {
556                 checked++;
557                 totalCosToDelete++;
558                 iscolocated = false;
559 
560                 List<ActivityOfferingDisplayInfo> aoDisplayInfoList = getCourseOfferingService().getActivityOfferingDisplaysForCourseOffering(co.getCourseOfferingId(), contextInfo);
561                 List<ActivityOfferingInfo> aoInfoList = getCourseOfferingService().getActivityOfferingsByCourseOffering(co.getCourseOfferingId(), contextInfo);
562 
563                 co.setCoHasAoToDelete(true);
564                 if (aoDisplayInfoList.isEmpty()) {
565                     co.setCoHasAoToDelete(false);
566                 }
567                 co.setColocated(false);
568 
569                 if (aoDisplayInfoList != null && !aoDisplayInfoList.isEmpty()) {
570                     for (ActivityOfferingDisplayInfo aoDisplayInfo : aoDisplayInfoList) {
571 
572                         ActivityOfferingDisplayWrapper aoDisplayWrapper = new ActivityOfferingDisplayWrapper();
573                         aoDisplayWrapper.setAoDisplayInfo(aoDisplayInfo);
574                         aoDisplayWrapper.setActivityOfferingCode(aoDisplayInfo.getActivityOfferingCode());
575                         // Adding Information (icons)
576                         String information = "";
577                         if (aoDisplayInfo.getIsHonorsOffering() != null && aoDisplayInfo.getIsHonorsOffering()) {
578                             information = "<img src=" + ScheduleOfClassesConstants.SOC_RESULT_PAGE_HONORS_COURSE_IMG + " title=\"" + ScheduleOfClassesConstants.SOC_RESULT_PAGE_HELP_HONORS_ACTIVITY + "\"> ";
579                         }
580                         aoDisplayWrapper.setInformation(information);
581 
582                         if (aoDisplayInfo.getScheduleDisplay() != null && !aoDisplayInfo.getScheduleDisplay().getScheduleComponentDisplays().isEmpty()) {
583                             //TODO handle TBA state
584                             //ScheduleComponentDisplay scheduleComponentDisplay = aoDisplayInfo.getScheduleDisplay().getScheduleComponentDisplays().get(0);
585                             List<ScheduleComponentDisplayInfo> scheduleComponentDisplays = (List<ScheduleComponentDisplayInfo>) aoDisplayInfo.getScheduleDisplay().getScheduleComponentDisplays();
586                             for (ScheduleComponentDisplay scheduleComponentDisplay : scheduleComponentDisplays) {
587                                 if (scheduleComponentDisplay.getBuilding() != null) {
588                                     aoDisplayWrapper.setBuildingName(scheduleComponentDisplay.getBuilding().getBuildingCode(), true);
589                                 }
590                                 if (scheduleComponentDisplay.getRoom() != null) {
591                                     aoDisplayWrapper.setRoomName(scheduleComponentDisplay.getRoom().getRoomCode(), true);
592                                 }
593                                 if (!scheduleComponentDisplay.getTimeSlots().isEmpty()) {
594                                     if (scheduleComponentDisplay.getTimeSlots().get(0).getStartTime() != null) {
595                                         aoDisplayWrapper.setStartTimeDisplay(millisToTime(scheduleComponentDisplay.getTimeSlots().get(0).getStartTime().getMilliSeconds()), true);
596                                     }
597                                     if (scheduleComponentDisplay.getTimeSlots().get(0).getEndTime() != null) {
598                                         aoDisplayWrapper.setEndTimeDisplay(millisToTime(scheduleComponentDisplay.getTimeSlots().get(0).getEndTime().getMilliSeconds()), true);
599                                     }
600                                     aoDisplayWrapper.setDaysDisplayName(getDays(scheduleComponentDisplay.getTimeSlots().get(0).getWeekdays()), true);
601                                 }
602                             }
603                         }
604                         // if ao is colocated AO add colocated info
605                         if(isColocatedAo(aoDisplayInfo.getActivityOfferingCode(), aoInfoList))  {
606                             String colocateInfo = CourseOfferingViewHelperUtil.createColocatedDisplayData(getAoInfo(aoDisplayInfo.getActivityOfferingCode(), aoInfoList), contextInfo);
607                             aoDisplayWrapper.setColocatedAoInfo(colocateInfo);
608                             co.setColocated(true);
609                             co.setColocatedCoCode(colocateInfo);
610                             form.setColocatedCO(true);
611                             totalColocatedAos++;
612                             iscolocated = true;
613                         }
614                         co.getAoToBeDeletedList().add(aoDisplayWrapper);
615                     }
616 
617                     totalAos = totalAos + co.getAoToBeDeletedList().size();
618                     co.setCrossListed(false);
619                     if (co.getAlternateCOCodes() != null && co.getAlternateCOCodes().size() > 0) {
620                         co.setCrossListed(true);
621                         form.setCrossListedCO(true);
622                         totalCrossListedCosToDelete++;
623                     }
624                 }
625                 co.setJointDefined(false);
626 
627                 if(iscolocated) {
628                     totalColocatedCos++;
629                 } else {
630                     // verify whether this CO is joint-defined or not
631                     String jointDefinedCodes = getJointDefinedInfo(co);
632                     if(!jointDefinedCodes.isEmpty()) {
633                         co.setJointDefinedCoCode(jointDefinedCodes);
634                         co.setJointDefined(true);
635                         totalJointDefinedCosToDelete++;
636                     }
637                 }
638                 qualifiedToDeleteList.add(co);
639 
640                 if (hasDeletion) {
641                     enabled++;
642                 }
643             }
644         }
645         form.setNumOfCrossListedCosToDelete(totalCrossListedCosToDelete);
646         form.setNumOfJointDefinedCosToDelete(totalJointDefinedCosToDelete);
647         if(totalColocatedCos == totalCosToDelete) {
648             form.setColocatedCoOnly(true);
649             form.setNumOfColocatedCosToDelete(totalColocatedCos);
650         }
651         if(totalJointDefinedCosToDelete >= 1)  {
652             form.setJointDefinedCo(true);
653         }
654         form.setNumOfColocatedAosToDelete(totalColocatedAos);
655         form.setTotalAOsToBeDeleted(totalAos);
656     }
657 
658     public void approveActivityOfferings(CourseOfferingManagementForm form) throws Exception{
659         List<ActivityOfferingWrapper> aoList = form.getActivityWrapperList();
660         ContextInfo contextInfo = createContextInfo();
661         int checked = 0;
662         int enabled = 0;
663         for(ActivityOfferingWrapper ao : aoList) {
664             if(ao.getIsChecked()){
665                 checked++;
666                  if(ao.isEnableApproveButton()) {
667                      enabled++;
668                     getCourseOfferingService().changeActivityOfferingState(ao.getAoInfo().getId(), LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, contextInfo);
669                  }
670             }
671          }
672 
673         if(checked > enabled){
674             KSUifUtils.addGrowlMessageIcon(GrowlIcon.WARNING, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_APPROVED);
675         }else{
676             if(enabled == 1){
677                 KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_APPROVED_1_SUCCESS);
678             }else {
679                 KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_APPROVED_N_SUCCESS);
680             }
681         }
682     }
683 
684     public void draftActivityOfferings(CourseOfferingManagementForm form) throws Exception{
685         List<ActivityOfferingWrapper> aoList = form.getActivityWrapperList();
686         ContextInfo contextInfo = createContextInfo();
687         int checked = 0;
688         int enabled = 0;
689         for(ActivityOfferingWrapper ao : aoList) {
690              if(ao.getIsChecked()){
691                  checked++;
692                  if(ao.isEnableDraftButton()) {
693                      enabled++;
694                     getCourseOfferingService().changeActivityOfferingState(ao.getAoInfo().getId(), LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY, contextInfo);
695                  }
696              }
697          }
698 
699         if(checked > enabled){
700             KSUifUtils.addGrowlMessageIcon(GrowlIcon.WARNING, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_DRAFT);
701         }else{
702             if(enabled == 1){
703                 KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_DRAFT_1_SUCCESS);
704             }else {
705                 KSUifUtils.addGrowlMessageIcon(GrowlIcon.INFORMATION, CourseOfferingConstants.ACTIVITYOFFERING_TOOLBAR_DRAFT_N_SUCCESS);
706             }
707         }
708 
709     }
710     /**
711      * @param aoList The list of AOs to evaluate.
712      * @param selectedAction The state change action to perform.
713      * @throws Exception
714      */
715     public void changeActivityOfferingsState(List<ActivityOfferingWrapper> aoList, CourseOfferingInfo courseOfferingInfo, String selectedAction) throws Exception {
716         ContextInfo contextInfo = createContextInfo();
717         StateInfo draftState = getStateService().getState(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY, contextInfo);
718         StateInfo approvedState = getStateService().getState(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, contextInfo);
719 
720         boolean hasBadStateWarning = false, hasStateChangedAO = false, isDraftAction = false;
721         String messageKeyWarn, messageKeyError;
722 
723         //  Setup feedback message keys.
724         if (StringUtils.equals(CourseOfferingConstants.ACTIVITY_OFFERING_DRAFT_ACTION, selectedAction)) {
725             isDraftAction = true;
726             messageKeyWarn = CourseOfferingConstants.COURSEOFFERING_SET_TO_DRAFT_SOME_AOS_UPATED;
727             messageKeyError = CourseOfferingConstants.COURSEOFFERING_SET_TO_DRAFT_NO_AOS_UPDATED;
728         } else {
729             messageKeyWarn = CourseOfferingConstants.COURSEOFFERING_APPROVE_FOR_SCHEDULING_SOME_AOS_UPDATED;
730             messageKeyError = CourseOfferingConstants.COURSEOFFERING_APPROVE_FOR_SCHEDULING_NO_AOS_UPDATED;
731         }
732 
733         for (ActivityOfferingWrapper wrapper : aoList) {
734             //  Only evaluate items that were selected/checked in the UI.
735             if (wrapper.getIsChecked()) {
736                 //  If the action is "Set as Draft" then the current state of the AO must be "Approved".
737                 if (isDraftAction) {
738                     if (StringUtils.equals(wrapper.getAoInfo().getStateKey(), LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY)){
739                         wrapper.getAoInfo().setStateKey(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY);
740                         wrapper.setStateName(draftState.getName());
741                         getCourseOfferingService().changeActivityOfferingState(wrapper.getAoInfo().getId(), LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY, contextInfo);
742                         if ( ! hasStateChangedAO) hasStateChangedAO = true;
743                     } else {
744                         if ( ! hasBadStateWarning) hasBadStateWarning = true;
745                     }
746                     //  If the action is "Approve for Scheduling" then AO state must be "Draft"
747                 } else {
748                     if (StringUtils.equals(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY, wrapper.getAoInfo().getStateKey())) {
749                         wrapper.getAoInfo().setStateKey(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY);
750                         wrapper.setStateName(approvedState.getName());
751                         getCourseOfferingService().changeActivityOfferingState(wrapper.getAoInfo().getId(), LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, contextInfo);
752                         if ( ! hasStateChangedAO) hasStateChangedAO = true;
753                     } else {
754                         if ( ! hasBadStateWarning) hasBadStateWarning = true;
755                     }
756                 }
757             }
758         }
759 
760         //  Set feedback message.
761         if ( ! hasStateChangedAO) {
762             GlobalVariables.getMessageMap().putError("selectedOfferingAction", messageKeyError);
763         } else {
764             if (hasBadStateWarning) {
765                 GlobalVariables.getMessageMap().putWarning("selectedOfferingAction", messageKeyWarn);
766             }
767         }
768     }
769 
770     /**
771      *  Same as markCourseOfferingsForScheduling() but defaults isChecked() == true.
772      *  @param coWrappers, viewId, socStateKey provides list of CourseOfferings, viewId, socState.
773      */
774     public void  markCourseOfferingsForScheduling(List<CourseOfferingListSectionWrapper> coWrappers, String viewId, String socStateKey) throws Exception {
775         markCourseOfferingsForScheduling(coWrappers, viewId, socStateKey, true);
776     }
777 
778     /**
779      *  Examines a List of CourseOffering wrappers and changes the state of each "checked" AO (meaning the
780      *  CO was selected on the UI) from "Draft" to "Approved". If the AO has a state other than "Draft" the AO is ignored.
781      *  Also, changes the state of the CourseOffering if appropriate.
782      *
783      * @param coWrappers, viewId, socStateKey provides list of CourseOfferings, viewId, socState.
784      * @param checkedOnly True if the CO wrapper isChecked() flag should be respected.
785      */
786     public void markCourseOfferingsForScheduling(List<CourseOfferingListSectionWrapper> coWrappers, String viewId, String socStateKey, boolean checkedOnly) throws Exception {
787         boolean hasAOWarning = false, hasStateChangedAO = false, hasOrgWarning = false;
788         ContextInfo contextInfo = createContextInfo();
789         for (CourseOfferingListSectionWrapper coWrapper : coWrappers) {
790             if (coWrapper.getIsChecked() || ! checkedOnly) {
791                 // Checking if the person is authorized to approve
792                 Map<String,String> permissionDetails = new HashMap<String,String>();
793                 Map<String,String> roleQualifications = new HashMap<String,String>();
794                 CourseOfferingInfo coInfo = getCourseOfferingService().getCourseOffering(coWrapper.getCourseOfferingId(), contextInfo);
795                 List<String> orgIds = coInfo.getUnitsDeploymentOrgIds();
796                 String orgIDs = "";
797                 if(orgIds != null && !orgIds.isEmpty()){
798                     for (String orgId : orgIds) {
799                         orgIDs = orgIDs + orgId + ",";
800                     }
801                 }
802                 boolean canApproveAOs = true;
803                 if (orgIDs.length() > 0) {
804                     String principalId = GlobalVariables.getUserSession().getPerson().getPrincipalId();
805 
806                     roleQualifications.put("org", orgIDs.substring(0, orgIDs.length()-1));
807 
808                     permissionDetails.put(KimConstants.AttributeConstants.VIEW_ID, viewId);
809                     permissionDetails.put(KimConstants.AttributeConstants.ACTION_EVENT, "approveSubj");
810 
811                     String socState = socStateKey==null?null:socStateKey.substring(socStateKey.lastIndexOf('.')+1);
812                     permissionDetails.put("socState", socState);
813 
814                     canApproveAOs = getPermissionService().isAuthorizedByTemplate(principalId, "KS-ENR", KimConstants.PermissionTemplateNames.PERFORM_ACTION, permissionDetails, roleQualifications);
815                 }
816 
817                 if (!canApproveAOs) {  // if can't approve AOs for all COs (because they are in a different org)
818                     if (!hasOrgWarning) hasOrgWarning = true;
819                     continue;
820                 } else {
821                     List<ActivityOfferingInfo> activityOfferingInfos = getCourseOfferingService().getActivityOfferingsByCourseOffering(coWrapper.getCourseOfferingId(),contextInfo);
822                     if (activityOfferingInfos.size() == 0) {
823                         if ( ! hasAOWarning) hasAOWarning = true;
824                         continue;
825                     }
826                     // Iterate through the AOs and state change Draft -> Approved.
827                     for (ActivityOfferingInfo activityOfferingInfo : activityOfferingInfos) {
828                         boolean isAOStateDraft = StringUtils.equals(activityOfferingInfo.getStateKey(), LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY);
829                         if (isAOStateDraft) {
830                             StatusInfo statusInfo = getCourseOfferingService().changeActivityOfferingState(activityOfferingInfo.getId(), LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, contextInfo);
831                             if (!statusInfo.getIsSuccess()){
832                                 GlobalVariables.getMessageMap().putError("manageCourseOfferingsPage", CourseOfferingConstants.COURSE_OFFERING_STATE_CHANGE_ERROR,coWrapper.getCourseOfferingCode(),statusInfo.getMessage());
833                             }
834                             //  Flag if any AOs can be state changed. This affects the error message whi.
835                             if (statusInfo.getIsSuccess()){
836                                 hasStateChangedAO = true;
837                             }
838                         } else {
839                             //  Flag if any AOs are not in a valid state for approval.
840                             if ( ! hasAOWarning) hasAOWarning = true;
841                         }
842                     }
843                 }
844             }
845         }
846         //  Set feedback messages.
847         if (!hasStateChangedAO) {
848             GlobalVariables.getMessageMap().putError("manageCourseOfferingsPage", CourseOfferingConstants.COURSEOFFERING_NONE_APPROVED);
849         } else {
850             if (hasAOWarning) {
851                 GlobalVariables.getMessageMap().putWarning("manageCourseOfferingsPage", CourseOfferingConstants.COURSEOFFERING_WITH_AO_DRAFT_APPROVED_ONLY);
852             }
853             if (hasOrgWarning) {
854                 GlobalVariables.getMessageMap().putWarning("manageCourseOfferingsPage", CourseOfferingConstants.COURSEOFFERING_WITH_AO_ORG_APPROVED_ONLY);
855             }
856         }
857     }
858 
859     public void setSocStateKeys (CourseOfferingManagementForm form) throws Exception{
860         String termCode = form.getTermInfo().getId();
861         List<String> socIds = getSocService().getSocIdsByTerm(termCode, createContextInfo());
862         if (socIds != null && !socIds.isEmpty()) {
863             List<SocInfo> targetSocs = this.getSocService().getSocsByIds(socIds, createContextInfo());
864             for (SocInfo soc: targetSocs) {
865                 if (soc.getTypeKey().equals(CourseOfferingSetServiceConstants.MAIN_SOC_TYPE_KEY)) {
866                     form.setSocStateKey(soc.getStateKey());
867                     form.setSocSchedulingStateKey(soc.getSchedulingStateKey());
868                     return;
869                 }
870             }
871         }
872     }
873 
874     public static String trimTrailing0(String creditValue){
875         if (creditValue.indexOf(".0") > 0) {
876             return creditValue.substring(0, creditValue.length( )- 2);
877         } else {
878             return creditValue;
879         }
880     }
881 
882     private boolean isColocatedAo(String aoCode, List<ActivityOfferingInfo> aoList) {
883         for(ActivityOfferingInfo ao : aoList) {
884             if(StringUtils.equals(aoCode, ao.getActivityCode())) {
885                 if(ao.getIsPartOfColocatedOfferingSet()) {
886                     return true;
887                 }
888             }
889         }
890         return false;
891     }
892 
893     private ActivityOfferingInfo getAoInfo(String aoCode, List<ActivityOfferingInfo> aoList) {
894         for(ActivityOfferingInfo ao : aoList) {
895             if(StringUtils.equals(aoCode, ao.getActivityCode())) {
896                 if(ao.getIsPartOfColocatedOfferingSet()) {
897                     return ao;
898                 }
899             }
900         }
901         return null;
902     }
903 
904     private String getJointDefinedInfo(CourseOfferingListSectionWrapper co) {
905         if(co == null) return null;
906 
907         List<CourseInfo> coInfoList = CourseOfferingViewHelperUtil.getMatchingCoursesFromClu(co.getCourseOfferingCode());
908         StringBuffer jointDefinedCodes  = new StringBuffer();
909 
910         for(CourseInfo coInfo : coInfoList) {
911             List<CourseJointInfo> jointList = coInfo.getJoints();
912            if(!jointList.isEmpty() && jointList.size() >= 1 ) {
913                for(CourseJointInfo jointInfo : jointList)  {
914                    jointDefinedCodes.append(jointInfo.getSubjectArea());
915                    jointDefinedCodes.append(jointInfo.getCourseNumberSuffix());
916                    jointDefinedCodes.append(" ");
917                }
918 
919             }
920         }
921 
922         return jointDefinedCodes.toString();
923     }
924 
925     private CourseOfferingService _getCourseOfferingService() {
926         if (coService == null) {
927             coService = (CourseOfferingService) GlobalResourceLoader.getService(new QName(CourseOfferingServiceConstants.NAMESPACE,
928                     CourseOfferingServiceConstants.SERVICE_NAME_LOCAL_PART));
929         }
930         return coService;
931     }
932 
933     private AcademicCalendarService getAcalService() {
934         if (acalService == null) {
935             acalService = (AcademicCalendarService) GlobalResourceLoader.getService(new QName(AcademicCalendarServiceConstants.NAMESPACE,
936                     AcademicCalendarServiceConstants.SERVICE_NAME_LOCAL_PART));
937         }
938         return acalService;
939     }
940 
941     private String millisToTime(Long milliseconds){
942         if(milliseconds == null){
943             return null;
944         }
945         final Calendar cal = Calendar.getInstance();
946         cal.setTimeInMillis(milliseconds);
947         return DateFormatters.HOUR_MINUTE_AM_PM_TIME_FORMATTER.format(cal.getTime());
948 
949     }
950 
951     private String convertIntoDaysDisplay(int day) {
952         String dayOfWeek;
953         switch (day) {
954             case 1:
955                 dayOfWeek = SchedulingServiceConstants.SUNDAY_TIMESLOT_DISPLAY_DAY_CODE;
956                 break;
957             case 2:
958                 dayOfWeek = SchedulingServiceConstants.MONDAY_TIMESLOT_DISPLAY_DAY_CODE;
959                 break;
960             case 3:
961                 dayOfWeek = SchedulingServiceConstants.TUESDAY_TIMESLOT_DISPLAY_DAY_CODE;
962                 break;
963             case 4:
964                 dayOfWeek = SchedulingServiceConstants.WEDNESDAY_TIMESLOT_DISPLAY_DAY_CODE;
965                 break;
966             case 5:
967                 dayOfWeek = SchedulingServiceConstants.THURSDAY_TIMESLOT_DISPLAY_DAY_CODE;
968                 break;
969             case 6:
970                 dayOfWeek = SchedulingServiceConstants.FRIDAY_TIMESLOT_DISPLAY_DAY_CODE;
971                 break;
972             case 7:
973                 dayOfWeek = SchedulingServiceConstants.SATURDAY_TIMESLOT_DISPLAY_DAY_CODE;
974                 break;
975             default:
976                 dayOfWeek = StringUtils.EMPTY;
977         }
978         // TODO implement TBA when service stores it.
979         return dayOfWeek;
980     }
981 
982     private String getDays(List<Integer> intList) {
983 
984         StringBuilder sb = new StringBuilder();
985         if(intList == null){
986             return sb.toString();
987         }
988 
989         for(Integer d : intList) {
990             sb.append(convertIntoDaysDisplay(d));
991         }
992 
993         return sb.toString();
994     }
995 
996     public CourseOfferingService getCourseOfferingService() {
997         return CourseOfferingResourceLoader.loadCourseOfferingService();
998     }
999 
1000     public CourseService getCourseService() {
1001         if (courseService == null){
1002             courseService = CourseOfferingResourceLoader.loadCourseService();
1003         }
1004         return courseService;
1005     }
1006 
1007 
1008     protected LRCService getLrcService() {
1009         if(lrcService == null) {
1010             lrcService = (LRCService) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/lrc", "LrcService"));
1011         }
1012         return this.lrcService;
1013     }
1014 
1015     protected SearchService getSearchService() {
1016         if(searchService == null) {
1017             searchService = (SearchService) GlobalResourceLoader.getService(new QName(CommonServiceConstants.REF_OBJECT_URI_GLOBAL_PREFIX + "search", SearchService.class.getSimpleName()));
1018         }
1019         return searchService;
1020     }
1021     public AtpService getAtpService() {
1022         if (atpService == null){
1023             atpService = CourseOfferingResourceLoader.loadAtpService();
1024         }
1025         return atpService;
1026     }
1027 
1028     public CourseOfferingSetService getSocService() {
1029         // If it hasn't been set by Spring, then look it up by GlobalResourceLoader
1030         if (socService == null) {
1031             socService = (CourseOfferingSetService) GlobalResourceLoader.getService(new QName(CourseOfferingSetServiceConstants.NAMESPACE,
1032                                                                                     CourseOfferingSetServiceConstants.SERVICE_NAME_LOCAL_PART));
1033         }
1034         return socService;
1035     }
1036 
1037     private static PermissionService getPermissionService() {
1038         if(permissionService == null){
1039             permissionService = KimApiServiceLocator.getPermissionService();
1040         }
1041         return permissionService;
1042     }
1043 }