001    /**
002     * Copyright 2012 The Kuali Foundation Licensed under the
003     * Educational Community License, Version 2.0 (the "License"); you may
004     * not use this file except in compliance with the License. You may
005     * obtain a copy of the License at
006     *
007     * http://www.osedu.org/licenses/ECL-2.0
008     *
009     * Unless required by applicable law or agreed to in writing,
010     * software distributed under the License is distributed on an "AS IS"
011     * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
012     * or implied. See the License for the specific language governing
013     * permissions and limitations under the License.
014     *
015     * @author Kuali Student Team
016     */
017    package org.kuali.student.enrollment.class2.courseoffering.service.impl;
018    
019    
020    import org.apache.commons.lang.StringUtils;
021    import org.kuali.rice.core.api.util.ConcreteKeyValue;
022    import org.kuali.rice.core.api.util.KeyValue;
023    import org.kuali.rice.krad.maintenance.MaintainableImpl;
024    import org.kuali.rice.krad.uif.UifConstants;
025    import org.kuali.rice.krad.uif.control.CheckboxGroupControl;
026    import org.kuali.rice.krad.uif.control.SelectControl;
027    import org.kuali.rice.krad.uif.field.InputField;
028    import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
029    import org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingCreateWrapper;
030    import org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingEditWrapper;
031    import org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingWrapper;
032    import org.kuali.student.enrollment.class2.courseoffering.dto.FormatOfferingWrapper;
033    import org.kuali.student.enrollment.class2.courseoffering.service.CourseOfferingMaintainable;
034    import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingResourceLoader;
035    import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingCrossListingInfo;
036    import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
037    import org.kuali.student.enrollment.courseoffering.dto.FormatOfferingInfo;
038    import org.kuali.student.enrollment.courseoffering.service.CourseOfferingService;
039    import org.kuali.student.r2.common.dto.ContextInfo;
040    import org.kuali.student.r2.common.util.ContextUtils;
041    import org.kuali.student.r2.common.util.constants.LuiServiceConstants;
042    import org.kuali.student.r2.core.class1.state.service.StateService;
043    import org.kuali.student.r2.core.class1.type.dto.TypeInfo;
044    import org.kuali.student.r2.core.class1.type.service.TypeService;
045    import org.kuali.student.r2.lum.course.dto.ActivityInfo;
046    import org.kuali.student.r2.lum.course.dto.CourseCrossListingInfo;
047    import org.kuali.student.r2.lum.course.dto.CourseInfo;
048    import org.kuali.student.r2.lum.course.dto.FormatInfo;
049    import org.kuali.student.r2.lum.course.service.CourseService;
050    
051    import java.util.ArrayList;
052    import java.util.HashSet;
053    import java.util.List;
054    import java.util.Set;
055    
056    /**
057     * Base view helper service for both create and edit course offering presentations.
058     *
059     */
060    public abstract class CourseOfferingMaintainableImpl extends MaintainableImpl implements CourseOfferingMaintainable {
061    
062        private transient CourseOfferingService courseOfferingService;
063        private transient TypeService typeService;
064        private transient StateService stateService;
065        private transient CourseService courseService;
066    
067        /**
068         * This method is being called by KRAD to populate grade roster level types drop down.
069         *
070         * <p>
071         * In 'Create CO', we use a wrapper around <code>FormatOfferingInfo</code> to handle joint formats.
072         * In 'Edit CO', it's just <code>FormatOfferingInfo</code> at the collection
073         * </p>
074         *
075         * <p>There would be no reference for this method in the code as it has it's references at the following view xmls</p>
076         *      <ul>
077         *          <li>CourseOfferingCreateMaintenanceView.xml</li>
078         *          <li>CourseOfferingEditMaintenanceView.xml</li>
079         *      </ul>
080         *
081         * @param field grade roster level field
082         * @param form maintenace form
083         * @see #populateFinalExamDriverTypes
084         */
085        @SuppressWarnings("unused")
086        public void populateGradeRosterLevelTypes(InputField field, MaintenanceDocumentForm form){
087    
088            if (field.isReadOnly()){
089                return;
090            }
091    
092            FormatOfferingInfo formatOfferingInfo;
093            CourseOfferingWrapper wrapper = (CourseOfferingWrapper)form.getDocument().getNewMaintainableObject().getDataObject();
094            CourseInfo courseInfo = wrapper.getCourse();
095    
096            if (wrapper instanceof CourseOfferingCreateWrapper) {
097                /**
098                 * If the call is from create co, then there are two places from where this method is being called. From the 'Add format' section
099                 * and from the format offering collections. For the 'add format' section, we're checking the property name to get the FO Wrapper
100                 */
101                if (StringUtils.equals(field.getPropertyName(),"addLineFormatWrapper.gradeRosterLevelTypeKey")){
102                    formatOfferingInfo = ((CourseOfferingCreateWrapper)wrapper).getAddLineFormatWrapper().getFormatOfferingInfo();
103                } else {
104                    //This else is for the format offering collection.
105                    FormatOfferingWrapper foWrapper = (FormatOfferingWrapper)field.getContext().get(UifConstants.ContextVariableNames.LINE);
106                    formatOfferingInfo = foWrapper.getFormatOfferingInfo();
107                    if (foWrapper.isJointOffering()){
108                        courseInfo = foWrapper.getJointCreateWrapper().getCourseInfo();
109                    }
110                }
111            } else {
112                formatOfferingInfo = (FormatOfferingInfo)field.getContext().get(UifConstants.ContextVariableNames.LINE);
113            }
114    
115            SelectControl control = (SelectControl)field.getControl();
116    
117            List<KeyValue> gradeKeyValues = new ArrayList<KeyValue>();
118    
119            if (StringUtils.isNotBlank(formatOfferingInfo.getFormatId())){
120                // Always include an option for Course
121                gradeKeyValues.add(new ConcreteKeyValue(LuiServiceConstants.COURSE_OFFERING_TYPE_KEY, getTypeName(LuiServiceConstants.COURSE_OFFERING_TYPE_KEY)));
122                gradeKeyValues.addAll(collectActivityTypeKeyValues(courseInfo, formatOfferingInfo.getFormatId(), getTypeService(), ContextUtils.createDefaultContextInfo()));
123                control.setDisabled(false);
124            } else {
125                control.setDisabled(true);
126            }
127    
128            control.setOptions(gradeKeyValues);
129    
130        }
131    
132        /**
133         * This method is being called by KRAD to populate final exam driver types drop down.
134         *
135         * <p>
136         * In 'Create CO', we use a wrapper around <code>FormatOfferingInfo</code> to handle joint formats.
137         * In 'Edit CO', it's just <code>FormatOfferingInfo</code> at the collection
138         * </p>
139         *
140         * <p>There would be no reference for this method in the code as it has it's references at the following view xmls</p>
141         *      <ul>
142         *          <li>CourseOfferingCreateMaintenanceView.xml</li>
143         *          <li>CourseOfferingEditMaintenanceView.xml</li>
144         *      </ul>
145         *
146         * @param field grade roster level field
147         * @param form maintenace form
148         * @see #populateGradeRosterLevelTypes
149         */
150        @SuppressWarnings("unused")
151        public void populateFinalExamDriverTypes(InputField field, MaintenanceDocumentForm form){
152    
153            if (field.isReadOnly()){
154                return;
155            }
156    
157            FormatOfferingInfo formatOfferingInfo;
158            CourseOfferingWrapper wrapper = (CourseOfferingWrapper)form.getDocument().getNewMaintainableObject().getDataObject();
159            CourseInfo courseInfo = wrapper.getCourse();
160    
161            if (wrapper instanceof CourseOfferingCreateWrapper) {
162                /**
163                 * If the call is from create co, then there are two places from where this method is being called. From the 'Add format' section
164                 * and from the format offering collections. For the 'add format' section, we're checking the property name to get the FO Wrapper
165                 */
166                if (StringUtils.equals(field.getPropertyName(),"addLineFormatWrapper.finalExamLevelTypeKey")){
167                    formatOfferingInfo = ((CourseOfferingCreateWrapper)wrapper).getAddLineFormatWrapper().getFormatOfferingInfo();
168                } else {
169                    //This else is for the format offering collection.
170                    FormatOfferingWrapper foWrapper = (FormatOfferingWrapper)field.getContext().get(UifConstants.ContextVariableNames.LINE);
171                    formatOfferingInfo = foWrapper.getFormatOfferingInfo();
172                    if (foWrapper.isJointOffering()){
173                        courseInfo = foWrapper.getJointCreateWrapper().getCourseInfo();
174                    }
175                }
176            } else {
177                formatOfferingInfo = (FormatOfferingInfo)field.getContext().get(UifConstants.ContextVariableNames.LINE);
178            }
179    
180            SelectControl control = (SelectControl)field.getControl();
181    
182            List<KeyValue> keyValues = new ArrayList<KeyValue>();
183    
184            if (StringUtils.isNotBlank(formatOfferingInfo.getFormatId()) && courseInfo != null){
185                keyValues.addAll(collectActivityTypeKeyValues(courseInfo, formatOfferingInfo.getFormatId(), getTypeService(), ContextUtils.createDefaultContextInfo()));
186                control.setDisabled(false);
187            } else {
188                control.setDisabled(true);
189            }
190    
191            control.setOptions(keyValues);
192    
193        }
194    
195        protected List<KeyValue> collectActivityTypeKeyValues(CourseInfo course, String formatId, TypeService typeService, ContextInfo contextInfo) {
196    
197            List<KeyValue> results = new ArrayList<KeyValue>();
198    
199            Set<String> activityTypes = new HashSet<String>();
200            for(FormatInfo format : course.getFormats()) {
201                if (StringUtils.isBlank(formatId) || (StringUtils.isNotBlank(formatId) && StringUtils.equals(format.getId(),formatId))){
202                    for (ActivityInfo activity : format.getActivities()) {
203                        // if we haven't added a value for this activity type yet
204                        if(activityTypes.add(activity.getTypeKey())) {
205                            try {
206                                TypeInfo type = typeService.getType(activity.getTypeKey(), contextInfo);
207                                results.add(new ConcreteKeyValue(type.getKey(), type.getName()));
208                            } catch (Exception e) {
209                                throw new RuntimeException(e);
210                            }
211                        }
212                    }
213                }
214            }
215    
216            return results;
217        }
218    
219        public void populateCrossCourseList(InputField field, MaintenanceDocumentForm form){
220    
221            CourseOfferingCreateWrapper wrapper = (CourseOfferingCreateWrapper)form.getDocument().getNewMaintainableObject().getDataObject();
222    
223            CheckboxGroupControl control = (CheckboxGroupControl)field.getControl();
224    
225            List<KeyValue> crossListedCos = new ArrayList<KeyValue>();
226    
227            if (wrapper.getCourseOfferingInfo().getCrossListings() != null && wrapper.getCourseOfferingInfo().getCrossListings().size() > 0){
228                // Always include an option for Course
229                for(CourseOfferingCrossListingInfo courseInfo : wrapper.getCourseOfferingInfo().getCrossListings())  {
230                    crossListedCos.add(new ConcreteKeyValue(courseInfo.getId(), courseInfo.getCode()));
231                }
232             }
233    
234            crossListedCos.add(new ConcreteKeyValue("1", "A"));
235            control.setOptions(crossListedCos);
236    
237        }
238    
239        /**
240         * This method populates {@link CourseCrossListingInfo} in to the {@link CourseOfferingInfo}
241         * based on the user selection at create or edit CO. Note: If the <code>kuali.ks.enrollment.options.selective-crosslisting-allowed</code>
242         * property is enabled, this method creates cross listing dtos for all the alternate course codes.
243         *
244         * @param wrapper either {@link CourseOfferingCreateWrapper} or {@link org.kuali.student.enrollment.class2.courseoffering.dto.CourseOfferingEditWrapper}
245         * @param coInfo course offering dto
246         */
247        protected void loadCrossListedCOs(CourseOfferingWrapper wrapper, CourseOfferingInfo coInfo) {
248            coInfo.getCrossListings().clear();
249            if (wrapper.isSelectCrossListingAllowed()) {
250                List<String> alternateCodes = null;
251                if (wrapper instanceof CourseOfferingCreateWrapper){
252                    alternateCodes = wrapper.getAlternateCOCodes();
253                } else if (wrapper instanceof CourseOfferingEditWrapper){
254                    alternateCodes = ((CourseOfferingEditWrapper)wrapper).getAlternateCourseCodesSuffixStripped();
255                }
256                for (String alternateCode : alternateCodes) {
257                    for (CourseCrossListingInfo crossInfo : wrapper.getCourse().getCrossListings()) {
258                        if (StringUtils.equals(crossInfo.getCode(),alternateCode)) {
259                            CourseOfferingCrossListingInfo crossListingInfo = new CourseOfferingCrossListingInfo();
260                            crossListingInfo.setCode(crossInfo.getCode());
261                            crossListingInfo.setCourseNumberSuffix(crossInfo.getCourseNumberSuffix());
262                            crossListingInfo.setSubjectOrgId(crossInfo.getSubjectOrgId());
263                            crossListingInfo.setSubjectArea(crossInfo.getSubjectArea());
264                            crossListingInfo.setStateKey(LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY);
265                            crossListingInfo.setTypeKey(LuiServiceConstants.LUI_IDENTIFIER_CROSSLISTED_TYPE_KEY);
266                            coInfo.getCrossListings().add(crossListingInfo);
267                        }
268                    }
269                }
270            } else {
271                // get all the crosslisted COs
272                CourseInfo courseInfo = wrapper.getCourse();
273                for (CourseCrossListingInfo crossInfo : courseInfo.getCrossListings()) {
274                    CourseOfferingCrossListingInfo crossListingInfo = new CourseOfferingCrossListingInfo();
275                    crossListingInfo.setCode(crossInfo.getCode());
276                    crossListingInfo.setCourseNumberSuffix(crossInfo.getCourseNumberSuffix());
277                    crossListingInfo.setSubjectOrgId(crossInfo.getSubjectOrgId());
278                    crossListingInfo.setSubjectArea(crossInfo.getSubjectArea());
279                    crossListingInfo.setStateKey(LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY);
280                    crossListingInfo.setTypeKey(LuiServiceConstants.LUI_IDENTIFIER_CROSSLISTED_TYPE_KEY);
281                    coInfo.getCrossListings().add(crossListingInfo);
282                }
283            }
284        }
285    
286        protected TypeService getTypeService() {
287            if(typeService == null) {
288                typeService = CourseOfferingResourceLoader.loadTypeService();
289            }
290            return this.typeService;
291        }
292    
293        protected StateService getStateService() {
294            if(stateService == null) {
295                stateService = CourseOfferingResourceLoader.loadStateService();
296            }
297            return stateService;
298        }
299    
300        protected CourseOfferingService getCourseOfferingService() {
301            if (courseOfferingService == null) {
302                courseOfferingService = CourseOfferingResourceLoader.loadCourseOfferingService();
303            }
304            return courseOfferingService;
305        }
306    
307        protected CourseService getCourseService() {
308            if(courseService == null) {
309                courseService = CourseOfferingResourceLoader.loadCourseService();
310            }
311            return this.courseService;
312        }
313    
314        /**
315         * Returns the Name for a type key.
316         *
317         * @param typeKey
318         * @return
319         */
320        protected String getTypeName(String typeKey){
321            try{
322                TypeInfo typeInfo = getTypeService().getType(typeKey,ContextUtils.createDefaultContextInfo());
323                return typeInfo.getName();
324            } catch (Exception e){
325                //Throwing a runtime as we use this method to get the type name only for the ui purpose..
326                throw new RuntimeException(e);
327            }
328        }
329    
330    
331    }