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 vgadiyak on 9/10/12
16   */
17  package org.kuali.student.enrollment.class2.scheduleofclasses.controller;
18  
19  /**
20   * This class provides a controller for the Schedule of Classes ui
21   *
22   * @author Kuali Student Team
23   */
24  
25  import org.apache.commons.lang.StringUtils;
26  import org.kuali.rice.core.api.config.property.ConfigContext;
27  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
28  import org.kuali.rice.krad.util.GlobalVariables;
29  import org.kuali.rice.krad.web.controller.UifControllerBase;
30  import org.kuali.rice.krad.web.form.UifFormBase;
31  import org.kuali.student.common.uif.util.KSControllerHelper;
32  import org.kuali.student.enrollment.class2.courseoffering.dto.ActivityOfferingClusterWrapper;
33  import org.kuali.student.enrollment.class2.courseoffering.dto.ActivityOfferingWrapper;
34  import org.kuali.student.enrollment.class2.courseoffering.dto.RegistrationGroupWrapper;
35  import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingResourceLoader;
36  import org.kuali.student.enrollment.class2.scheduleofclasses.dto.CourseOfferingDisplayWrapper;
37  import org.kuali.student.enrollment.class2.scheduleofclasses.form.ScheduleOfClassesSearchForm;
38  import org.kuali.student.enrollment.class2.scheduleofclasses.service.ScheduleOfClassesViewHelperService;
39  import org.kuali.student.enrollment.class2.scheduleofclasses.util.SOCRequisiteWrapper;
40  import org.kuali.student.enrollment.class2.scheduleofclasses.util.ScheduleOfClassesConstants;
41  import org.kuali.student.enrollment.class2.scheduleofclasses.util.ScheduleOfClassesUtil;
42  import org.kuali.student.enrollment.courseofferingset.service.CourseOfferingSetService;
43  import org.kuali.student.r2.common.dto.ContextInfo;
44  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
45  import org.kuali.student.r2.common.exceptions.OperationFailedException;
46  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
47  import org.kuali.student.r2.common.util.ContextUtils;
48  import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants;
49  import org.kuali.student.r2.core.acal.dto.TermInfo;
50  import org.kuali.student.r2.core.acal.service.AcademicCalendarService;
51  import org.kuali.student.r2.core.atp.dto.AtpInfo;
52  import org.kuali.student.r2.core.atp.service.AtpService;
53  import org.kuali.student.r2.core.class1.search.ActivityOfferingSearchServiceImpl;
54  import org.kuali.student.r2.core.class1.type.dto.TypeInfo;
55  import org.kuali.student.r2.core.class1.type.dto.TypeTypeRelationInfo;
56  import org.kuali.student.r2.core.class1.type.service.TypeService;
57  import org.kuali.student.r2.core.constants.AcademicCalendarServiceConstants;
58  import org.kuali.student.r2.core.constants.AtpServiceConstants;
59  import org.kuali.student.r2.core.constants.TypeServiceConstants;
60  import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
61  import org.springframework.stereotype.Controller;
62  import org.springframework.validation.BindingResult;
63  import org.springframework.web.bind.annotation.ModelAttribute;
64  import org.springframework.web.bind.annotation.RequestMapping;
65  import org.springframework.web.bind.annotation.RequestMethod;
66  import org.springframework.web.servlet.ModelAndView;
67  
68  import javax.servlet.http.HttpServletRequest;
69  import javax.servlet.http.HttpServletResponse;
70  import javax.xml.namespace.QName;
71  import java.util.ArrayList;
72  import java.util.HashMap;
73  import java.util.List;
74  import java.util.Map;
75  
76  @Controller
77  @RequestMapping(value = "/scheduleOfClassesSearch")
78  public class ScheduleOfClassesSearchController extends UifControllerBase {
79  
80      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ScheduleOfClassesSearchController.class);
81  
82      private static final String MODEL_ATTRIBUTE_FORM = "KualiForm";
83      private static final String SEARCH_TYPE_COURSE = "course";
84      private static final String SEARCH_FIELD = "course";
85      private static final String ERROR_SEARCH_FIELD_CANNOT_BE_EMPTY = "Error: search field can't be empty";
86  
87      @Override
88      protected UifFormBase createInitialForm(HttpServletRequest request) {
89          return new ScheduleOfClassesSearchForm();
90      }
91  
92      @Override
93      @RequestMapping(method = RequestMethod.GET, params = "methodToCall=start")
94      public ModelAndView start( @ModelAttribute( MODEL_ATTRIBUTE_FORM ) UifFormBase form,
95                                 BindingResult result, HttpServletRequest request, HttpServletResponse response) {
96  
97          ScheduleOfClassesSearchForm scheduleOfClassesSearchForm = (ScheduleOfClassesSearchForm) form;
98          scheduleOfClassesSearchForm.setSearchType( SEARCH_TYPE_COURSE );
99  
100         configureCurrentTermCodeOnInitialRequest( scheduleOfClassesSearchForm );
101         //This scenario will be very rare if ever (no published term in db)
102         if (GlobalVariables.getMessageMap().hasErrors() && GlobalVariables.getMessageMap().containsMessageKey(ScheduleOfClassesConstants.SOC_MSG_ERROR_NO_PUBLISHED_TERM)) {
103             return getUIFModelAndView(scheduleOfClassesSearchForm, ScheduleOfClassesConstants.SOC_RESULT_PAGE);
104         }
105         configureDefaultAoDisplayFormat( scheduleOfClassesSearchForm );
106         configureSelectableAoRenderingWidget( scheduleOfClassesSearchForm, request );
107 
108         return super.start(form, result, request, response);
109     }
110 
111     private void configureCurrentTermCodeOnInitialRequest( ScheduleOfClassesSearchForm form ) {
112         if (form.getTermCode() == null) {
113             ContextInfo context = ContextUtils.getContextInfo();
114             List<AtpInfo> atps = ScheduleOfClassesUtil.getValidSocTerms(ScheduleOfClassesUtil.getCourseOfferingSetService(), ScheduleOfClassesUtil.getAtpService(), context);
115             if (atps != null && atps.size() > 0 && !atps.isEmpty()) {
116                 form.setTermCode(ScheduleOfClassesUtil.getClosestAtp(atps).getId());
117             } else {
118                 GlobalVariables.getMessageMap().putError("termCode", ScheduleOfClassesConstants.SOC_MSG_ERROR_NO_PUBLISHED_TERM);
119             }
120         }
121     }
122 
123     private void configureDefaultAoDisplayFormat( ScheduleOfClassesSearchForm form ) {
124         String aoDisplayFormat = ConfigContext.getCurrentContextConfig().getProperty(ScheduleOfClassesConstants.ConfigProperties.AO_DISPLAY_FORMAT);
125         if (StringUtils.isNotBlank(aoDisplayFormat)){
126             ScheduleOfClassesSearchForm.AoDisplayFormat format = ScheduleOfClassesSearchForm.AoDisplayFormat.valueOf(StringUtils.upperCase(aoDisplayFormat));
127             form.setAoDisplayFormat(format);
128         }
129     }
130 
131     private void configureSelectableAoRenderingWidget( ScheduleOfClassesSearchForm form, HttpServletRequest request ) {
132 
133         boolean displaySelectableAoRenderingWidget = false;
134 
135         // URL-parameter overrides setting in kuali config file
136         if( request.getParameter( "showAoDisplayWidget" ) != null ) {
137             displaySelectableAoRenderingWidget = Boolean.valueOf( request.getParameter( "showAoDisplayWidget" ) );
138         } else if(request.getParameter("scheduleOfClassesDisplayFormat") != null) {
139             String urlSelectedRendering = request.getParameter( "scheduleOfClassesDisplayFormat" );
140             if(ScheduleOfClassesSearchForm.AoDisplayFormat.REG_GROUP.getText().equals(urlSelectedRendering)) {
141                 form.setAoDisplayFormat(ScheduleOfClassesSearchForm.AoDisplayFormat.REG_GROUP);
142             } else if(ScheduleOfClassesSearchForm.AoDisplayFormat.CLUSTER.getText().equals(urlSelectedRendering)) {
143                 form.setAoDisplayFormat(ScheduleOfClassesSearchForm.AoDisplayFormat.CLUSTER);
144             } else {
145                 form.setAoDisplayFormat(ScheduleOfClassesSearchForm.AoDisplayFormat.FLAT);
146             }
147         }
148         // Setting in kuali config file is applied if URL-parameter was not supplied
149         // (and in event kuali config file does not specify, then UI widget will be set to not show)
150         else {
151             String allowSelectableAoRendering = ConfigContext.getCurrentContextConfig().getProperty( ScheduleOfClassesConstants.ConfigProperties.ALLOW_SELECTABLE_AO_RENDERING );
152             displaySelectableAoRenderingWidget = Boolean.valueOf( allowSelectableAoRendering );
153         }
154 
155         form.setAllowSelectableAoRendering(displaySelectableAoRenderingWidget);
156     }
157 
158     /**
159      * Method used to
160      * Search for course offerings based on search parameters: term and courseCode/Title&Desc/Instructor/Department
161      */
162     @RequestMapping(params = "methodToCall=show")
163     public ModelAndView show(@ModelAttribute( MODEL_ATTRIBUTE_FORM ) ScheduleOfClassesSearchForm theForm)
164             throws Exception, DoesNotExistException, PermissionDeniedException, OperationFailedException
165     {
166 
167         theForm.getCoDisplayWrapperList().clear();
168 
169         //First, find termName based on termCode
170         String termCode = theForm.getTermCode();
171         if (StringUtils.isNotBlank(termCode)) {
172             String termName = ScheduleOfClassesUtil.getAcademicCalendarService().getTerm(termCode, ContextUtils.createDefaultContextInfo()).getName();
173             theForm.setTermName(termName);
174         } else {
175             LOG.error("Error: term can't be empty");
176             GlobalVariables.getMessageMap().putError("termCode", ScheduleOfClassesConstants.SOC_MSG_ERROR_TERM_IS_EMPTY);
177             return getUIFModelAndView(theForm);
178         }
179 
180         // Second, handle searchType
181         if (theForm.getSearchType().equals( SEARCH_TYPE_COURSE )) {
182             String course = StringUtils.upperCase(theForm.getCourse());
183             if (StringUtils.isNotBlank(course)) {
184                 ScheduleOfClassesUtil.getViewHelperService(theForm).loadCourseOfferingsByTermAndCourseCode(termCode, course, theForm);
185                 theForm.setSearchParameter("Course: " + course);
186             } else {
187                 LOG.error( ERROR_SEARCH_FIELD_CANNOT_BE_EMPTY );
188                 GlobalVariables.getMessageMap().putError( SEARCH_FIELD, ScheduleOfClassesConstants.SOC_MSG_ERROR_COURSE_IS_EMPTY);
189                 return getUIFModelAndView(theForm);
190             }
191         } else if (theForm.getSearchType().equals("instructor")) {
192             String instructorId = theForm.getInstructor();
193             String instructorName = theForm.getInstructorName();
194             if ((StringUtils.isNotBlank(instructorId)) || (StringUtils.isNotBlank(instructorName))) {
195                 ScheduleOfClassesUtil.getViewHelperService(theForm).loadCourseOfferingsByTermAndInstructor(termCode, instructorId, instructorName, theForm);
196                 theForm.setSearchParameter("Instructor: " + instructorName);
197             } else {
198                 LOG.error( ERROR_SEARCH_FIELD_CANNOT_BE_EMPTY );
199                 GlobalVariables.getMessageMap().putError( SEARCH_FIELD, ScheduleOfClassesConstants.SOC_MSG_ERROR_COURSE_IS_EMPTY);
200                 return getUIFModelAndView(theForm);
201             }
202         } else if (theForm.getSearchType().equals("department")) {
203             String departmentId = theForm.getDepartment();
204             String departmentName = theForm.getDepartmentName();
205             if ((StringUtils.isNotBlank(departmentId)) || (StringUtils.isNotBlank(departmentName))) {
206                 ScheduleOfClassesUtil.getViewHelperService(theForm).loadCourseOfferingsByTermAndDepartment(termCode, departmentId, departmentName, theForm);
207                 theForm.setSearchParameter("Department: " + departmentName);
208             } else {
209                 LOG.error( ERROR_SEARCH_FIELD_CANNOT_BE_EMPTY );
210                 GlobalVariables.getMessageMap().putError( SEARCH_FIELD, ScheduleOfClassesConstants.SOC_MSG_ERROR_COURSE_IS_EMPTY);
211                 return getUIFModelAndView(theForm);
212             }
213         } else if (theForm.getSearchType().equals("titleDesc")) {
214             String titleDesc = theForm.getTitleDesc();
215             if (StringUtils.isNotBlank(titleDesc)) {
216                 ScheduleOfClassesUtil.getViewHelperService(theForm).loadCourseOfferingsByTitleAndDescription(termCode, titleDesc, theForm);
217                 theForm.setSearchParameter("Title & Description: " + titleDesc);
218             } else {
219                 LOG.error(ERROR_SEARCH_FIELD_CANNOT_BE_EMPTY );
220                 GlobalVariables.getMessageMap().putError( SEARCH_FIELD, ScheduleOfClassesConstants.SOC_MSG_ERROR_COURSE_IS_EMPTY);
221                 return getUIFModelAndView(theForm);
222             }
223         }
224 
225         return getUIFModelAndView(theForm, ScheduleOfClassesConstants.SOC_RESULT_PAGE);
226     }
227 
228     /**
229      *
230      * Populates the AOs and clusters when the user clicks on the disclosure at the CO display.
231      *
232      * @param theForm
233      * @return
234      * @throws Exception
235      */
236     @RequestMapping(params = "methodToCall=populateAOs")
237     public ModelAndView populateAOs(@ModelAttribute( MODEL_ATTRIBUTE_FORM ) ScheduleOfClassesSearchForm theForm) throws Exception {
238 
239         CourseOfferingDisplayWrapper coDisplayWrapper = (CourseOfferingDisplayWrapper)KSControllerHelper.getSelectedCollectionItem(theForm);
240         theForm.setCourseOfferingId(coDisplayWrapper.getCourseOfferingId());
241 
242         SearchRequestInfo searchRequestInfo = new SearchRequestInfo(ActivityOfferingSearchServiceImpl.AOS_AND_CLUSTERS_BY_CO_ID_SEARCH_KEY);
243 
244         List<String> aoStates = ScheduleOfClassesUtil.getViewHelperService(theForm).getAOStateFilter();
245         searchRequestInfo.addParam(ActivityOfferingSearchServiceImpl.SearchParameters.AO_STATES, aoStates);
246 
247         ScheduleOfClassesUtil.getViewHelperService(theForm).build_AOs_RGs_AOCs_Lists_For_TheCourseOffering(theForm, searchRequestInfo, false);
248 
249         coDisplayWrapper.getClusterResultList().clear();
250         coDisplayWrapper.getClusterResultList().addAll(theForm.getClusterResultList());
251         coDisplayWrapper.getActivityWrapperList().clear();
252         coDisplayWrapper.getActivityWrapperList().addAll(theForm.getActivityWrapperList());
253 
254         SOCRequisiteWrapper requisites =  ScheduleOfClassesUtil.getViewHelperService(theForm).retrieveRequisites(coDisplayWrapper.getCourseOfferingId(), coDisplayWrapper.getActivityWrapperList());
255         coDisplayWrapper.setRequisites(requisites.getCoRequisite().toString());
256 
257         ScheduleOfClassesUtil.getViewHelperService(theForm).sortActivityOfferings(theForm,coDisplayWrapper);
258 
259         Map<String, String> subTermInfoMap = new HashMap<String, String>();
260 
261         ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();
262 
263         for (ActivityOfferingWrapper aoWrapper : coDisplayWrapper.getActivityWrapperList()){
264             //Adding Requisites
265             if(requisites.getAoRequisiteMap().containsKey(aoWrapper.getId())) {
266                 aoWrapper.setRequisite(requisites.getRequisiteForAO(aoWrapper.getId()));
267             }
268 
269             // Adding Information (icons)
270             StringBuilder information = new StringBuilder();
271             if (aoWrapper.getAoInfo().getIsHonorsOffering() != null && aoWrapper.getAoInfo().getIsHonorsOffering()) {
272                 information.append("<img src=").append(ScheduleOfClassesConstants.SOC_RESULT_PAGE_HONORS_COURSE_IMG).append(" title=\"").append(ScheduleOfClassesConstants.SOC_RESULT_PAGE_HELP_HONORS_ACTIVITY).append("\"> ");
273             }
274 
275             // Adding subterm
276             String termId = aoWrapper.getAoInfo().getTermId();
277             String subTermDisplay = "";
278             if (!theForm.getTermCode().equals(termId)) {
279                 if (!subTermInfoMap.containsKey(termId)) {
280                     TermInfo subTerm = ScheduleOfClassesUtil.getAcademicCalendarService().getTerm(termId, contextInfo);
281                     // check if term or subterm
282                     List<TypeTypeRelationInfo> terms = ScheduleOfClassesUtil.getTypeService().getTypeTypeRelationsByRelatedTypeAndType(subTerm.getTypeKey(), TypeServiceConstants.TYPE_TYPE_RELATION_CONTAINS_TYPE_KEY, contextInfo);
283                     // if subterm
284                     if (!terms.isEmpty()) {
285                         TypeInfo subTermType = ScheduleOfClassesUtil.getTypeService().getType(subTerm.getTypeKey(), contextInfo);
286                         subTermDisplay = "This activity is in " + subTermType.getName() + " - " + ScheduleOfClassesUtil.getViewHelperService(theForm).getTermStartEndDate(subTerm);
287                         subTermInfoMap.put(termId, subTermDisplay);
288                         // displaying information
289                         information.append("<img src=").append(ScheduleOfClassesConstants.SOC_RESULT_PAGE_SUBTERM_IMG).append(" title=\"").append(subTermDisplay).append("\"> ");
290                     }
291                 } else {
292                     subTermDisplay = subTermInfoMap.get(termId);
293                     information.append("<img src=").append(ScheduleOfClassesConstants.SOC_RESULT_PAGE_SUBTERM_IMG).append(" title=\"").append(subTermDisplay).append("\"> ");
294                 }
295             }
296 
297             aoWrapper.setSchOfClassesRenderHelper(aoWrapper.new SchOfClassesRenderHelper());
298             aoWrapper.getSchOfClassesRenderHelper().setInformation(information.toString());
299         }
300 
301 
302         return getUIFModelAndView(theForm, ScheduleOfClassesConstants.SOC_RESULT_PAGE);
303     }
304 
305     /**
306      * Populates the reg group when the user clicks on the disclosure at the CO display.
307      *
308      * @param theForm
309      * @return
310      * @throws Exception
311      */
312     @RequestMapping(params = "methodToCall=populateRegGroups")
313     public ModelAndView populateRegGroups(@ModelAttribute( MODEL_ATTRIBUTE_FORM ) ScheduleOfClassesSearchForm theForm) throws Exception {
314 
315         SearchRequestInfo searchRequestInfo = new SearchRequestInfo(ActivityOfferingSearchServiceImpl.AOS_AND_CLUSTERS_BY_CO_ID_SEARCH_KEY);
316 
317         CourseOfferingDisplayWrapper coDisplayWrapper = (CourseOfferingDisplayWrapper)KSControllerHelper.getSelectedCollectionItem(theForm);
318         theForm.setCourseOfferingId(coDisplayWrapper.getCourseOfferingId());
319 
320         List<String> regGroupStates = ScheduleOfClassesUtil.getViewHelperService(theForm).getRegGroupStateFilter();
321         searchRequestInfo.addParam(ActivityOfferingSearchServiceImpl.SearchParameters.REGGROUP_STATES, regGroupStates);
322 
323         ScheduleOfClassesUtil.getViewHelperService(theForm).build_AOs_RGs_AOCs_Lists_For_TheCourseOffering(theForm,searchRequestInfo, true);
324 
325         coDisplayWrapper.getClusterResultList().clear();
326         coDisplayWrapper.getClusterResultList().addAll(theForm.getClusterResultList());
327 
328         /**
329          * Sort the RegGroups first by the ID and then by institutionally configured list of comparators
330          */
331         for (ActivityOfferingClusterWrapper clusterWrapper : coDisplayWrapper.getClusterResultList()){
332             Map<RegistrationGroupWrapper, List<RegistrationGroupWrapper>> regGroupMap = new HashMap<RegistrationGroupWrapper, List<RegistrationGroupWrapper>>();
333             List<RegistrationGroupWrapper> sortRegGroupWrappers = new ArrayList<RegistrationGroupWrapper>();
334 
335             for (int i = 0; i < clusterWrapper.getRgWrapperList().size(); i++) {
336                 RegistrationGroupWrapper registrationGroupWrapper = clusterWrapper.getRgWrapperList().get(i);
337                 for (RegistrationGroupWrapper partnerRegistrationGroupWrappers : clusterWrapper.getRgWrapperList()) {
338                     if (registrationGroupWrapper.getRgInfo().getId().equals(partnerRegistrationGroupWrappers.getRgInfo().getId())) {
339                         if (regGroupMap.containsKey(registrationGroupWrapper)) {
340                             regGroupMap.get(registrationGroupWrapper).add(partnerRegistrationGroupWrappers);
341                             i++;
342                         } else {
343                             regGroupMap.put(registrationGroupWrapper, new ArrayList<RegistrationGroupWrapper>());
344                             regGroupMap.get(registrationGroupWrapper).add(registrationGroupWrapper);
345                         }
346                     }
347                 }
348             }
349 
350             sortRegGroupWrappers.addAll(regGroupMap.keySet());
351 
352             if(clusterWrapper.getRgWrapperList().size() > 1){
353                 //Sort Reg Groups by Reg Group name (which is not institutionally configurable)
354                // Collections.sort(clusterWrapper.getRgWrapperList(),new RegGroupNameComparator());
355                 //Sort by whatever configured at the xml (which are institutionally configurable)
356                 ScheduleOfClassesUtil.getViewHelperService(theForm).sortRegGroups(sortRegGroupWrappers);
357             }
358 
359             clusterWrapper.getRgWrapperList().clear();
360 
361             for (RegistrationGroupWrapper registrationGroupWrapper : sortRegGroupWrappers) {
362                 clusterWrapper.getRgWrapperList().addAll(regGroupMap.get(registrationGroupWrapper));
363             }
364         }
365 
366 
367         SOCRequisiteWrapper requisites =  ScheduleOfClassesUtil.getViewHelperService(theForm).retrieveRequisites(coDisplayWrapper.getCourseOfferingId(), theForm.getActivityWrapperList());
368         coDisplayWrapper.setRequisites(requisites.getCoRequisite().toString());
369         for(ActivityOfferingClusterWrapper activityOfferingClusterWrapper : theForm.getClusterResultList()) {
370             ScheduleOfClassesUtil.loadRegRequisites(requisites, activityOfferingClusterWrapper.getRgWrapperList());
371         }
372 
373         return getUIFModelAndView(theForm, ScheduleOfClassesConstants.SOC_RESULT_PAGE);
374     }
375 }