001/*
002 * Copyright 2011 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may      obtain a copy of the License at
007 *
008 *      http://www.osedu.org/licenses/ECL-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.student.enrollment.class2.courseoffering.service.impl;
017
018import org.apache.commons.collections.CollectionUtils;
019import org.apache.log4j.Logger;
020import org.kuali.rice.core.api.criteria.QueryByCriteria;
021import org.kuali.student.common.mock.MockService;
022import org.kuali.student.common.util.UUIDHelper;
023import org.kuali.student.enrollment.class2.courseoffering.service.decorators.R1CourseServiceHelper;
024import org.kuali.student.enrollment.class2.courseoffering.service.transformer.CourseOfferingTransformer;
025import org.kuali.student.enrollment.courseoffering.dto.AOClusterVerifyResultsInfo;
026import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingClusterInfo;
027import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingDisplayInfo;
028import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingInfo;
029import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingSetInfo;
030import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingDisplayInfo;
031import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
032import org.kuali.student.enrollment.courseoffering.dto.FormatOfferingInfo;
033import org.kuali.student.enrollment.courseoffering.dto.OfferingInstructorInfo;
034import org.kuali.student.enrollment.courseoffering.dto.RegistrationGroupInfo;
035import org.kuali.student.enrollment.courseoffering.dto.SeatPoolDefinitionInfo;
036import org.kuali.student.enrollment.courseoffering.service.CourseOfferingService;
037import org.kuali.student.enrollment.courseoffering.service.CourseOfferingServiceBusinessLogic;
038import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultItemInfo;
039import org.kuali.student.r2.common.dto.BulkStatusInfo;
040import org.kuali.student.r2.common.dto.ContextInfo;
041import org.kuali.student.r2.common.dto.KeyNameInfo;
042import org.kuali.student.r2.common.dto.MetaInfo;
043import org.kuali.student.r2.common.dto.StatusInfo;
044import org.kuali.student.r2.common.dto.TimeOfDayInfo;
045import org.kuali.student.r2.common.dto.ValidationResultInfo;
046import org.kuali.student.r2.common.exceptions.AlreadyExistsException;
047import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
048import org.kuali.student.r2.common.exceptions.DependentObjectsExistException;
049import org.kuali.student.r2.common.exceptions.DoesNotExistException;
050import org.kuali.student.r2.common.exceptions.InvalidParameterException;
051import org.kuali.student.r2.common.exceptions.MissingParameterException;
052import org.kuali.student.r2.common.exceptions.OperationFailedException;
053import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
054import org.kuali.student.r2.common.exceptions.ReadOnlyException;
055import org.kuali.student.r2.common.exceptions.VersionMismatchException;
056import org.kuali.student.r2.common.infc.ValidationResult;
057import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants;
058import org.kuali.student.r2.common.util.constants.LuiServiceConstants;
059import org.kuali.student.r2.core.acal.dto.TermInfo;
060import org.kuali.student.r2.core.acal.service.AcademicCalendarService;
061import org.kuali.student.r2.core.class1.state.dto.StateInfo;
062import org.kuali.student.r2.core.class1.state.service.StateService;
063import org.kuali.student.r2.core.class1.type.dto.TypeInfo;
064import org.kuali.student.r2.core.class1.type.service.TypeService;
065import org.kuali.student.r2.core.scheduling.dto.ScheduleComponentDisplayInfo;
066import org.kuali.student.r2.core.scheduling.dto.ScheduleDisplayInfo;
067import org.kuali.student.r2.core.scheduling.dto.TimeSlotInfo;
068import org.kuali.student.r2.core.scheduling.service.SchedulingService;
069import org.kuali.student.r2.lum.course.dto.CourseInfo;
070import org.kuali.student.r2.lum.course.service.CourseService;
071import org.kuali.student.r2.lum.lrc.service.LRCService;
072
073import javax.annotation.Resource;
074import javax.jws.WebParam;
075import java.util.ArrayList;
076import java.util.Collection;
077import java.util.Collections;
078import java.util.Date;
079import java.util.HashMap;
080import java.util.HashSet;
081import java.util.LinkedHashMap;
082import java.util.List;
083import java.util.Map;
084import java.util.Set;
085
086public class CourseOfferingServiceMockImpl implements CourseOfferingService,
087        MockService {
088
089    private static Logger log = Logger
090            .getLogger(CourseOfferingServiceMockImpl.class);
091
092
093    @Resource
094    private CourseService courseService;
095
096    @Resource
097    private AcademicCalendarService acalService;
098
099    @Resource(name = "coBusinessLogic")
100    private CourseOfferingServiceBusinessLogic businessLogic;
101
102    @Resource
103    private TypeService typeService;
104
105    @Resource
106    private StateService stateService;
107
108    @Resource
109    private LRCService lrcService;
110    
111    @Resource
112    private SchedulingService schedulingService;
113
114    @Resource
115    private CourseOfferingTransformer courseOfferingTransformer;
116    
117    public SchedulingService getSchedulingService() {
118        return schedulingService;
119    }
120
121    public void setSchedulingService(SchedulingService schedulingService) {
122        this.schedulingService = schedulingService;
123    }
124
125    public StateService getStateService() {
126        return stateService;
127    }
128
129    public void setStateService(StateService stateService) {
130        this.stateService = stateService;
131    }
132
133    public LRCService getLrcService() {
134        return lrcService;
135    }
136
137    public void setLrcService(LRCService lrcService) {
138        this.lrcService = lrcService;
139    }
140
141    public CourseOfferingTransformer getCourseOfferingTransformer() {
142        return courseOfferingTransformer;
143    }
144
145    public void setCourseOfferingTransformer(CourseOfferingTransformer courseOfferingTransformer) {
146        this.courseOfferingTransformer = courseOfferingTransformer;
147    }
148    
149    @Override
150    public void clear() {
151
152        this.activityOfferingMap.clear();
153        this.courseOfferingMap.clear();
154        this.formatOfferingMap.clear();
155        this.registrationGroupMap.clear();
156        this.seatPoolDefinitionMap.clear();
157
158        activityOfferingToSeatPoolMap.clear();
159
160        this.activityOfferingClusterMap.clear();
161
162    }
163
164    public void setTypeService(TypeService typeService) {
165        this.typeService = typeService;
166    }
167
168    public CourseOfferingServiceBusinessLogic getBusinessLogic() {
169        return businessLogic;
170    }
171
172    public void setBusinessLogic(
173            CourseOfferingServiceBusinessLogic businessLogic) {
174        this.businessLogic = businessLogic;
175    }
176
177    public CourseService getCourseService() {
178        return courseService;
179    }
180
181    public void setCourseService(CourseService courseService) {
182        this.courseService = courseService;
183    }
184
185    public AcademicCalendarService getAcalService() {
186        return acalService;
187    }
188
189    public void setAcalService(AcademicCalendarService acalService) {
190        this.acalService = acalService;
191    }
192
193    @Override
194    public TypeInfo getCourseOfferingType(String courseOfferingTypeKey,
195                                          ContextInfo context) throws DoesNotExistException,
196            InvalidParameterException, MissingParameterException,
197            OperationFailedException, PermissionDeniedException {
198        return typeService.getType(courseOfferingTypeKey, context);
199    }
200
201    @Override
202    public List<TypeInfo> getCourseOfferingTypes(ContextInfo context)
203            throws InvalidParameterException, MissingParameterException,
204            OperationFailedException, PermissionDeniedException {
205        throw new UnsupportedOperationException("Not supported yet");
206    }
207
208    @Override
209    public List<TypeInfo> getInstructorTypesForCourseOfferingType(
210            String courseOfferingTypeKey, ContextInfo context)
211            throws DoesNotExistException, InvalidParameterException,
212            MissingParameterException, OperationFailedException,
213            PermissionDeniedException {
214        throw new UnsupportedOperationException("Not supported yet");
215    }
216
217    @Override
218    public StatusInfo deleteCourseOfferingCascaded(String courseOfferingId,
219                                                   ContextInfo context) throws DoesNotExistException,
220            InvalidParameterException, MissingParameterException,
221            OperationFailedException, PermissionDeniedException {
222
223
224        List<FormatOfferingInfo> fos = getFormatOfferingsByCourseOffering(courseOfferingId, context);
225
226        for (FormatOfferingInfo formatOfferingInfo : fos) {
227
228            StatusInfo status = deleteFormatOfferingCascaded(formatOfferingInfo.getId(), context);
229
230            if (!status.getIsSuccess())
231                throw new OperationFailedException("deleteFormatOfferingCascaded(): failed for id = " + formatOfferingInfo.getId());
232        }
233
234        StatusInfo status;
235        try {
236            status = deleteCourseOffering(courseOfferingId, context);
237        } catch (DependentObjectsExistException e) {
238            throw new OperationFailedException("deleteFormatOfferingCascaded(): failed because dependant objects still exist for courseOfferingId = " + courseOfferingId, e);
239        }
240
241        return status;
242    }
243
244    @Override
245    public StatusInfo deleteFormatOfferingCascaded(String formatOfferingId,
246                                                   ContextInfo context) throws DoesNotExistException,
247            InvalidParameterException, MissingParameterException,
248            OperationFailedException, PermissionDeniedException {
249
250        List<ActivityOfferingInfo> aos = getActivityOfferingsByFormatOffering(formatOfferingId, context);
251
252        for (ActivityOfferingInfo activityOfferingInfo : aos) {
253
254            deleteActivityOfferingCascaded(activityOfferingInfo.getId(), context);
255        }
256
257
258        try {
259            deleteFormatOffering(formatOfferingId, context);
260        } catch (DependentObjectsExistException e) {
261            // should never fire since we deleted the dependencies
262            throw new OperationFailedException("failed to delete format offering for id = " + formatOfferingId, e);
263        }
264
265        return successStatus();
266    }
267
268    @Override
269    public RegistrationGroupInfo createRegistrationGroup(
270            String formatOfferingId, String activityOfferingClusterId, String registrationGroupType,
271            RegistrationGroupInfo registrationGroupInfo,
272            ContextInfo context)
273            throws DoesNotExistException, DataValidationErrorException,
274            InvalidParameterException, MissingParameterException,
275            OperationFailedException, PermissionDeniedException,
276            ReadOnlyException {
277        // create
278        if (!registrationGroupType.equals(registrationGroupInfo.getTypeKey())) {
279            throw new InvalidParameterException(
280                    "The type parameter does not match the type on the info object");
281        }
282        RegistrationGroupInfo copy = new RegistrationGroupInfo(
283                registrationGroupInfo);
284        if (copy.getId() == null) {
285            copy.setId(UUIDHelper.genStringUUID());
286        }
287        copy.setMeta(newMeta(context));
288        registrationGroupMap.put(copy.getId(), copy);
289        return new RegistrationGroupInfo(copy);
290    }
291
292    @Override
293    public CourseOfferingInfo getCourseOffering(String courseOfferingId,
294                                                ContextInfo context) throws DoesNotExistException,
295            InvalidParameterException, MissingParameterException,
296            OperationFailedException, PermissionDeniedException {
297        if (!this.courseOfferingMap.containsKey(courseOfferingId)) {
298            throw new DoesNotExistException(courseOfferingId);
299        }
300        return this.courseOfferingMap.get(courseOfferingId);
301    }
302
303    @Override
304    public List<CourseOfferingInfo> getCourseOfferingsByIds(
305            List<String> courseOfferingIds, ContextInfo context)
306            throws DoesNotExistException, InvalidParameterException,
307            MissingParameterException, OperationFailedException,
308            PermissionDeniedException {
309        List<CourseOfferingInfo> list = new ArrayList<CourseOfferingInfo>();
310        for (String id : courseOfferingIds) {
311            list.add(this.getCourseOffering(id, context));
312        }
313        return list;
314    }
315
316    @Override
317    public List<CourseOfferingInfo> getCourseOfferingsByCourse(String courseId,
318                                                               ContextInfo context) throws DoesNotExistException,
319            InvalidParameterException, MissingParameterException,
320            OperationFailedException, PermissionDeniedException {
321        List<CourseOfferingInfo> list = new ArrayList<CourseOfferingInfo>();
322        for (CourseOfferingInfo info : courseOfferingMap.values()) {
323            if (courseId.equals(info.getCourseId())) {
324                list.add(info);
325            }
326        }
327        return list;
328    }
329
330    @Override
331    public List<CourseOfferingInfo> getCourseOfferingsByCourseAndTerm(
332            String courseId, String termId, ContextInfo context)
333            throws DoesNotExistException, InvalidParameterException,
334            MissingParameterException, OperationFailedException,
335            PermissionDeniedException {
336        List<CourseOfferingInfo> list = new ArrayList<CourseOfferingInfo>();
337        for (CourseOfferingInfo info : courseOfferingMap.values()) {
338            if (courseId.equals(info.getCourseId())) {
339                if (termId.equals(info.getTermId())) {
340                    list.add(info);
341                }
342            }
343        }
344        return list;
345    }
346
347    @Override
348    public List<String> getCourseOfferingIdsByTerm(String termId,
349                                                   Boolean useIncludedTerm, ContextInfo context)
350            throws DoesNotExistException, InvalidParameterException,
351            MissingParameterException, OperationFailedException,
352            PermissionDeniedException {
353        List<String> list = new ArrayList<String>();
354        for (CourseOfferingInfo info : courseOfferingMap.values()) {
355            if (termId.equals(info.getTermId())) {
356                list.add(info.getId());
357            }
358            // TODO: check included terms
359        }
360        return list;
361    }
362
363    @Override
364    public CourseOfferingInfo createCourseOffering(String courseId, String termId, String courseOfferingTypeKey, CourseOfferingInfo courseOfferingInfo,
365                                                   List<String> optionKeys, ContextInfo context)
366            throws DoesNotExistException, DataValidationErrorException, InvalidParameterException, MissingParameterException,
367            OperationFailedException, PermissionDeniedException, ReadOnlyException {
368        // create
369        if (!courseOfferingTypeKey.equals(courseOfferingInfo.getTypeKey())) {
370            throw new InvalidParameterException("The type parameter does not match the type on the info object");
371        }
372        // TODO: check the rest of the readonly fields that are specified on the create to make sure they match the info object
373        CourseOfferingInfo copy = new CourseOfferingInfo(courseOfferingInfo);
374        if (copy.getId() == null) {
375            copy.setId(UUIDHelper.genStringUUID());
376        }
377        // TODO: move this logic to the calculation decorator do the persistence layer doesn't have this logic mixed in with it
378        // copy from cannonical
379        CourseInfo courseInfo = new R1CourseServiceHelper(courseService, acalService).getCourse(courseId);
380        courseOfferingTransformer.copyFromCanonical(courseInfo, copy, optionKeys, context);
381        copy.setMeta(newMeta(context));
382        copy.setHasWaitlist(true);
383        courseOfferingMap.put(copy.getId(), copy);
384        log.info("CourseOfferingMockImpl: created course offering: " + copy.getId() + "term=" + copy.getTermId() + " for course =" + copy.getCourseId());
385        
386        // copy rules from canonical
387        courseOfferingTransformer.copyRulesFromCanonical(courseInfo, copy, optionKeys, context);
388        return new CourseOfferingInfo(copy);
389    }
390
391    @Override
392    public List<CourseOfferingInfo> getCourseOfferingsByTermAndInstructor(
393            String termId, String instructorId, ContextInfo context)
394            throws DoesNotExistException, InvalidParameterException,
395            MissingParameterException, OperationFailedException,
396            PermissionDeniedException {
397        List<CourseOfferingInfo> list = new ArrayList<CourseOfferingInfo>();
398        for (CourseOfferingInfo info : courseOfferingMap.values()) {
399            if (termId.equals(info.getTermId())) {
400                if (matches(instructorId, info.getInstructors())) {
401                    list.add(info);
402                }
403            }
404        }
405        return list;
406    }
407
408    private boolean matches(String personId,
409                            List<OfferingInstructorInfo> instructors) {
410        for (OfferingInstructorInfo instructor : instructors) {
411            if (personId.equals(instructor.getPersonId())) {
412                return true;
413            }
414        }
415        return false;
416    }
417
418    @Override
419    public List<String> getCourseOfferingIdsByTermAndUnitsContentOwner(
420            String termId, String unitsContentOwnerId, ContextInfo context)
421            throws DoesNotExistException, InvalidParameterException,
422            MissingParameterException, OperationFailedException,
423            PermissionDeniedException {
424        List<String> list = new ArrayList<String>();
425        for (CourseOfferingInfo info : courseOfferingMap.values()) {
426            if (termId.equals(info.getTermId())) {
427                if (info.getUnitsContentOwnerOrgIds().contains(
428                        unitsContentOwnerId)) {
429                    list.add(info.getId());
430                }
431            }
432        }
433        return list;
434    }
435
436    @Override
437    public List<String> getCourseOfferingIdsByType(String typeKey,
438                                                   ContextInfo context) throws DoesNotExistException,
439            InvalidParameterException, MissingParameterException,
440            OperationFailedException, PermissionDeniedException {
441        List<String> list = new ArrayList<String>();
442        for (CourseOfferingInfo info : courseOfferingMap.values()) {
443            if (typeKey.equals(info.getTypeKey())) {
444                list.add(info.getId());
445            }
446        }
447        return list;
448    }
449
450    // cache variable
451    // The LinkedHashMap is just so the values come back in a predictable order
452    protected Map<String, CourseOfferingInfo> courseOfferingMap = new LinkedHashMap<String, CourseOfferingInfo>();
453
454    @Override
455    public CourseOfferingInfo updateCourseOffering(String courseOfferingId,
456                                                   CourseOfferingInfo courseOfferingInfo, ContextInfo context)
457            throws DataValidationErrorException, DoesNotExistException,
458            InvalidParameterException, MissingParameterException,
459            OperationFailedException, PermissionDeniedException,
460            ReadOnlyException, VersionMismatchException {
461        // update
462        if (!courseOfferingId.equals(courseOfferingInfo.getId())) {
463            throw new InvalidParameterException(
464                    "The id parameter does not match the id on the info object");
465        }
466        CourseOfferingInfo copy = new CourseOfferingInfo(courseOfferingInfo);
467        CourseOfferingInfo old = this.getCourseOffering(
468                courseOfferingInfo.getId(), context);
469        if (!old.getMeta().getVersionInd()
470                .equals(copy.getMeta().getVersionInd())) {
471            throw new VersionMismatchException(old.getMeta().getVersionInd());
472        }
473        copy.setMeta(updateMeta(copy.getMeta(), context));
474        this.courseOfferingMap.put(courseOfferingInfo.getId(), copy);
475        return new CourseOfferingInfo(copy);
476    }
477
478    @Override
479    public CourseOfferingInfo updateCourseOfferingFromCanonical(
480            String courseOfferingId, List<String> optionKeys,
481            ContextInfo context) throws DataValidationErrorException,
482            DoesNotExistException, InvalidParameterException,
483            MissingParameterException, OperationFailedException,
484            PermissionDeniedException, VersionMismatchException {
485        return this.businessLogic.updateCourseOfferingFromCanonical(
486                courseOfferingId, optionKeys, context);
487    }
488
489    @Override
490    public StatusInfo deleteCourseOffering(String courseOfferingId,
491                                           ContextInfo context) throws DoesNotExistException,
492            InvalidParameterException, MissingParameterException,
493            OperationFailedException, PermissionDeniedException, DependentObjectsExistException {
494
495        for (FormatOfferingInfo fo: formatOfferingMap.values()) {
496            // See if any format offerings are still connected to COs
497            if (fo.getCourseOfferingId().equals(courseOfferingId)) {
498                throw new DependentObjectsExistException("Format offering still attached to CO (" + courseOfferingId + ")");
499            }
500        }
501        if (this.courseOfferingMap.remove(courseOfferingId) == null) {
502            throw new DoesNotExistException(courseOfferingId);
503        }
504        return successStatus();
505    }
506
507    @Override
508    public List<ValidationResultInfo> validateCourseOffering(
509            String validationType, CourseOfferingInfo courseOfferingInfo,
510            ContextInfo context) throws DoesNotExistException,
511            InvalidParameterException, MissingParameterException,
512            OperationFailedException {
513        // validate
514        return new ArrayList<ValidationResultInfo>();
515    }
516
517    @Override
518    public List<ValidationResultInfo> validateCourseOfferingFromCanonical(
519            CourseOfferingInfo courseOfferingInfo, List<String> optionKeys,
520            ContextInfo context) throws DoesNotExistException,
521            InvalidParameterException, MissingParameterException,
522            OperationFailedException, PermissionDeniedException {
523        return this.businessLogic.validateCourseOfferingFromCanonical(
524                courseOfferingInfo, optionKeys, context);
525    }
526
527    @Override
528    public FormatOfferingInfo getFormatOffering(String formatOfferingId,
529                                                ContextInfo context) throws DoesNotExistException,
530            InvalidParameterException, MissingParameterException,
531            OperationFailedException, PermissionDeniedException {
532        if (!this.formatOfferingMap.containsKey(formatOfferingId)) {
533            throw new DoesNotExistException(formatOfferingId);
534        }
535        return this.formatOfferingMap.get(formatOfferingId);
536    }
537
538    @Override
539    public List<FormatOfferingInfo> getFormatOfferingsByCourseOffering(
540            String courseOfferingId, ContextInfo context)
541            throws DoesNotExistException, InvalidParameterException,
542            MissingParameterException, OperationFailedException,
543            PermissionDeniedException {
544        List<FormatOfferingInfo> list = new ArrayList<FormatOfferingInfo>();
545        for (FormatOfferingInfo info : formatOfferingMap.values()) {
546            if (courseOfferingId.equals(info.getCourseOfferingId())) {
547                list.add(info);
548            }
549        }
550        return list;
551    }
552
553    // cache variable
554    // The LinkedHashMap is just so the values come back in a predictable order
555    private Map<String, FormatOfferingInfo> formatOfferingMap = new LinkedHashMap<String, FormatOfferingInfo>();
556
557    @Override
558    public FormatOfferingInfo createFormatOffering(String courseOfferingId,
559                                                   String formatId, String formatOfferingType,
560                                                   FormatOfferingInfo formatOfferingInfo, ContextInfo context)
561            throws DoesNotExistException, DataValidationErrorException,
562            InvalidParameterException, MissingParameterException,
563            OperationFailedException, PermissionDeniedException,
564            ReadOnlyException {
565        CourseOfferingInfo co = this.getCourseOffering(courseOfferingId,
566                context);
567        // create
568        if (!courseOfferingId.equals(formatOfferingInfo.getCourseOfferingId())) {
569            throw new InvalidParameterException(
570                    "The course offering id parameter does not match the course offering id on the info object");
571        }
572        if (!formatId.equals(formatOfferingInfo.getFormatId())) {
573            throw new InvalidParameterException(
574                    "The format id parameter does not match the format id on the info object");
575        }
576        if (!formatOfferingType.equals(formatOfferingInfo.getTypeKey())) {
577            throw new InvalidParameterException(
578                    "The type parameter does not match the type on the info object");
579        }
580        // TODO: check the rest of the readonly fields that are specified on the
581        // create to make sure they match the info object
582        FormatOfferingInfo copy = new FormatOfferingInfo(formatOfferingInfo);
583        if (copy.getId() == null) {
584            copy.setId(UUIDHelper.genStringUUID());
585        }
586        copy.setTermId(co.getTermId());
587        copy.setMeta(newMeta(context));
588        formatOfferingMap.put(copy.getId(), copy);
589        log.debug("CourseOfferingMockImpl: created format offering: "
590                + copy.getId() + "term=" + copy.getTermId() + " for format ="
591                + copy.getFormatId() + " and course offering="
592                + copy.getCourseOfferingId());
593        return new FormatOfferingInfo(copy);
594    }
595
596    @Override
597    public FormatOfferingInfo updateFormatOffering(String formatOfferingId,
598                                                   FormatOfferingInfo formatOfferingInfo, ContextInfo context)
599            throws DataValidationErrorException, DoesNotExistException,
600            InvalidParameterException, MissingParameterException,
601            OperationFailedException, PermissionDeniedException,
602            ReadOnlyException, VersionMismatchException {
603        // update
604        if (!formatOfferingId.equals(formatOfferingInfo.getId())) {
605            throw new InvalidParameterException(
606                    "The id parameter does not match the id on the info object");
607        }
608        FormatOfferingInfo copy = new FormatOfferingInfo(formatOfferingInfo);
609        FormatOfferingInfo old = this.getFormatOffering(
610                formatOfferingInfo.getId(), context);
611        if (!old.getMeta().getVersionInd()
612                .equals(copy.getMeta().getVersionInd())) {
613            throw new VersionMismatchException(old.getMeta().getVersionInd());
614        }
615        copy.setMeta(updateMeta(copy.getMeta(), context));
616        this.formatOfferingMap.put(formatOfferingInfo.getId(), copy);
617        return new FormatOfferingInfo(copy);
618    }
619
620    @Override
621    public List<ValidationResultInfo> validateFormatOffering(
622            String validationType, FormatOfferingInfo formatOfferingInfo,
623            ContextInfo context) throws DoesNotExistException,
624            InvalidParameterException, MissingParameterException,
625            OperationFailedException {
626        // validate
627        return new ArrayList<ValidationResultInfo>();
628    }
629
630    @Override
631    public StatusInfo deleteFormatOffering(String formatOfferingId,
632                                           ContextInfo context) throws DoesNotExistException,
633            InvalidParameterException, MissingParameterException,
634            OperationFailedException, PermissionDeniedException,
635            DependentObjectsExistException {
636        for (ActivityOfferingInfo aoInfo: activityOfferingMap.values()) {
637            // test if AOs still attached to FO, if so, throw dependent object exists exception
638            if (aoInfo.getFormatOfferingId().equals(formatOfferingId)) {
639                throw new DependentObjectsExistException("Activity offerings still attached to FO (" + formatOfferingId + ")");
640            }
641        }
642        if (this.formatOfferingMap.remove(formatOfferingId) == null) {
643            throw new DoesNotExistException(formatOfferingId);
644        }
645        return successStatus();
646    }
647
648    @Override
649    public TypeInfo getActivityOfferingType(String activityOfferingTypeKey,
650                                            ContextInfo context) throws DoesNotExistException,
651            InvalidParameterException, MissingParameterException,
652            OperationFailedException, PermissionDeniedException {
653        return typeService.getType(activityOfferingTypeKey, context);
654    }
655
656    @Override
657    public List<TypeInfo> getActivityOfferingTypes(ContextInfo context)
658            throws InvalidParameterException, MissingParameterException,
659            OperationFailedException, PermissionDeniedException {
660        try {
661            return typeService.getTypesForGroupType(
662                    LuiServiceConstants.ACTIVITY_OFFERING_GROUP_TYPE_KEY,
663                    context);
664        } catch (DoesNotExistException e) {
665            throw new OperationFailedException(
666                    "Invalid group type used to retrieve Activity Offering Types: "
667                            + LuiServiceConstants.ACTIVITY_OFFERING_GROUP_TYPE_KEY);
668        }
669    }
670
671    @Override
672    public List<TypeInfo> getActivityOfferingTypesForActivityType(
673            String activityTypeKey, ContextInfo context)
674            throws DoesNotExistException, InvalidParameterException,
675            MissingParameterException, OperationFailedException,
676            PermissionDeniedException {
677        return typeService.getAllowedTypesForType(activityTypeKey, context);
678    }
679
680    @Override
681    public List<TypeInfo> getInstructorTypesForActivityOfferingType(
682            String activityOfferingTypeKey, ContextInfo context)
683            throws DoesNotExistException, InvalidParameterException,
684            MissingParameterException, OperationFailedException,
685            PermissionDeniedException {
686        throw new OperationFailedException("not implemented");
687    }
688
689    @Override
690    public ActivityOfferingInfo getActivityOffering(String activityOfferingId,
691                                                    ContextInfo context) throws DoesNotExistException,
692            InvalidParameterException, MissingParameterException,
693            OperationFailedException, PermissionDeniedException {
694        if (!this.activityOfferingMap.containsKey(activityOfferingId)) {
695            throw new DoesNotExistException(activityOfferingId);
696        }
697        return this.activityOfferingMap.get(activityOfferingId);
698    }
699
700    @Override
701    public List<ActivityOfferingInfo> getActivityOfferingsByIds(
702            List<String> activityOfferingIds, ContextInfo context)
703            throws DoesNotExistException, InvalidParameterException,
704            MissingParameterException, OperationFailedException,
705            PermissionDeniedException {
706        List<ActivityOfferingInfo> list = new ArrayList<ActivityOfferingInfo>();
707        for (String id : activityOfferingIds) {
708            list.add(this.getActivityOffering(id, context));
709        }
710        return list;
711    }
712
713    @Override
714    public List<ActivityOfferingInfo> getActivityOfferingsByCourseOffering(
715            String courseOfferingId, ContextInfo context)
716            throws DoesNotExistException, InvalidParameterException,
717            MissingParameterException, OperationFailedException,
718            PermissionDeniedException {
719        List<ActivityOfferingInfo> list = new ArrayList<ActivityOfferingInfo>();
720        for (ActivityOfferingInfo info : activityOfferingMap.values()) {
721
722            if (courseOfferingId.equals(info.getCourseOfferingId())) {
723                list.add(info);
724            }
725        }
726
727        return list;
728    }
729
730    @Override
731    public List<ActivityOfferingInfo> getActivityOfferingsByFormatOffering(
732            String formatOfferingId, ContextInfo contextInfo)
733            throws DoesNotExistException, InvalidParameterException,
734            MissingParameterException, OperationFailedException,
735            PermissionDeniedException {
736        List<ActivityOfferingInfo> list = new ArrayList<ActivityOfferingInfo>();
737        for (ActivityOfferingInfo info : activityOfferingMap.values()) {
738            if (formatOfferingId.equals(info.getFormatOfferingId())) {
739                list.add(info);
740            }
741        }
742        return list;
743    }
744
745    @Override
746    public List<ActivityOfferingInfo> getActivityOfferingsWithoutClusterByFormatOffering(String formatOfferingId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
747    
748        List<ActivityOfferingInfo> aos = getActivityOfferingsByFormatOffering(formatOfferingId, contextInfo);
749        
750        Map<String, ActivityOfferingInfo> aoMap = new HashMap<String, ActivityOfferingInfo>();
751        
752        for (ActivityOfferingInfo activityOfferingInfo : aos) {
753            
754            aoMap.put(activityOfferingInfo.getId(), activityOfferingInfo);
755        
756        }
757        
758        List<ActivityOfferingClusterInfo> aocs = getActivityOfferingClustersByFormatOffering(formatOfferingId, contextInfo);
759    
760        for (ActivityOfferingClusterInfo activityOfferingClusterInfo : aocs) {
761            
762            for (ActivityOfferingSetInfo aoSet : activityOfferingClusterInfo.getActivityOfferingSets()) {
763                
764                for (String aoId : aoSet.getActivityOfferingIds()) {
765                    
766                    aoMap.remove(aoId);
767                }
768            }
769        }
770        
771        return new ArrayList<ActivityOfferingInfo>(aoMap.values());
772    }
773
774    @Override
775    public List<ActivityOfferingInfo> getActivityOfferingsByFormatOfferingWithoutRegGroup(String formatOfferingId, ContextInfo context) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
776        throw new OperationFailedException("unsupported");
777    }
778
779    @Override
780    public List<String> getAllowedTimeSlotIdsForActivityOffering(@WebParam(name = "activityOfferingId") String activityOfferingId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
781        throw new OperationFailedException("unsupported");
782    }
783
784    @Override
785    public List<TimeSlotInfo> getAllowedTimeSlotsForActivityOffering(@WebParam(name = "activityOfferingId") String activityOfferingId, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
786        throw new OperationFailedException("unsupported");
787    }
788
789    @Override
790    public List<TimeSlotInfo> getAllowedTimeSlotsByDaysAndStartTimeForActivityOffering(@WebParam(name = "activityOfferingId") String activityOfferingId, @WebParam(name = "daysOfWeek") List<Integer> daysOfWeek, @WebParam(name = "startTime") TimeOfDayInfo startTime, @WebParam(name = "contextInfo") ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
791        throw new OperationFailedException("unsupported");
792    }
793
794    // cache variable
795    // The LinkedHashMap is just so the values come back in a predictable order
796    private Map<String, ActivityOfferingInfo> activityOfferingMap = new LinkedHashMap<String, ActivityOfferingInfo>();
797
798    @Override
799    public ActivityOfferingInfo createActivityOffering(String formatOfferingId,
800                                                       String activityId, String activityOfferingTypeKey,
801                                                       ActivityOfferingInfo activityOfferingInfo, ContextInfo context)
802            throws DoesNotExistException, DataValidationErrorException,
803            InvalidParameterException, MissingParameterException,
804            OperationFailedException, PermissionDeniedException,
805            ReadOnlyException {
806        FormatOfferingInfo fo = this.getFormatOffering(formatOfferingId,
807                context);
808        // create
809        if (!formatOfferingId
810                .equals(activityOfferingInfo.getFormatOfferingId())) {
811            throw new InvalidParameterException(
812                    "The format offering id parameter does not match the format offering id on the info object");
813        }
814        if (!activityId.equals(activityOfferingInfo.getActivityId())) {
815            throw new InvalidParameterException(
816                    "The activity id parameter does not match the activity id on the info object");
817        }
818        if (!activityOfferingTypeKey.equals(activityOfferingInfo.getTypeKey())) {
819            throw new InvalidParameterException(
820                    "The type parameter does not match the type on the info object");
821        }
822        // TODO: check the rest of the readonly fields that are specified on the
823        // create to make sure they match the info object
824        ActivityOfferingInfo copy = new ActivityOfferingInfo(
825                activityOfferingInfo);
826        if (copy.getId() == null) {
827            copy.setId(UUIDHelper.genStringUUID());
828        }
829        copy.setTermId(fo.getTermId());
830        copy.setMeta(newMeta(context));
831        activityOfferingMap.put(copy.getId(), copy);
832        log.debug("CourseOfferingMockImpl: created activity offering: "
833                + copy.getId() + "term=" + copy.getTermId()
834                + " for activity " + copy.getActivityId()
835                + " and format offering=" + copy.getFormatOfferingId());
836        return new ActivityOfferingInfo(copy);
837    }
838
839    @Override
840    public ActivityOfferingInfo copyActivityOffering(String activityOfferingId,
841                                                     ContextInfo context) throws DoesNotExistException,
842            DataValidationErrorException, InvalidParameterException,
843            MissingParameterException, OperationFailedException,
844            PermissionDeniedException, ReadOnlyException {
845        throw new OperationFailedException(
846                "copyActivityOffering has not been implemented");
847    }
848
849    @Override
850    public List<ActivityOfferingInfo> generateActivityOfferings(
851            String formatOfferingId, String activityOfferingType,
852            Integer quantity, ContextInfo context)
853            throws InvalidParameterException, MissingParameterException,
854            OperationFailedException, PermissionDeniedException {
855        throw new OperationFailedException(
856                "generateActivityOfferings has not been implemented");
857    }
858
859    @Override
860    public ActivityOfferingInfo updateActivityOffering(
861            String activityOfferingId,
862            ActivityOfferingInfo activityOfferingInfo, ContextInfo context)
863            throws DataValidationErrorException, DoesNotExistException,
864            InvalidParameterException, MissingParameterException,
865            OperationFailedException, PermissionDeniedException,
866            VersionMismatchException, ReadOnlyException {
867        // update
868        if (!activityOfferingId.equals(activityOfferingInfo.getId())) {
869            throw new InvalidParameterException(
870                    "The id parameter does not match the id on the info object");
871        }
872        ActivityOfferingInfo copy = new ActivityOfferingInfo(
873                activityOfferingInfo);
874        ActivityOfferingInfo old = this.getActivityOffering(
875                activityOfferingInfo.getId(), context);
876        if (!old.getMeta().getVersionInd()
877                .equals(copy.getMeta().getVersionInd())) {
878            throw new VersionMismatchException(old.getMeta().getVersionInd());
879        }
880        copy.setMeta(updateMeta(copy.getMeta(), context));
881        this.activityOfferingMap.put(activityOfferingInfo.getId(), copy);
882        return new ActivityOfferingInfo(copy);
883    }
884
885    @Override
886    public StatusInfo deleteActivityOffering(String activityOfferingId,
887                                             ContextInfo context) throws DoesNotExistException,
888            InvalidParameterException, MissingParameterException,
889            OperationFailedException, PermissionDeniedException, DependentObjectsExistException {
890
891        for (RegistrationGroupInfo rg : this.registrationGroupMap.values()) {
892
893            if (rg.getActivityOfferingIds().contains(activityOfferingId))
894                throw new DependentObjectsExistException("Registration Groups Exist for Activity id = " + activityOfferingId);
895        }
896
897        List<String> seatpoolIds =  activityOfferingToSeatPoolMap.get(activityOfferingId);
898        if (seatpoolIds != null && !seatpoolIds.isEmpty()) {
899            throw new DependentObjectsExistException("Seatpools exists for Activity id = " + activityOfferingId);
900        }
901
902        if (this.activityOfferingMap.remove(activityOfferingId) == null) {
903            throw new DoesNotExistException(activityOfferingId);
904        }
905        return successStatus();
906    }
907
908
909    @Override
910    public StatusInfo deleteActivityOfferingCascaded(String activityOfferingId, 
911                                                     ContextInfo context) throws DoesNotExistException,
912            InvalidParameterException, MissingParameterException,
913            OperationFailedException, PermissionDeniedException {
914
915        // delete seat pool registrations
916
917        List<SeatPoolDefinitionInfo> spls = getSeatPoolDefinitionsForActivityOffering(activityOfferingId, context);
918        List<String> seatpoolIds = new ArrayList<String>();
919        for (SeatPoolDefinitionInfo spInfo: spls) {
920            seatpoolIds.add(spInfo.getId());
921        }
922        // Delete the attachments from AOs to seatpools
923        List<String> fetchedIds = activityOfferingToSeatPoolMap.get(activityOfferingId);
924        if (fetchedIds != null) {
925            fetchedIds.removeAll(seatpoolIds); // Get rid of seatpool IDs in this association
926        }
927
928        for (SeatPoolDefinitionInfo spl : spls) {
929
930            StatusInfo status = deleteSeatPoolDefinition(spl.getId(), context);
931
932            if (!status.getIsSuccess())
933                throw new OperationFailedException(status.getMessage());
934
935        }
936
937
938        // delete registration groups
939
940        // intentionally separated to avoid a concurrent modification exception on delete.
941        ArrayList<RegistrationGroupInfo> rgs = new ArrayList<RegistrationGroupInfo>(this.registrationGroupMap.values());
942
943        for (RegistrationGroupInfo rg : rgs) {
944
945            if (rg.getActivityOfferingIds().contains(activityOfferingId)) {
946                StatusInfo status = deleteRegistrationGroup(rg.getId(), context);
947
948                if (!status.getIsSuccess()) {
949                    throw new OperationFailedException(status.getMessage());
950                }
951            }
952        }
953
954        // Remove the AO from the AOC
955        for (ActivityOfferingClusterInfo cluster: this.activityOfferingClusterMap.values()) {
956            for (ActivityOfferingSetInfo set: cluster.getActivityOfferingSets()) {
957                if (set.getActivityOfferingIds().contains(activityOfferingId)) {
958                    set.getActivityOfferingIds().remove(activityOfferingId);
959                }
960            }
961        }
962
963        // delete activity offering
964        try {
965            return deleteActivityOffering(activityOfferingId, context);
966        } catch (DependentObjectsExistException e) {
967            throw new OperationFailedException("Dependent object still exists for Activity Offering with id = " + activityOfferingId, e);
968        }
969    }
970
971
972    @Override
973    public StatusInfo scheduleActivityOffering(String activityOfferingId,
974                                               ContextInfo contextInfo) throws DoesNotExistException,
975            InvalidParameterException, MissingParameterException,
976            OperationFailedException, PermissionDeniedException {
977        throw new OperationFailedException("implement for M5");
978    }
979
980    @Override
981    public List<ValidationResultInfo> validateActivityOffering(
982            String validationType, ActivityOfferingInfo activityOfferingInfo,
983            ContextInfo context) throws DoesNotExistException,
984            InvalidParameterException, MissingParameterException,
985            OperationFailedException {
986        // validate
987        return new ArrayList<ValidationResultInfo>();
988    }
989
990    @Override
991    public Float calculateInClassContactHoursForTerm(String activityOfferingId,
992                                                     ContextInfo context) throws DoesNotExistException,
993            InvalidParameterException, MissingParameterException,
994            OperationFailedException, PermissionDeniedException {
995        throw new OperationFailedException(
996                "calculateInClassContactHoursForTerm has not been implemented");
997    }
998
999    @Override
1000    public Float calculateOutofClassContactHoursForTerm(
1001            String activityOfferingId, ContextInfo context)
1002            throws DoesNotExistException, InvalidParameterException,
1003            MissingParameterException, OperationFailedException,
1004            PermissionDeniedException {
1005        throw new OperationFailedException(
1006                "calculateOutofClassContactHoursForTerm has not been implemented");
1007    }
1008
1009    @Override
1010    public Float calculateTotalContactHoursForTerm(String activityOfferingId,
1011                                                   ContextInfo context) throws DoesNotExistException,
1012            InvalidParameterException, MissingParameterException,
1013            OperationFailedException, PermissionDeniedException {
1014        throw new OperationFailedException(
1015                "calculateTotalContactHoursForTerm has not been implemented");
1016    }
1017
1018    @Override
1019    public RegistrationGroupInfo getRegistrationGroup(
1020            String registrationGroupId, ContextInfo context)
1021            throws DoesNotExistException, InvalidParameterException,
1022            MissingParameterException, OperationFailedException,
1023            PermissionDeniedException {
1024        if (!this.registrationGroupMap.containsKey(registrationGroupId)) {
1025            throw new DoesNotExistException(registrationGroupId);
1026        }
1027        return this.registrationGroupMap.get(registrationGroupId);
1028    }
1029
1030    @Override
1031    public List<RegistrationGroupInfo> getRegistrationGroupsByIds(
1032            List<String> registrationGroupIds, ContextInfo context)
1033            throws DoesNotExistException, InvalidParameterException,
1034            MissingParameterException, OperationFailedException,
1035            PermissionDeniedException {
1036        List<RegistrationGroupInfo> list = new ArrayList<RegistrationGroupInfo>();
1037        for (String id : registrationGroupIds) {
1038            list.add(this.getRegistrationGroup(id, context));
1039        }
1040        return list;
1041    }
1042
1043    @Override
1044    public List<RegistrationGroupInfo> getRegistrationGroupsForCourseOffering(
1045            String courseOfferingId, ContextInfo context)
1046            throws DoesNotExistException, InvalidParameterException,
1047            MissingParameterException, OperationFailedException,
1048            PermissionDeniedException {
1049
1050        List<RegistrationGroupInfo> regGroupList = new ArrayList<RegistrationGroupInfo>();
1051
1052        for (RegistrationGroupInfo rg : this.registrationGroupMap.values()) {
1053            if (rg.getCourseOfferingId().equals(courseOfferingId)) {
1054                regGroupList.add(rg);
1055            }
1056        }
1057
1058        return regGroupList;
1059    }
1060
1061    @Override
1062    public List<RegistrationGroupInfo> getRegistrationGroupsWithActivityOfferings(
1063            List<String> activityOfferingIds, ContextInfo context)
1064            throws DoesNotExistException, InvalidParameterException,
1065            MissingParameterException, OperationFailedException,
1066            PermissionDeniedException {
1067
1068        List<RegistrationGroupInfo> regGroupList = new ArrayList<RegistrationGroupInfo>();
1069
1070        for (RegistrationGroupInfo rg : this.registrationGroupMap.values()) {
1071            if (CollectionUtils.isSubCollection(activityOfferingIds,
1072                    rg.getActivityOfferingIds())) {
1073                regGroupList.add(rg);
1074            }
1075        }
1076
1077        return regGroupList;
1078
1079    }
1080
1081    @Override
1082    public List<RegistrationGroupInfo> getRegistrationGroupsByActivityOffering(@WebParam(name = "activityOfferingId") String activityOfferingId, @WebParam(name = "context") ContextInfo context) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1083        List<RegistrationGroupInfo> regGroupList = new ArrayList<RegistrationGroupInfo>();
1084
1085        for (RegistrationGroupInfo rg : this.registrationGroupMap.values()) {
1086            if (rg.getActivityOfferingIds().contains(activityOfferingId)) {
1087                regGroupList.add(rg);
1088            }
1089        }
1090
1091        return regGroupList;
1092    }
1093
1094    @Override
1095    public List<RegistrationGroupInfo> getRegistrationGroupsByFormatOffering(
1096            String formatOfferingId, ContextInfo context)
1097            throws DoesNotExistException, InvalidParameterException,
1098            MissingParameterException, OperationFailedException,
1099            PermissionDeniedException {
1100
1101        List<RegistrationGroupInfo> regGroupList = new ArrayList<RegistrationGroupInfo>();
1102
1103        for (RegistrationGroupInfo rg : this.registrationGroupMap.values()) {
1104
1105            if (rg.getFormatOfferingId().equals(formatOfferingId))
1106                regGroupList.add(rg);
1107        }
1108
1109        return regGroupList;
1110
1111    }
1112
1113    // cache variable
1114    // The LinkedHashMap is just so the values come back in a predictable order
1115    private Map<String, RegistrationGroupInfo> registrationGroupMap = new LinkedHashMap<String, RegistrationGroupInfo>();
1116
1117
1118    @Override
1119    public RegistrationGroupInfo updateRegistrationGroup(
1120            String registrationGroupId,
1121            RegistrationGroupInfo registrationGroupInfo, ContextInfo context)
1122            throws DataValidationErrorException, DoesNotExistException,
1123            InvalidParameterException, MissingParameterException,
1124            OperationFailedException, PermissionDeniedException,
1125            ReadOnlyException, VersionMismatchException {
1126        // update
1127        if (!registrationGroupId.equals(registrationGroupInfo.getId())) {
1128            throw new InvalidParameterException(
1129                    "The id parameter does not match the id on the info object");
1130        }
1131        RegistrationGroupInfo copy = new RegistrationGroupInfo(
1132                registrationGroupInfo);
1133        RegistrationGroupInfo old = this.getRegistrationGroup(
1134                registrationGroupInfo.getId(), context);
1135        if (!old.getMeta().getVersionInd()
1136                .equals(copy.getMeta().getVersionInd())) {
1137            throw new VersionMismatchException(old.getMeta().getVersionInd());
1138        }
1139        copy.setMeta(updateMeta(copy.getMeta(), context));
1140        this.registrationGroupMap.put(registrationGroupInfo.getId(), copy);
1141        return new RegistrationGroupInfo(copy);
1142    }
1143
1144    @Override
1145    public StatusInfo deleteRegistrationGroup(String registrationGroupId,
1146                                              ContextInfo context) throws DoesNotExistException,
1147            InvalidParameterException, MissingParameterException,
1148            OperationFailedException, PermissionDeniedException {
1149        if (this.registrationGroupMap.remove(registrationGroupId) == null) {
1150            throw new DoesNotExistException(registrationGroupId);
1151        }
1152        return successStatus();
1153    }
1154
1155    
1156  private BulkStatusInfo bulkDeleteRegistrationGroup(RegistrationGroupInfo regGroup, ContextInfo context) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1157        
1158        StatusInfo status = deleteRegistrationGroup(regGroup.getId(), context);
1159
1160        BulkStatusInfo bulkStatus = new BulkStatusInfo();
1161        
1162        bulkStatus.setId(regGroup.getId());
1163        bulkStatus.setSuccess(status.getIsSuccess());
1164        bulkStatus.setMessage("Registration Group Deleted");
1165        
1166        return bulkStatus;
1167    }
1168    
1169    @Override
1170    public List<BulkStatusInfo> deleteRegistrationGroupsByFormatOffering(
1171            String formatOfferingId, ContextInfo context)
1172            throws InvalidParameterException, MissingParameterException,
1173            OperationFailedException, PermissionDeniedException {
1174
1175        List<BulkStatusInfo> rgChanges = new ArrayList<BulkStatusInfo>();
1176        List<RegistrationGroupInfo> rgs;
1177        try {
1178            rgs = getRegistrationGroupsByFormatOffering(formatOfferingId, context);
1179
1180            for (RegistrationGroupInfo rg : rgs) {
1181
1182                   rgChanges.add(bulkDeleteRegistrationGroup(rg, context));
1183            }
1184
1185        } catch (DoesNotExistException e) {
1186            throw new OperationFailedException("deleteRegistrationGroupsByFormatOffering (formatOfferingId=" + formatOfferingId + "): failed.", e);
1187        }
1188
1189        return rgChanges;
1190    }
1191
1192    @Override
1193    public List<BulkStatusInfo>  deleteGeneratedRegistrationGroupsByFormatOffering(
1194            String formatOfferingId, ContextInfo context)
1195            throws InvalidParameterException, MissingParameterException,
1196            OperationFailedException, PermissionDeniedException {
1197
1198        List<RegistrationGroupInfo> rgs;
1199        List<BulkStatusInfo> rgChanges = new ArrayList<BulkStatusInfo>();
1200        
1201        
1202        try {
1203            rgs = getRegistrationGroupsByFormatOffering(formatOfferingId, context);
1204
1205            for (RegistrationGroupInfo rg : rgs) {
1206
1207                if (rg.getIsGenerated()) {
1208                    rgChanges.add(bulkDeleteRegistrationGroup(rg, context));
1209                }
1210
1211            }
1212
1213        } catch (DoesNotExistException e) {
1214            throw new OperationFailedException("deleteGeneratedRegistrationGroupsByFormatOffering (formatOfferingId=" + formatOfferingId + "): failed", e);
1215        }
1216
1217
1218        return rgChanges;
1219    }
1220
1221    @Override
1222    public List<BulkStatusInfo> deleteRegistrationGroupsForCluster(String activityOfferingClusterId, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1223
1224        // copy list to avoid concurrent modification exceptions
1225        Collection<RegistrationGroupInfo>groups = new ArrayList<RegistrationGroupInfo> (this.registrationGroupMap.values());
1226        
1227        List<BulkStatusInfo> rgChanges = new ArrayList<BulkStatusInfo>();
1228        
1229       for (RegistrationGroupInfo rg : groups) {
1230        
1231            if (rg.getActivityOfferingClusterId().equals(activityOfferingClusterId)) {
1232                
1233                try {
1234                    rgChanges.add(bulkDeleteRegistrationGroup(rg, contextInfo));
1235                } catch (DoesNotExistException e) {
1236                    throw new OperationFailedException("Bulk Delete Failed", e);
1237                }
1238            }
1239        }
1240                
1241        return rgChanges;
1242        
1243        
1244        }
1245
1246   
1247
1248    @Override
1249    public List<ValidationResultInfo> verifyRegistrationGroup(String registrationGroupId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException {
1250        return Collections.emptyList();
1251    }
1252
1253    @Override
1254    public List<ValidationResultInfo> validateRegistrationGroup(
1255            String validationType, String activityOfferingClusterId, String registrationGroupType, RegistrationGroupInfo registrationGroupInfo,
1256            ContextInfo context) throws DoesNotExistException,
1257            InvalidParameterException, MissingParameterException,
1258            OperationFailedException {
1259        // validate
1260        // this is actually done at the ValidationDecorator layer
1261        return new ArrayList<ValidationResultInfo>();
1262    }
1263
1264    @Override
1265    public ActivityOfferingClusterInfo getActivityOfferingCluster(
1266            String activityOfferingClusterId, ContextInfo contextInfo)
1267            throws DoesNotExistException, InvalidParameterException,
1268            MissingParameterException, OperationFailedException,
1269            PermissionDeniedException {
1270
1271        ActivityOfferingClusterInfo aoc = this.activityOfferingClusterMap
1272                .get(activityOfferingClusterId);
1273
1274        if (aoc == null)
1275            throw new DoesNotExistException(
1276                    "No ActivityOfferingCluster for id = "
1277                            + activityOfferingClusterId);
1278
1279        return new ActivityOfferingClusterInfo(aoc);
1280
1281    }
1282
1283    @Override
1284    public List<ActivityOfferingClusterInfo> getActivityOfferingClustersByIds(List<String> activityOfferingClusterIds, ContextInfo context) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1285        List<ActivityOfferingClusterInfo> results = new ArrayList<ActivityOfferingClusterInfo>();
1286
1287        if(activityOfferingClusterIds != null && !activityOfferingClusterIds.isEmpty()) {
1288            for(String id : activityOfferingClusterIds) {
1289                results.add(getActivityOfferingCluster(id, context));
1290            }
1291        }
1292
1293        return results;
1294    }
1295
1296    @Override
1297    public List<ActivityOfferingClusterInfo> getActivityOfferingClustersByFormatOffering(String formatOfferingId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1298        List<ActivityOfferingClusterInfo> clusters = new ArrayList<ActivityOfferingClusterInfo>();
1299        for (ActivityOfferingClusterInfo info: this.activityOfferingClusterMap.values()) {
1300            if (info.getFormatOfferingId().equals(formatOfferingId)) {
1301                clusters.add(info);
1302            }
1303        }
1304        return clusters;
1305    }
1306
1307
1308    @Override
1309    public List<ValidationResultInfo> validateActivityOfferingCluster(
1310            String validationTypeKey,
1311            String formatOfferingId,
1312            ActivityOfferingClusterInfo activityOfferingClusterInfo,
1313             ContextInfo contextInfo)
1314            throws DoesNotExistException, InvalidParameterException,
1315            MissingParameterException, OperationFailedException {
1316        // Note: validation is handled in the CourseOfferingServiceValidationDecorator
1317        return new ArrayList<ValidationResultInfo>();
1318    }
1319
1320    @Override
1321    public StatusInfo deleteActivityOfferingClusterCascaded(
1322            String activityOfferingClusterId,
1323             ContextInfo contextInfo)
1324            throws DoesNotExistException, InvalidParameterException,
1325            MissingParameterException, OperationFailedException,
1326            PermissionDeniedException {
1327
1328        List<RegistrationGroupInfo> rgList = getRegistrationGroupsByActivityOfferingCluster(activityOfferingClusterId, contextInfo);
1329
1330        for (RegistrationGroupInfo rg : rgList) {
1331            deleteRegistrationGroup(rg.getId(), contextInfo);
1332        }
1333
1334        try {
1335            deleteActivityOfferingCluster(activityOfferingClusterId, contextInfo);
1336        } catch (DependentObjectsExistException e) {
1337            throw new OperationFailedException("unexpected reg group exists for activityOfferingCluster = " + activityOfferingClusterId);
1338        }
1339
1340        return successStatus();
1341    }
1342
1343    private Map<String, ActivityOfferingClusterInfo> activityOfferingClusterMap = new LinkedHashMap<String, ActivityOfferingClusterInfo>();
1344
1345    private void _createAOSets(FormatOfferingInfo foInfo, ActivityOfferingClusterInfo clusterInfo) {
1346        if (clusterInfo.getActivityOfferingSets() == null) {
1347            // Shouldn't be necessary, but just in case.
1348            clusterInfo.setActivityOfferingSets(new ArrayList<ActivityOfferingSetInfo>());
1349        }
1350        List<ActivityOfferingSetInfo> setInfos = clusterInfo.getActivityOfferingSets();
1351        List<String> aoTypeKeys = foInfo.getActivityOfferingTypeKeys();
1352        if (aoTypeKeys != null) {
1353            for (String aoTypeKey: aoTypeKeys) {
1354                // Create an AOSetInfo
1355                ActivityOfferingSetInfo setInfo = new ActivityOfferingSetInfo();
1356                setInfo.setActivityOfferingType(aoTypeKey);
1357                setInfo.setActivityOfferingIds(new ArrayList<String>()); // leave it empty for now
1358                // Add it to the list
1359                setInfos.add(setInfo);
1360            }
1361        }
1362    }
1363
1364    @Override
1365    public ActivityOfferingClusterInfo createActivityOfferingCluster(String formatOfferingId,
1366                                                                     String activityOfferingClusterTypeKey, ActivityOfferingClusterInfo activityOfferingClusterInfo,
1367                                                                     ContextInfo contextInfo)
1368            throws DataValidationErrorException,
1369            DoesNotExistException,
1370            InvalidParameterException,
1371            MissingParameterException,
1372            OperationFailedException,
1373            PermissionDeniedException,
1374            ReadOnlyException {
1375
1376        ActivityOfferingClusterInfo copy = new ActivityOfferingClusterInfo(
1377                activityOfferingClusterInfo);
1378
1379        if (copy.getActivityOfferingSets().isEmpty()) {
1380            FormatOfferingInfo foInfo = getFormatOffering(formatOfferingId, contextInfo);
1381            _createAOSets(foInfo, copy);
1382        }
1383
1384        if (copy.getId() == null) {
1385            copy.setId(UUIDHelper.genStringUUID());
1386        }
1387
1388        copy.setMeta(newMeta(contextInfo));
1389
1390        activityOfferingClusterMap.put(copy.getId(), copy);
1391
1392        return copy;
1393
1394    }
1395
1396    @Override
1397    public AOClusterVerifyResultsInfo verifyActivityOfferingClusterForGeneration(String activityOfferingClusterId, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
1398        // This is the same implementation as the CourseOfferingServiceImpl.  (It had been unimplemented).
1399        // TODO: Find some way to resuse the COSI impl.
1400        AOClusterVerifyResultsInfo aoClusterVerifyResultsInfo = new AOClusterVerifyResultsInfo();
1401        List<ValidationResultInfo> validationResultInfos = new ArrayList<ValidationResultInfo>() ;
1402        ValidationResultInfo validationResultInfo = new ValidationResultInfo();
1403
1404        try {
1405            ActivityOfferingClusterInfo aoCInfo = getActivityOfferingCluster(activityOfferingClusterId, contextInfo);
1406            List<ActivityOfferingSetInfo> aoSetInfos = aoCInfo.getActivityOfferingSets();
1407
1408            for (ActivityOfferingSetInfo aoSetInfo : aoSetInfos ){
1409                List<String> aoIdList = aoSetInfo.getActivityOfferingIds();
1410                if (aoIdList == null || aoIdList.isEmpty()) {
1411                    //invalidValidationInfo.setError("");
1412                    validationResultInfo.setLevel(ValidationResult.ErrorLevel.ERROR);
1413                    validationResultInfos.add(validationResultInfo);
1414                    aoClusterVerifyResultsInfo.setValidationResults(validationResultInfos);
1415
1416                    return aoClusterVerifyResultsInfo;
1417                }
1418            }
1419        } catch (Exception ex) {
1420            throw new OperationFailedException("unexpected", ex);
1421        }
1422
1423        validationResultInfo.setLevel(ValidationResult.ErrorLevel.OK);
1424        validationResultInfos.add(validationResultInfo);
1425        aoClusterVerifyResultsInfo.setValidationResults(validationResultInfos);
1426
1427        return aoClusterVerifyResultsInfo;
1428    }
1429
1430
1431    @Override
1432    public ActivityOfferingClusterInfo updateActivityOfferingCluster(String formatOfferingId, String activityOfferingClusterId,
1433                                                                     ActivityOfferingClusterInfo activityOfferingClusterInfo, ContextInfo contextInfo)
1434            throws DataValidationErrorException,
1435            DoesNotExistException,
1436            InvalidParameterException,
1437            MissingParameterException,
1438            OperationFailedException,
1439            PermissionDeniedException,
1440            ReadOnlyException,
1441            VersionMismatchException {
1442
1443        // update
1444        if (!activityOfferingClusterId.equals(activityOfferingClusterInfo.getId())) {
1445            throw new InvalidParameterException(
1446                    "The id parameter does not match the id on the info object");
1447        }
1448        ActivityOfferingClusterInfo copy = new ActivityOfferingClusterInfo(activityOfferingClusterInfo);
1449        ActivityOfferingClusterInfo old = this.getActivityOfferingCluster(
1450                activityOfferingClusterId, contextInfo);
1451        // Figure out IDs that appear in old, but not in copy.
1452        Set<String> oldIds = new HashSet<String>(); // First the old Ids
1453        for (ActivityOfferingSetInfo set: old.getActivityOfferingSets()) {
1454            oldIds.addAll(set.getActivityOfferingIds());
1455        }
1456        Set<String> copyIds = new HashSet<String>(); // First the old Ids
1457        for (ActivityOfferingSetInfo set: copy.getActivityOfferingSets()) {
1458            copyIds.addAll(set.getActivityOfferingIds());
1459        }
1460        oldIds.removeAll(copyIds);
1461        for (String aoId: oldIds) {
1462            // Find any RGs that contain these aoIds
1463            for (Map.Entry<String, RegistrationGroupInfo> entry: this.registrationGroupMap.entrySet()) {
1464                if (entry.getValue().getFormatOfferingId().equals(formatOfferingId) &&
1465                        entry.getValue().getActivityOfferingIds().contains(aoId)) {
1466                    // Delete RG with this ao id
1467                    this.registrationGroupMap.remove(entry.getKey());
1468                }
1469            }
1470        }
1471
1472        if (!old.getMeta().getVersionInd()
1473                .equals(copy.getMeta().getVersionInd())) {
1474            throw new VersionMismatchException(old.getMeta().getVersionInd());
1475        }
1476        copy.setMeta(updateMeta(copy.getMeta(), contextInfo));
1477        this.activityOfferingClusterMap.put(activityOfferingClusterInfo.getId(), copy);
1478
1479        return new ActivityOfferingClusterInfo(copy);
1480
1481    }
1482
1483    @Override
1484    public StatusInfo deleteActivityOfferingCluster(
1485            String activityOfferingClusterId, ContextInfo context)
1486            throws DoesNotExistException, InvalidParameterException,
1487            MissingParameterException, OperationFailedException,
1488            PermissionDeniedException, DependentObjectsExistException {
1489
1490        // note validation is in the validation decorator.
1491        ActivityOfferingClusterInfo aoc = this.activityOfferingClusterMap.remove(activityOfferingClusterId);
1492
1493        if (aoc == null)
1494            throw new DoesNotExistException("No ActivityOfferingCluster for Id = " + activityOfferingClusterId);
1495
1496        return successStatus();
1497
1498    }
1499
1500    @Override
1501    public SeatPoolDefinitionInfo getSeatPoolDefinition(
1502            String seatPoolDefinitionId, ContextInfo context)
1503            throws DoesNotExistException, InvalidParameterException,
1504            MissingParameterException, OperationFailedException,
1505            PermissionDeniedException {
1506        if (!this.seatPoolDefinitionMap.containsKey(seatPoolDefinitionId)) {
1507            throw new DoesNotExistException(seatPoolDefinitionId);
1508        }
1509        return this.seatPoolDefinitionMap.get(seatPoolDefinitionId);
1510    }
1511
1512    @Override
1513    public List<SeatPoolDefinitionInfo> getSeatPoolDefinitionsForActivityOffering(
1514            String activityOfferingId, ContextInfo context)
1515            throws DoesNotExistException, InvalidParameterException,
1516            MissingParameterException, OperationFailedException,
1517            PermissionDeniedException {
1518
1519        // will throw does not exist exception if there is no matching activity id
1520        ActivityOfferingInfo ao = getActivityOffering(activityOfferingId, context);
1521
1522        List<String> seatPoolIds = activityOfferingToSeatPoolMap.get(activityOfferingId);
1523
1524        if (seatPoolIds == null)
1525            return new ArrayList<SeatPoolDefinitionInfo>();
1526
1527        List<SeatPoolDefinitionInfo> seatPoolInfos = new ArrayList<SeatPoolDefinitionInfo>(seatPoolIds.size());
1528
1529        for (String spId : seatPoolIds) {
1530
1531            SeatPoolDefinitionInfo sp = getSeatPoolDefinition(spId, context);
1532
1533            seatPoolInfos.add(sp);
1534        }
1535
1536        return seatPoolInfos;
1537
1538
1539    }
1540
1541    // cache variable
1542    // The LinkedHashMap is just so the values come back in a predictable order
1543    private Map<String, SeatPoolDefinitionInfo> seatPoolDefinitionMap = new LinkedHashMap<String, SeatPoolDefinitionInfo>();
1544
1545    @Override
1546    public SeatPoolDefinitionInfo createSeatPoolDefinition(
1547            SeatPoolDefinitionInfo seatPoolDefinitionInfo, ContextInfo context)
1548            throws DataValidationErrorException, InvalidParameterException,
1549            MissingParameterException, OperationFailedException,
1550            PermissionDeniedException, ReadOnlyException {
1551        // create
1552        SeatPoolDefinitionInfo copy = new SeatPoolDefinitionInfo(
1553                seatPoolDefinitionInfo);
1554        if (copy.getId() == null) {
1555            copy.setId(UUIDHelper.genStringUUID());
1556        }
1557        copy.setMeta(newMeta(context));
1558        seatPoolDefinitionMap.put(copy.getId(), copy);
1559        return new SeatPoolDefinitionInfo(copy);
1560    }
1561
1562    @Override
1563    public SeatPoolDefinitionInfo updateSeatPoolDefinition(
1564            String seatPoolDefinitionId,
1565            SeatPoolDefinitionInfo seatPoolDefinitionInfo, ContextInfo context)
1566            throws DataValidationErrorException, DoesNotExistException,
1567            InvalidParameterException, MissingParameterException,
1568            OperationFailedException, PermissionDeniedException,
1569            ReadOnlyException, VersionMismatchException {
1570        // update
1571        if (!seatPoolDefinitionId.equals(seatPoolDefinitionInfo.getId())) {
1572            throw new InvalidParameterException(
1573                    "The id parameter does not match the id on the info object");
1574        }
1575        SeatPoolDefinitionInfo copy = new SeatPoolDefinitionInfo(
1576                seatPoolDefinitionInfo);
1577        SeatPoolDefinitionInfo old = this.getSeatPoolDefinition(
1578                seatPoolDefinitionInfo.getId(), context);
1579        if (!old.getMeta().getVersionInd()
1580                .equals(copy.getMeta().getVersionInd())) {
1581            throw new VersionMismatchException(old.getMeta().getVersionInd());
1582        }
1583        copy.setMeta(updateMeta(copy.getMeta(), context));
1584        this.seatPoolDefinitionMap.put(seatPoolDefinitionInfo.getId(), copy);
1585        return new SeatPoolDefinitionInfo(copy);
1586    }
1587
1588    @Override
1589    public List<ValidationResultInfo> validateSeatPoolDefinition(
1590            String validationTypeKey,
1591            SeatPoolDefinitionInfo seatPoolDefinitionInfo, ContextInfo context)
1592            throws DoesNotExistException,
1593            InvalidParameterException, MissingParameterException,
1594            OperationFailedException, PermissionDeniedException {
1595        // validate
1596        return new ArrayList<ValidationResultInfo>();
1597    }
1598
1599    @Override
1600    public StatusInfo deleteSeatPoolDefinition(String seatPoolDefinitionId,
1601                                               ContextInfo context) throws DoesNotExistException,
1602            InvalidParameterException, MissingParameterException,
1603            OperationFailedException, PermissionDeniedException {
1604        if (this.seatPoolDefinitionMap.remove(seatPoolDefinitionId) == null) {
1605            throw new DoesNotExistException(seatPoolDefinitionId);
1606        }
1607        return successStatus();
1608    }
1609
1610    @Override
1611    public List<CourseOfferingInfo> searchForCourseOfferings(
1612            QueryByCriteria criteria, ContextInfo context)
1613            throws InvalidParameterException, MissingParameterException,
1614            OperationFailedException, PermissionDeniedException {
1615
1616        throw new OperationFailedException(
1617                "searchForCourseOfferings has not been implemented");
1618    }
1619
1620    @Override
1621    public List<String> searchForCourseOfferingIds(QueryByCriteria criteria,
1622                                                   ContextInfo context) throws InvalidParameterException,
1623            MissingParameterException, OperationFailedException,
1624            PermissionDeniedException {
1625        throw new OperationFailedException(
1626                "searchForCourseOfferingIds has not been implemented");
1627    }
1628
1629    @Override
1630    public List<ActivityOfferingInfo> searchForActivityOfferings(
1631            QueryByCriteria criteria, ContextInfo context)
1632            throws InvalidParameterException, MissingParameterException,
1633            OperationFailedException, PermissionDeniedException {
1634        throw new OperationFailedException(
1635                "searchForActivityOfferings has not been implemented");
1636    }
1637
1638    @Override
1639    public List<String> searchForActivityOfferingIds(QueryByCriteria criteria,
1640                                                     ContextInfo context) throws InvalidParameterException,
1641            MissingParameterException, OperationFailedException,
1642            PermissionDeniedException {
1643        throw new OperationFailedException(
1644                "searchForActivityOfferingIds has not been implemented");
1645    }
1646
1647    @Override
1648    public List<RegistrationGroupInfo> searchForRegistrationGroups(
1649            QueryByCriteria criteria, ContextInfo context)
1650            throws InvalidParameterException, MissingParameterException,
1651            OperationFailedException, PermissionDeniedException {
1652        throw new OperationFailedException(
1653                "searchForRegistrationGroups has not been implemented");
1654    }
1655
1656    @Override
1657    public List<String> searchForRegistrationGroupIds(QueryByCriteria criteria,
1658                                                      ContextInfo context) throws InvalidParameterException,
1659            MissingParameterException, OperationFailedException,
1660            PermissionDeniedException {
1661        throw new OperationFailedException(
1662                "searchForRegistrationGroupIds has not been implemented");
1663    }
1664
1665    @Override
1666    public List<SeatPoolDefinitionInfo> searchForSeatpoolDefinitions(
1667            QueryByCriteria criteria, ContextInfo context)
1668            throws InvalidParameterException, MissingParameterException,
1669            OperationFailedException, PermissionDeniedException {
1670        throw new OperationFailedException(
1671                "searchForSeatpoolDefinitions has not been implemented");
1672    }
1673
1674    @Override
1675    public List<String> searchForSeatpoolDefinitionIds(
1676            QueryByCriteria criteria, ContextInfo context)
1677            throws InvalidParameterException, MissingParameterException,
1678            OperationFailedException, PermissionDeniedException {
1679        throw new OperationFailedException(
1680                "searchForSeatpoolDefinitionIds has not been implemented");
1681    }
1682
1683    @Override
1684    public CourseOfferingDisplayInfo getCourseOfferingDisplay(
1685            String courseOfferingId, ContextInfo context)
1686            throws DoesNotExistException, InvalidParameterException,
1687            MissingParameterException, OperationFailedException,
1688            PermissionDeniedException {
1689        CourseOfferingInfo co = this.getCourseOffering(courseOfferingId, context);
1690        CourseOfferingDisplayInfo info = new CourseOfferingDisplayInfo();
1691        info.setId(co.getId());
1692        info.setTypeKey(co.getTypeKey());
1693        info.setStateKey(co.getStateKey());
1694        info.setDescr (co.getDescr ());
1695        info.setCourseId(co.getCourseId());
1696        info.setTermId(co.getTermId());
1697        info.setCourseOfferingCode(co.getCourseOfferingCode());
1698        info.setCourseOfferingTitle(co.getCourseOfferingTitle());
1699        info.setSubjectArea(co.getSubjectArea());
1700        TermInfo term = this.acalService.getTerm(co.getTermId(), context);
1701        info.setTermName(term.getName());
1702        info.setTermCode(term.getCode());
1703        info.setGradingOption(new KeyNameInfo(co.getGradingOptionId(), co.getGradingOptionName()));
1704        info.setCreditOption(new KeyNameInfo(co.getCreditOptionId(), co.getCreditOptionName()));
1705        TypeInfo type = typeService.getType(co.getTypeKey(), context);
1706        info.setTypeName(type.getName());
1707        StateInfo state = stateService.getState(co.getStateKey(), context);
1708        info.setStateName(state.getName());
1709        info.setMeta(co.getMeta());
1710        info.setAttributes(co.getAttributes());
1711        return info;
1712    }
1713
1714    private List<String> calcActivityOfferingTypes(CourseOfferingInfo co, ContextInfo context)
1715            throws DoesNotExistException, InvalidParameterException, MissingParameterException,
1716            OperationFailedException, PermissionDeniedException {
1717        List<String> list = new ArrayList<String>();
1718        for (FormatOfferingInfo fo : this.getFormatOfferingsByCourseOffering(co.getId(), context)) {
1719            list.addAll(fo.getActivityOfferingTypeKeys());
1720        }
1721        return list;
1722    }
1723
1724    @Override
1725    public List<CourseOfferingDisplayInfo> getCourseOfferingDisplaysByIds(
1726            List<String> courseOfferingIds, ContextInfo context)
1727            throws DoesNotExistException, InvalidParameterException,
1728            MissingParameterException, OperationFailedException,
1729            PermissionDeniedException {
1730        throw new OperationFailedException(
1731                "getCourseOfferingDisplayByIds has not been implemented");
1732    }
1733
1734    @Override
1735    public ActivityOfferingDisplayInfo getActivityOfferingDisplay(
1736            String activityOfferingId, ContextInfo contextInfo)
1737            throws DoesNotExistException, InvalidParameterException,
1738                MissingParameterException, OperationFailedException,
1739                PermissionDeniedException {
1740        ActivityOfferingInfo ao = this.getActivityOffering(activityOfferingId, contextInfo);
1741        ActivityOfferingDisplayInfo info = new ActivityOfferingDisplayInfo();
1742        info.setId(ao.getId());
1743        info.setTypeKey(ao.getTypeKey());
1744        info.setStateKey(ao.getStateKey());
1745        info.setName(ao.getName());
1746        info.setDescr(ao.getDescr());
1747        TypeInfo type = typeService.getType(ao.getTypeKey(), contextInfo);
1748        info.setTypeName(type.getName());
1749        StateInfo state = stateService.getState(ao.getStateKey(), contextInfo);
1750        info.setStateName(state.getName());
1751        info.setCourseOfferingTitle(ao.getCourseOfferingTitle());
1752        info.setCourseOfferingCode(ao.getCourseOfferingCode());
1753        info.setFormatOfferingId(ao.getFormatOfferingId());
1754        info.setFormatOfferingName(ao.getFormatOfferingName());
1755        info.setActivityOfferingCode(ao.getActivityCode());
1756       
1757        info.setInstructorId(ao.getInstructors().get(0).getPersonId());
1758        info.setInstructorName(ao.getInstructors().get(0).getPersonName());
1759
1760        info.setIsHonorsOffering(ao.getIsHonorsOffering());
1761        info.setMaximumEnrollment(ao.getMaximumEnrollment());
1762        //  Get the schedule components from all schedules and put them in a single ScheduleDisplayInfo.
1763        if (ao.getScheduleIds() != null && ! ao.getScheduleIds().isEmpty()) {
1764            List<ScheduleDisplayInfo> scheduleDisplays = schedulingService.getScheduleDisplaysByIds(ao.getScheduleIds(), contextInfo);
1765            List<ScheduleComponentDisplayInfo> scheduleComponentDisplayInfos = new ArrayList<ScheduleComponentDisplayInfo>();
1766            for (ScheduleDisplayInfo sdi : scheduleDisplays) {
1767                scheduleComponentDisplayInfos.addAll((List<ScheduleComponentDisplayInfo>) sdi.getScheduleComponentDisplays());
1768            }
1769            ScheduleDisplayInfo sdiAggregate = new ScheduleDisplayInfo();
1770            sdiAggregate.setScheduleComponentDisplays(scheduleComponentDisplayInfos);
1771            info.setScheduleDisplay(sdiAggregate);
1772        }
1773        info.setMeta(ao.getMeta());
1774        info.setAttributes(ao.getAttributes());
1775        return info;
1776    }
1777
1778    
1779        @Override
1780        public List<ActivityOfferingDisplayInfo> getActivityOfferingDisplaysByIds(
1781                        List<String> activityOfferingIds, ContextInfo contextInfo)
1782                        throws DoesNotExistException, InvalidParameterException,
1783                        MissingParameterException, OperationFailedException,
1784                        PermissionDeniedException {
1785                throw new UnsupportedOperationException("Not supported yet");
1786        }
1787
1788    @Override
1789    public List<ActivityOfferingDisplayInfo> getActivityOfferingDisplaysForCourseOffering(
1790            String courseOfferingId, ContextInfo contextInfo)
1791            throws DoesNotExistException, InvalidParameterException,
1792            MissingParameterException, OperationFailedException,
1793            PermissionDeniedException {
1794        throw new UnsupportedOperationException("Not supported yet");
1795    }
1796
1797    @Override
1798    public List<String> getValidCanonicalCourseToCourseOfferingOptionKeys(
1799            ContextInfo context) throws InvalidParameterException,
1800            MissingParameterException, OperationFailedException,
1801            PermissionDeniedException, ReadOnlyException {
1802        List<String> options = new ArrayList();
1803        options.add(CourseOfferingSetServiceConstants.NOT_COURSE_TITLE_OPTION_KEY);
1804        options.add(CourseOfferingSetServiceConstants.CREDITS_MATCH_SCHEDULED_HOURS_OPTION_KEY);
1805        return options;
1806    }
1807
1808    @Override
1809    public List<String> getValidRolloverOptionKeys(ContextInfo context)
1810            throws InvalidParameterException, MissingParameterException,
1811            OperationFailedException, PermissionDeniedException,
1812            ReadOnlyException {
1813        List<String> options = new ArrayList();
1814        // what courses
1815        options.add(CourseOfferingSetServiceConstants.STILL_OFFERABLE_OPTION_KEY);
1816        options.add(CourseOfferingSetServiceConstants.IF_NO_NEW_VERSION_OPTION_KEY);
1817        options.add(CourseOfferingSetServiceConstants.IGNORE_CANCELLED_OPTION_KEY);
1818        options.add(CourseOfferingSetServiceConstants.SKIP_IF_ALREADY_EXISTS_OPTION_KEY);
1819        // what data
1820        options.add(CourseOfferingSetServiceConstants.USE_CANONICAL_OPTION_KEY);
1821        options.add(CourseOfferingSetServiceConstants.NO_INSTRUCTORS_OPTION_KEY);
1822        options.add(CourseOfferingSetServiceConstants.NO_SCHEDULE_OPTION_KEY);
1823        return options;
1824    }
1825
1826    @Override
1827    public SocRolloverResultItemInfo rolloverCourseOffering(
1828            String sourceCourseOfferingId, String targetTermId,
1829            List<String> optionKeys, ContextInfo context)
1830            throws AlreadyExistsException, DataValidationErrorException,
1831            DoesNotExistException, DataValidationErrorException,
1832            InvalidParameterException, MissingParameterException,
1833            OperationFailedException, PermissionDeniedException,
1834            ReadOnlyException {
1835        return this.businessLogic.rolloverCourseOffering(
1836                sourceCourseOfferingId, targetTermId, optionKeys, context);
1837    }
1838
1839    private MetaInfo newMeta(ContextInfo context) {
1840        MetaInfo meta = new MetaInfo();
1841        meta.setCreateId(context.getPrincipalId());
1842        meta.setCreateTime(new Date());
1843        meta.setUpdateId(context.getPrincipalId());
1844        meta.setUpdateTime(meta.getCreateTime());
1845        meta.setVersionInd("0");
1846        return meta;
1847    }
1848
1849    private StatusInfo successStatus() {
1850        StatusInfo status = new StatusInfo();
1851        status.setSuccess(Boolean.TRUE);
1852        return status;
1853    }
1854
1855    private StatusInfo failStatus() {
1856        StatusInfo status = new StatusInfo();
1857        status.setMessage("Operation Failed");
1858        status.setSuccess(Boolean.FALSE);
1859        return status;
1860    }
1861
1862    private MetaInfo updateMeta(MetaInfo old, ContextInfo context) {
1863        MetaInfo meta = new MetaInfo(old);
1864        meta.setUpdateId(context.getPrincipalId());
1865        meta.setUpdateTime(new Date());
1866        meta.setVersionInd((Integer.parseInt(meta.getVersionInd()) + 1) + "");
1867        return meta;
1868    }
1869
1870    private Map<String, List<String>> activityOfferingToSeatPoolMap = new HashMap<String, List<String>>();
1871
1872
1873    @Override
1874    public StatusInfo addSeatPoolDefinitionToActivityOffering(
1875            String seatPoolDefinitionId, String activityOfferingId,
1876            ContextInfo contextInfo) throws AlreadyExistsException,
1877            DoesNotExistException, InvalidParameterException,
1878            MissingParameterException, OperationFailedException,
1879            PermissionDeniedException {
1880
1881        // first check that both the reg group and seat pool exist
1882        // these will throw does not exist exceptions
1883        ActivityOfferingInfo ao = getActivityOffering(activityOfferingId, contextInfo);
1884
1885        SeatPoolDefinitionInfo spd = getSeatPoolDefinition(seatPoolDefinitionId, contextInfo);
1886
1887        // now check for an existing association
1888        List<String> seatPoolIds = activityOfferingToSeatPoolMap.get(activityOfferingId);
1889
1890        if (seatPoolIds == null) {
1891            seatPoolIds = new ArrayList<String>();
1892            activityOfferingToSeatPoolMap.put(activityOfferingId, seatPoolIds);
1893        }
1894
1895        if (seatPoolIds.contains(seatPoolDefinitionId))
1896            throw new AlreadyExistsException("registration group (" + activityOfferingId + ") is already associated to seat pool definition (" + seatPoolDefinitionId + ")");
1897
1898        seatPoolIds.add(seatPoolDefinitionId);
1899
1900        return successStatus();
1901    }
1902
1903    @Override
1904    public StatusInfo removeSeatPoolDefinitionFromActivityOffering(
1905            String seatPoolDefinitionId, String activityOfferingId,
1906            ContextInfo contextInfo) throws DoesNotExistException,
1907            InvalidParameterException, MissingParameterException,
1908            OperationFailedException, PermissionDeniedException {
1909
1910        // first check that both the reg group and seat pool exist
1911        // these will throw does not exist exceptions
1912        ActivityOfferingInfo ao = getActivityOffering(activityOfferingId, contextInfo);
1913
1914        SeatPoolDefinitionInfo spd = getSeatPoolDefinition(seatPoolDefinitionId, contextInfo);
1915
1916        getSeatPoolDefinitionsForActivityOffering(activityOfferingId, contextInfo);
1917
1918        List<String> seatPoolIds = activityOfferingToSeatPoolMap.get(activityOfferingId);
1919
1920        if (seatPoolIds.remove(seatPoolDefinitionId))
1921            return successStatus();
1922        else
1923            throw new DoesNotExistException("no seatpool association for spId=" + seatPoolDefinitionId + " and activityOfferingId = " + activityOfferingId);
1924
1925    }
1926
1927    @Override
1928    public List<BulkStatusInfo> generateRegistrationGroupsForFormatOffering(
1929            String formatOfferingId, ContextInfo context)
1930            throws DoesNotExistException, InvalidParameterException,
1931            MissingParameterException, OperationFailedException,
1932            PermissionDeniedException, DataValidationErrorException {
1933
1934        return businessLogic.generateRegistrationGroupsForFormatOffering(formatOfferingId, context);
1935    }
1936
1937    @Override
1938    public List<String> getCourseOfferingIdsByTermAndSubjectArea(String termId,
1939                                                                 String subjectArea, ContextInfo context)
1940            throws DoesNotExistException, InvalidParameterException,
1941            MissingParameterException, OperationFailedException,
1942            PermissionDeniedException {
1943        List<String> list = new ArrayList<String>();
1944        for (CourseOfferingInfo info : courseOfferingMap.values()) {
1945            if (termId.equals(info.getTermId())) {
1946                if (subjectArea.equals(info.getSubjectArea())) {
1947                    list.add(info.getId());
1948                }
1949            }
1950        }
1951        return list;
1952    }
1953
1954    @Override
1955    public StatusInfo changeCourseOfferingState(
1956            String courseOfferingId,
1957            String nextStateKey,
1958             ContextInfo contextInfo)
1959            throws DoesNotExistException, MissingParameterException, OperationFailedException,
1960            PermissionDeniedException {
1961
1962        try {
1963            /*
1964                * get won't work because it doesn't return the map bound instance.
1965                * We need to get that instance ourselves manually.
1966                */
1967            CourseOfferingInfo co = this.courseOfferingMap.get(courseOfferingId);
1968
1969            if (co == null)
1970                throw new DoesNotExistException("No CourseOffering for id= " + courseOfferingId);
1971
1972            co.setStateKey(nextStateKey);
1973
1974            return successStatus();
1975
1976        } catch (Exception e) {
1977            throw new OperationFailedException("changeCourseOfferingState (id=" + courseOfferingId + ", nextStateKey=" + nextStateKey, e);
1978        }
1979    }
1980
1981    @Override
1982    public StatusInfo changeFormatOfferingState(
1983            String formatOfferingId,
1984            String nextStateKey,
1985             ContextInfo contextInfo)
1986            throws DoesNotExistException, MissingParameterException, OperationFailedException {
1987        try {
1988            /*
1989                * get won't work because it doesn't return the map bound instance.
1990                * We need to get that instance ourselves manually.
1991                */
1992            FormatOfferingInfo fo = this.formatOfferingMap.get(formatOfferingId);
1993
1994            if (fo == null)
1995                throw new DoesNotExistException("No FormatOffering for id= " + formatOfferingId);
1996
1997            fo.setStateKey(nextStateKey);
1998
1999            return successStatus();
2000
2001        } catch (Exception e) {
2002            throw new OperationFailedException("changeFormatOfferingState (id=" + formatOfferingId + ", nextStateKey=" + nextStateKey, e);
2003        }
2004    }
2005
2006    @Override
2007    public StatusInfo changeActivityOfferingState(
2008            String activityOfferingId,
2009            String nextStateKey,
2010             ContextInfo contextInfo)
2011            throws DoesNotExistException, MissingParameterException, OperationFailedException,
2012            PermissionDeniedException {
2013
2014        try {
2015            /*
2016                * get won't work because it doesn't return the map bound instance.
2017                * We need to get that instance ourselves manually.
2018                */
2019            ActivityOfferingInfo ao = this.activityOfferingMap.get(activityOfferingId);
2020
2021            if (ao == null)
2022                throw new DoesNotExistException("No ActivityOffering for id= " + activityOfferingId);
2023
2024            ao.setStateKey(nextStateKey);
2025
2026            return successStatus();
2027
2028        } catch (Exception e) {
2029            throw new OperationFailedException("changeActivityOfferingState (id=" + activityOfferingId + ", nextStateKey=" + nextStateKey, e);
2030        }
2031    }
2032
2033    @Override
2034    public StatusInfo changeRegistrationGroupState(
2035            String registrationGroupId,
2036            String nextStateKey,
2037             ContextInfo contextInfo)
2038            throws DoesNotExistException, MissingParameterException, OperationFailedException,
2039            PermissionDeniedException {
2040        try {
2041            /*
2042                * get won't work because it doesn't return the map bound instance.
2043                * We need to get that instance ourselves manually.
2044                */
2045            RegistrationGroupInfo rg = this.registrationGroupMap.get(registrationGroupId);
2046
2047            if (rg == null)
2048                throw new DoesNotExistException("No RegistrationGroup for id= " + registrationGroupId);
2049
2050            rg.setStateKey(nextStateKey);
2051
2052            return successStatus();
2053
2054        } catch (Exception e) {
2055            throw new OperationFailedException("changeRegistrationGroupState (id=" + registrationGroupId + ", nextStateKey=" + nextStateKey, e);
2056        }
2057    }
2058
2059    @Override
2060    public StatusInfo changeActivityOfferingClusterState(
2061            String activityOfferingClusterId,
2062            String nextStateKey,
2063             ContextInfo contextInfo)
2064            throws DoesNotExistException, MissingParameterException, OperationFailedException,
2065            PermissionDeniedException {
2066        try {
2067            /*
2068                * get won't work because it doesn't return the map bound instance.
2069                * We need to get that instance ourselves manually.
2070                */
2071            ActivityOfferingClusterInfo aoc = this.activityOfferingClusterMap.get(activityOfferingClusterId);
2072
2073            if (aoc == null)
2074                throw new DoesNotExistException("No ActivityOfferingCluster for id= " + activityOfferingClusterId);
2075
2076            aoc.setStateKey(nextStateKey);
2077
2078            return successStatus();
2079
2080        } catch (Exception e) {
2081            throw new OperationFailedException("changeActivityOfferingClusterState (id=" + activityOfferingClusterId + ", nextStateKey=" + nextStateKey, e);
2082        }
2083    }
2084
2085    @Override
2086    public StatusInfo changeSeatPoolDefinitionState(
2087            String seatPoolDefinitionId,
2088            String nextStateKey,
2089             ContextInfo contextInfo)
2090            throws DoesNotExistException, MissingParameterException, OperationFailedException,
2091            PermissionDeniedException {
2092        try {
2093            /*
2094                * get won't work because it doesn't return the map bound instance.
2095                * We need to get that instance ourselves manually.
2096                */
2097            SeatPoolDefinitionInfo spd = this.seatPoolDefinitionMap.get(seatPoolDefinitionId);
2098
2099            if (spd == null)
2100                throw new DoesNotExistException("No SeatPoolDefinition for id= " + seatPoolDefinitionId);
2101
2102            spd.setStateKey(nextStateKey);
2103
2104            return successStatus();
2105
2106        } catch (Exception e) {
2107            throw new OperationFailedException("changeSeatPoolDefinitionState (id=" + seatPoolDefinitionId + ", nextStateKey=" + nextStateKey, e);
2108        }
2109    }
2110
2111    @Override
2112    public List<RegistrationGroupInfo> getRegistrationGroupsByActivityOfferingCluster(
2113            String activityOfferingClusterId,
2114             ContextInfo contextInfo)
2115            throws DoesNotExistException, InvalidParameterException,
2116            MissingParameterException, OperationFailedException,
2117            PermissionDeniedException {
2118
2119        List<RegistrationGroupInfo> regGroups = new ArrayList<RegistrationGroupInfo>();
2120
2121        for (RegistrationGroupInfo regGroup : this.registrationGroupMap.values()) {
2122
2123            if (regGroup.getActivityOfferingClusterId().equals(activityOfferingClusterId))
2124                regGroups.add(regGroup);
2125        }
2126
2127        return regGroups;
2128    }
2129
2130    @Override
2131    public List<ActivityOfferingInfo> getActivityOfferingsByCluster(
2132            String activityOfferingClusterId,
2133             ContextInfo contextInfo)
2134            throws DoesNotExistException, InvalidParameterException,
2135            MissingParameterException, OperationFailedException,
2136            PermissionDeniedException {
2137
2138        List<ActivityOfferingInfo> aoList = new ArrayList<ActivityOfferingInfo>();
2139
2140        ActivityOfferingClusterInfo aoc = getActivityOfferingCluster(activityOfferingClusterId, contextInfo);
2141
2142        for (ActivityOfferingSetInfo aocSet : aoc.getActivityOfferingSets()) {
2143
2144            List<ActivityOfferingInfo> setAos = getActivityOfferingsByIds(aocSet.getActivityOfferingIds(), contextInfo);
2145
2146            aoList.addAll(setAos);
2147        }
2148
2149        return aoList;
2150    }
2151
2152    @Override
2153    public List<String> getActivityOfferingClustersIdsByFormatOffering(
2154            String formatOfferingId,
2155             ContextInfo contextInfo)
2156            throws DoesNotExistException, InvalidParameterException,
2157            MissingParameterException, OperationFailedException,
2158            PermissionDeniedException {
2159
2160        List<String> aocIdList = new ArrayList<String>();
2161
2162        for (ActivityOfferingClusterInfo aoc : this.activityOfferingClusterMap.values()) {
2163
2164            if (aoc.getFormatOfferingId().equals(formatOfferingId)) {
2165                aocIdList.add(aoc.getId());
2166            }
2167        }
2168        return aocIdList;
2169
2170    }
2171
2172    
2173    @Override
2174    public List<BulkStatusInfo> generateRegistrationGroupsForCluster(
2175            String activityOfferingClusterId,
2176             ContextInfo contextInfo)
2177            throws DoesNotExistException, 
2178            DataValidationErrorException, InvalidParameterException,
2179            MissingParameterException, OperationFailedException,
2180            PermissionDeniedException {
2181        return businessLogic.generateRegistrationGroupsForCluster(activityOfferingClusterId, contextInfo);
2182    }
2183
2184    @Override
2185    public List<String> searchForActivityOfferingClusterIds(QueryByCriteria criteria, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
2186        throw new UnsupportedOperationException("Not supported yet.");
2187    }
2188
2189    @Override
2190    public List<ActivityOfferingClusterInfo> searchForActivityOfferingClusters(QueryByCriteria criteria, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
2191        throw new UnsupportedOperationException("Not supported yet.");
2192    }
2193
2194    @Override
2195    public List<String> searchForFormatOfferingIds(QueryByCriteria criteria, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
2196        throw new UnsupportedOperationException("Not supported yet.");
2197    }
2198
2199    @Override
2200    public List<FormatOfferingInfo> searchForFormatOfferings(QueryByCriteria criteria, ContextInfo contextInfo) throws InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException {
2201        throw new UnsupportedOperationException("Not supported yet.");
2202    }
2203
2204    @Override
2205    public List<ActivityOfferingInfo> getActivityOfferingsForSeatPoolDefinition(
2206            String seatPoolDefinitionId,
2207             ContextInfo context)
2208            throws DoesNotExistException, InvalidParameterException,
2209            MissingParameterException, OperationFailedException,
2210            PermissionDeniedException {
2211        
2212        List<String> activityOfferingIds = this.activityOfferingToSeatPoolMap.get(seatPoolDefinitionId);
2213
2214        return getActivityOfferingsByIds(activityOfferingIds, context);
2215    }
2216
2217    
2218
2219}