@Override
 public DataSaveResult createCopyCourse(String originalCluId) throws Exception {
   try {
     return copyCourseService.createCopyCourse(originalCluId, ContextUtils.getContextInfo());
   } catch (Exception e) {
     LOG.error(String.format("Error copying course with id: %s", originalCluId), e);
     throw e;
   }
 }
 @Override
 public StatusInfo deleteLoCategory(String loCategoryId) {
   try {
     return loService.deleteLoCategory(loCategoryId, ContextUtils.getContextInfo());
   } catch (Exception e) {
     LOG.error("Exception occurred", e);
   }
   return null;
 }
  /**
   * This overridden method ...
   *
   * @see
   *     org.kuali.student.lum.common.client.lo.rpc.LoCategoryRpcService#getLoCategoryType(java.lang.String)
   */
  @Override
  public TypeInfo getLoCategoryType(String loCategoryTypeKey) {
    try {
      return loService.getLoCategoryType(loCategoryTypeKey, ContextUtils.getContextInfo());

    } catch (Exception e) {
      LOG.error("Exception occurred", e);
    }
    return null;
  }
  @Override
  public List<LoCategoryInfo> getLoCategories(String loRepositoryKey) {
    try {
      return loService.getLoCategoriesByLoRepository(
          loRepositoryKey, ContextUtils.getContextInfo());

    } catch (Exception e) {
      LOG.error("Exception occurred", e);
    }
    return null;
  }
 @Override
 public DataSaveResult createCopyCourseProposal(String originalProposalId, String documentType)
     throws Exception {
   try {
     return copyCourseService.createCopyCourseProposal(
         originalProposalId, documentType, ContextUtils.getContextInfo());
   } catch (Exception e) {
     LOG.error(String.format("Error copying proposal with id: %s", originalProposalId), e);
     throw e;
   }
 }
  protected static void copyCourseOfferingInfo(
      CourseOfferingCreateWrapper coCreateWrapper,
      String targetTermCode,
      String catalogCourseCode,
      String coId) {
    ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();

    if (targetTermCode != null) {
      coCreateWrapper.setTargetTermCode(targetTermCode);
      TermInfo term = CourseOfferingManagementUtil.getTerm(targetTermCode);
      coCreateWrapper.setTerm(term);
    }

    if (catalogCourseCode != null) {
      coCreateWrapper.setCatalogCourseCode(catalogCourseCode);
    }

    if (coId != null) {
      try {
        // configure context bar
        SocInfo soc =
            CourseOfferingSetUtil.getMainSocForTermId(
                coCreateWrapper.getTerm().getId(), contextInfo);
        coCreateWrapper.setSocInfo(soc);
        coCreateWrapper.setContextBar(
            CourseOfferingContextBar.NEW_INSTANCE(
                coCreateWrapper.getTerm(),
                coCreateWrapper.getSocInfo(),
                CourseOfferingManagementUtil.getStateService(),
                CourseOfferingManagementUtil.getAcademicCalendarService(),
                contextInfo));

        CourseOfferingInfo theCO =
            CourseOfferingManagementUtil.getCourseOfferingService()
                .getCourseOffering(coId, contextInfo);
        CourseOfferingEditWrapper coEditWrapper = new CourseOfferingEditWrapper(theCO);
        TermInfo termInfo =
            CourseOfferingManagementUtil.getAcademicCalendarService()
                .getTerm(theCO.getTermId(), contextInfo);
        coEditWrapper.setTerm(termInfo);
        coEditWrapper.setGradingOption(
            CourseOfferingManagementUtil.getGradingOption(theCO.getGradingOptionId()));
        // To prevent showing the same row twice in the table. It can be caused by pressing F5 key.
        if (coCreateWrapper.getExistingTermOfferings().size() == 0) {
          coCreateWrapper.getExistingTermOfferings().add(coEditWrapper);
        }
      } catch (Exception e) {
        throw new RuntimeException(
            "An Exception occurred while trying to copy course to new onw. ", e);
      }
    }
  }
  protected static List<String> getOptionKeys(
      CourseOfferingCreateWrapper createWrapper, CourseOfferingInfo existingCO) {

    List<String> optionKeys =
        getDefaultOptionKeysService().getDefaultOptionKeysForCopySingleCourseOffering();

    if (createWrapper.isExcludeInstructorInformation()) {
      optionKeys.add(CourseOfferingSetServiceConstants.NO_INSTRUCTORS_OPTION_KEY);
    }

    if (createWrapper.isExcludeSchedulingInformation()) {
      optionKeys.add(CourseOfferingSetServiceConstants.NO_SCHEDULE_OPTION_KEY);
    }

    if (createWrapper.isExcludeCancelledActivityOfferings()) {
      optionKeys.add(CourseOfferingSetServiceConstants.IGNORE_CANCELLED_AO_OPTION_KEY);
    }

    ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();

    try {
      // if source term differs from target term determine if add suffix or not
      if (StringUtils.equals(existingCO.getTermId(), createWrapper.getTerm().getId())) {
        optionKeys.add(CourseOfferingServiceConstants.APPEND_COURSE_OFFERING_IN_SUFFIX_OPTION_KEY);
      } else {
        QueryByCriteria.Builder qbcBuilder = QueryByCriteria.Builder.create();
        qbcBuilder.setPredicates(
            PredicateFactory.and(
                PredicateFactory.like(
                    "courseOfferingCode", existingCO.getCourseOfferingCode() + "%"),
                PredicateFactory.equalIgnoreCase("atpId", createWrapper.getTerm().getId())));
        QueryByCriteria criteria = qbcBuilder.build();
        List<String> courseOfferingIds =
            CourseOfferingManagementUtil.getCourseOfferingService()
                .searchForCourseOfferingIds(criteria, contextInfo);

        if (courseOfferingIds.size() > 0) {
          optionKeys.add(
              CourseOfferingServiceConstants.APPEND_COURSE_OFFERING_IN_SUFFIX_OPTION_KEY);
        }
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    //  According to Jira 4353 copy the title from CO instead of CLU. So set the property not to
    // copy from CLU
    optionKeys.add(CourseOfferingSetServiceConstants.NOT_COURSE_TITLE_OPTION_KEY);
    return optionKeys;
  }
  private String getCredentialId() throws Exception {

    List<String> credIds =
        cluService.getCluIdsByLuType(
            ProgramClientConstants.CREDENTIAL_BACCALAUREATE_PROGRAM,
            DtoConstants.STATE_ACTIVE,
            ContextUtils.getContextInfo());
    if (null == credIds || credIds.size() != 1) {
      throw new OperationFailedException(
          "A single credential program of type "
              + ProgramClientConstants.CREDENTIAL_BACCALAUREATE_PROGRAM
              + " is required; database contains "
              + (null == credIds ? "0" : credIds.size() + "."));
    }
    return credIds.get(0);
  }
  public CourseOfferingInfo testCRUDCourseOffering()
      throws DoesNotExistException, DataValidationErrorException, InvalidParameterException,
          MissingParameterException, OperationFailedException, PermissionDeniedException,
          ReadOnlyException, VersionMismatchException {
    // get course
    CourseInfo course;
    course = courseService.getCourse("COURSE1", ContextUtils.getContextInfo());
    // create co from course
    List<String> optionKeys = new ArrayList<String>();
    CourseOfferingInfo orig = new CourseOfferingInfo();
    orig.setCourseId(course.getId());
    orig.setTermId("testAtpId1");
    orig.setTypeKey(LuiServiceConstants.COURSE_OFFERING_TYPE_KEY);
    orig.setStateKey(LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY);
    orig.setCourseOfferingTitle("my name");
    orig.setWaitlistLevelTypeKey("waitlist key");
    orig.setHasWaitlist(true);
    orig.setFinalExamType(FinalExam.STANDARD.toString());
    orig.setIsEvaluated(true);
    orig.setIsFeeAtActivityOffering(false);
    orig.setFundingSource("funding source");
    orig.setCourseOfferingCode("CODE");
    orig.setCourseNumberSuffix("");
    orig.setCourseOfferingTitle("Title");
    orig.getStudentRegistrationGradingOptions()
        .add(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_AUDIT);
    orig.getStudentRegistrationGradingOptions()
        .add(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_PASSFAIL);
    orig.setGradingOptionId(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_LETTER);

    CourseOfferingInfo info =
        courseOfferingService.createCourseOffering(
            orig.getCourseId(), orig.getTermId(), orig.getTypeKey(), orig, optionKeys, callContext);
    assertNotNull(info);
    assertNotNull(info.getId());
    assertEquals(orig.getCourseId(), info.getCourseId());
    assertEquals(orig.getTermId(), info.getTermId());
    assertEquals(orig.getStateKey(), info.getStateKey());
    assertEquals(orig.getTypeKey(), info.getTypeKey());
    assertEquals(orig.getWaitlistLevelTypeKey(), info.getWaitlistLevelTypeKey());
    assertEquals(orig.getHasWaitlist(), info.getHasWaitlist());
    assertEquals(orig.getFinalExamType(), info.getFinalExamType());
    assertEquals(orig.getIsFeeAtActivityOffering(), info.getIsFeeAtActivityOffering());
    assertEquals(orig.getFundingSource(), info.getFundingSource());
    assertEquals(course.getCode() + info.getCourseNumberSuffix(), info.getCourseOfferingCode());
    assertEquals(orig.getCourseNumberSuffix(), info.getCourseNumberSuffix());
    assertEquals(course.getSubjectArea(), info.getSubjectArea());
    if (course.getDescr() != null) {
      assertEquals(course.getDescr().getPlain(), info.getDescr().getPlain());
      assertEquals(course.getDescr().getFormatted(), info.getDescr().getFormatted());
    }
    //        assertEquals(2,info.getStudentRegistrationOptionIds().size());
    //
    // assertTrue(info.getStudentRegistrationOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_AUDIT));
    //
    // assertTrue(info.getStudentRegistrationOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_PASSFAIL));
    //
    //        assertEquals(2,info.getGradingOptionIds().size());
    //
    // assertTrue(info.getGradingOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_LETTER));
    //
    // assertTrue(info.getGradingOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_PERCENTAGE));

    // TODO: test for these things
    //        assertEquals(course.getUnitsContentOwnerOrgIds(), info.getUnitsContentOwnerOrgIds());
    //        assertEquals(course.getUnitsDeploymentOrgIds(), info.getUnitsDeploymentOrgIds());
    //        assertEquals(course.getGradingOptions(), info.getGradingOptionIds());
    //        assertEquals(course.getCreditOptionIds(), info.getCreditOptionIds());

    // refetch co
    orig = info;
    info = courseOfferingService.getCourseOffering(orig.getId(), callContext);
    assertNotNull(info);
    assertEquals(orig.getId(), info.getId());
    assertEquals(orig.getCourseId(), info.getCourseId());
    assertEquals(orig.getTermId(), info.getTermId());
    assertEquals(orig.getStateKey(), info.getStateKey());
    assertEquals(orig.getTypeKey(), info.getTypeKey());

    // update co
    orig = info;
    orig.setIsHonorsOffering(true);
    orig.setMaximumEnrollment(40);
    orig.setMinimumEnrollment(10);
    List<OfferingInstructorInfo> instructors = new ArrayList<OfferingInstructorInfo>();
    //        OfferingInstructorInfo instructor = new OfferingInstructorInfo();
    //        instructor.setPersonId("Pers-1");
    //        instructor.setPercentageEffort(Float.valueOf("60"));
    //        instructor.setTypeKey(LprServiceConstants.INSTRUCTOR_MAIN_TYPE_KEY);
    //        instructor.setStateKey(LprServiceConstants.ASSIGNED_STATE_KEY);
    // TODO: add this back in and test for it
    //        instructors.add(instructor);
    orig.setInstructors(instructors);
    info = courseOfferingService.updateCourseOffering(orig.getId(), orig, callContext);
    assertNotNull(info);
    assertEquals(orig.getId(), info.getId());
    assertEquals(orig.getCourseId(), info.getCourseId());
    assertEquals(orig.getTermId(), info.getTermId());
    assertEquals(orig.getStateKey(), info.getStateKey());
    assertEquals(orig.getTypeKey(), info.getTypeKey());
    assertEquals(orig.getIsHonorsOffering(), info.getIsHonorsOffering());
    assertEquals(orig.getMaximumEnrollment(), info.getMaximumEnrollment());
    assertEquals(orig.getMinimumEnrollment(), info.getMinimumEnrollment());
    assertEquals(orig.getInstructors().size(), info.getInstructors().size());
    //        OfferingInstructorInfo origInst1 = orig.getInstructors().get(0);
    //        OfferingInstructorInfo infoInst1 = info.getInstructors().get(0);
    //        assertEquals(origInst1.getPersonId(), infoInst1.getPersonId());
    //        assertEquals(origInst1.getPercentageEffort(), infoInst1.getPercentageEffort());
    //        assertEquals(origInst1.getTypeKey(), infoInst1.getTypeKey());
    //        assertEquals(origInst1.getStateKey(), infoInst1.getStateKey());
    return info;
  }
  protected static void populateCreateCourseOfferingForm(
      MaintenanceDocumentForm form, HttpServletRequest request) {
    int firstValue = 0;

    try {
      ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();
      MaintenanceDocument document = form.getDocument();
      String termId = request.getParameter(CourseOfferingConstants.TARGET_TERM_ID);
      CourseInfo courseInfo =
          CourseOfferingManagementUtil.getCourseService()
              .getCourse(request.getParameter(CourseOfferingConstants.COURSE_ID), contextInfo);

      // 1. set CourseOfferingInfo - no saved Course Offering as of yet (see logic in
      // CourseOfferingEditMaintainableImpl.retrieveObjectForEditOrCopy
      CourseOfferingInfo coInfo =
          CourseOfferingManagementUtil.createCourseOfferingInfo(termId, courseInfo);
      // set the default value for hasWaitlist based on info defined in ks-enroll-config.xml through
      // CourseWaitListServiceFacade
      coInfo.setHasWaitlist(getCourseWaitListServiceFacade().getHasWaitlist());

      CourseOfferingEditWrapper formObject = new CourseOfferingEditWrapper(coInfo);
      formObject.setCreateCO(true);

      // 2. set CourseInfo
      formObject.setCourse(courseInfo);

      // 3. set formatOfferingList
      formObject.setFormatOfferingList(new ArrayList<FormatOfferingWrapper>());
      FormatOfferingWrapper defaultFO = new FormatOfferingWrapper();
      defaultFO.setFormatId(courseInfo.getFormats().get(firstValue).getId());
      defaultFO.getRenderHelper().setNewRow(true);
      defaultFO.setCourseOfferingWrapper(formObject);
      formObject.getFormatOfferingList().add(defaultFO);
      formObject.setFinalExamDriver(LuServiceConstants.LU_EXAM_DRIVER_AO_KEY);

      // 4. Checking if Grading Options should be disabled or not and assign default (if no value)
      // 5. Checking if there are any student registration options from CLU for screen display
      List<String> studentRegOptions = new ArrayList<String>();
      List<String> crsGradingOptions = new ArrayList<String>();
      if (courseInfo != null) {
        List<String> gradingOptions = courseInfo.getGradingOptions();
        Set<String> regOpts =
            new HashSet<String>(
                Arrays.asList(
                    CourseOfferingServiceConstants.ALL_STUDENT_REGISTRATION_OPTION_TYPE_KEYS));
        for (String gradingOption : gradingOptions) {
          if (regOpts.contains(gradingOption)) {
            studentRegOptions.add(gradingOption);
          } else {
            crsGradingOptions.add(gradingOption);
          }
        }
        // Audit is pulled out into a dynamic attribute on course so map it back
        if ("true"
            .equals(
                courseInfo.getAttributeValue(
                    CourseAssemblerConstants.COURSE_RESULT_COMP_ATTR_AUDIT))) {
          studentRegOptions.add(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_AUDIT);
        }
      }

      formObject.setStudentRegOptions(studentRegOptions);
      formObject.setCrsGradingOptions(crsGradingOptions);

      // 6. Defining Credit Option and if CLU is fixed (then it's disabled)
      boolean creditOptionFixed = false;
      CreditOptionInfo creditOption = new CreditOptionInfo();

      // Grab the Course's credit constraints
      // FindBugs: getCreditOptions() null check is in CourseInfo
      List<ResultValuesGroupInfo> courseCreditOptions = courseInfo.getCreditOptions();

      // Lookup the related course's credit constraints and set them on the creditOption
      if (!courseCreditOptions.isEmpty()) {
        ResultValuesGroupInfo resultValuesGroupInfo = courseCreditOptions.get(firstValue);
        // Check for fixed
        if (resultValuesGroupInfo
            .getTypeKey()
            .equalsIgnoreCase(LrcServiceConstants.RESULT_VALUES_GROUP_TYPE_KEY_FIXED)) {
          if (!resultValuesGroupInfo.getResultValueKeys().isEmpty()) {
            creditOption.setCourseFixedCredits(
                CourseOfferingManagementUtil.getLrcService()
                    .getResultValue(
                        resultValuesGroupInfo.getResultValueKeys().get(firstValue), contextInfo)
                    .getValue());
          }
          // Set the flag
          creditOptionFixed = true;

          // Default the value
          creditOption.setTypeKey(LrcServiceConstants.RESULT_VALUES_GROUP_TYPE_KEY_FIXED);
          creditOption.setFixedCredit(creditOption.getCourseFixedCredits());
          creditOption.getAllowedCredits().add(creditOption.getCourseFixedCredits());
        } else {
          // This is either range or multiple

          // Copy all the allowed credits and sort so that the multiple checkboxes can be properly
          // displayed
          List<ResultValueInfo> resultValueInfos =
              CourseOfferingManagementUtil.getLrcService()
                  .getResultValuesForResultValuesGroup(resultValuesGroupInfo.getKey(), contextInfo);
          for (ResultValueInfo rVI : resultValueInfos) {
            creditOption.getAllowedCredits().add(rVI.getValue());
          }
          Collections.sort(creditOption.getAllowedCredits());

          if (resultValuesGroupInfo
              .getTypeKey()
              .equalsIgnoreCase(LrcServiceConstants.RESULT_VALUES_GROUP_TYPE_KEY_RANGE)) {
            creditOption.setCourseMinCredits(
                resultValuesGroupInfo.getResultValueRange().getMinValue());
            creditOption.setCourseMaxCredits(
                resultValuesGroupInfo.getResultValueRange().getMaxValue());

            // Default the value
            creditOption.setTypeKey(LrcServiceConstants.RESULT_VALUES_GROUP_TYPE_KEY_RANGE);
            creditOption.setMinCredits(creditOption.getCourseMinCredits());
            creditOption.setMaxCredits(creditOption.getCourseMaxCredits());
          } else if (resultValuesGroupInfo
              .getTypeKey()
              .equalsIgnoreCase(LrcServiceConstants.RESULT_VALUES_GROUP_TYPE_KEY_MULTIPLE)) {
            // Default the value
            creditOption.setTypeKey(LrcServiceConstants.RESULT_VALUES_GROUP_TYPE_KEY_MULTIPLE);
            creditOption.getCredits().addAll(creditOption.getAllowedCredits());
          }
        }
      }

      formObject.setCreditOption(creditOption);
      formObject.setCreditOptionFixed(creditOptionFixed);

      formObject.setOrganizationNames(new ArrayList<OrganizationInfoWrapper>());

      ArrayList<OrganizationInfoWrapper> orgList = new ArrayList<OrganizationInfoWrapper>();

      if (courseInfo.getUnitsContentOwner() != null
          && !courseInfo.getUnitsContentOwner().isEmpty()) {
        for (String orgId : courseInfo.getUnitsContentOwner()) {
          OrgInfo orgInfo =
              CourseOfferingManagementUtil.getOrganizationService().getOrg(orgId, contextInfo);
          orgList.add(new OrganizationInfoWrapper(orgInfo));
        }
      }
      formObject.setOrganizationNames(orgList);

      // retrieve exam period id for the term that the CO is attached to
      try {
        String examPeriodId =
            CourseOfferingManagementUtil.getExamOfferingServiceFacade()
                .getExamPeriodId(
                    formObject.getCourseOfferingInfo().getTermId(),
                    ContextUtils.createDefaultContextInfo());
        if (!StringUtils.isEmpty(examPeriodId)) {
          formObject.setExamPeriodId(examPeriodId);
        }
      } catch (DoesNotExistException e) {
        LOG.warn(
            "The Term {} that the course offering {} is attached to doesn't have an exam period to create exam offerings.",
            formObject.getCourseOfferingInfo().getTermId(),
            formObject.getCourseOfferingCode());
      } catch (Exception e) {
        throw new RuntimeException(e);
      }

      formObject.setUseFinalExamMatrixSystemDefault(
          CourseOfferingManagementUtil.getExamOfferingServiceFacade().isUseFinalExamMatrix());
      formObject.setUseFinalExamMatrix(
          CourseOfferingManagementUtil.getExamOfferingServiceFacade().isUseFinalExamMatrix());

      // adding SOC
      SocInfo socInfo =
          CourseOfferingManagementUtil.getCourseOfferingSetService()
              .getSoc(request.getParameter(CourseOfferingConstants.SOC_ID), contextInfo);
      formObject.setSocInfo(socInfo);

      setTermPropertiesOnFormObject(formObject, termId, contextInfo);
      formObject.setContextBar(
          CourseOfferingContextBar.NEW_INSTANCE(
              formObject.getTerm(),
              formObject.getSocInfo(),
              CourseOfferingManagementUtil.getStateService(),
              CourseOfferingManagementUtil.getAcademicCalendarService(),
              contextInfo));

      document.getNewMaintainableObject().setDataObject(formObject);
      document.getOldMaintainableObject().setDataObject(formObject);
      document.getDocumentHeader().setDocumentDescription("Create CO - " + courseInfo.getCode());

    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  protected static void continueFromCreateCopyCourseOfferingInfo(
      CourseOfferingCreateWrapper coWrapper, CourseInfo course, TermInfo term) {

    ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();
    int firstValue = 0;

    try {
      List<CourseOfferingInfo> courseOfferingInfos =
          CourseOfferingManagementUtil.getCourseOfferingService()
              .getCourseOfferingsByCourseAndTerm(course.getId(), term.getId(), contextInfo);

      coWrapper.setCourse(course);
      coWrapper.setCreditCount(
          CourseOfferingViewHelperUtil.trimTrailing0(
              CourseOfferingManagementUtil.getLrcService()
                  .getResultValue(
                      course
                          .getCreditOptions()
                          .get(firstValue)
                          .getResultValueKeys()
                          .get(firstValue),
                      contextInfo)
                  .getValue()));
      coWrapper.setShowAllSections(true);
      coWrapper.setShowCopyCourseOffering(false);
      coWrapper.setShowTermOfferingLink(true);

      coWrapper.setContextBar(
          CourseOfferingContextBar.NEW_INSTANCE(
              coWrapper.getTerm(),
              coWrapper.getSocInfo(),
              CourseOfferingManagementUtil.getStateService(),
              CourseOfferingManagementUtil.getAcademicCalendarService(),
              contextInfo));

      coWrapper.getExistingTermOfferings().clear();
      coWrapper.getExistingOfferingsInCurrentTerm().clear();

      for (CourseOfferingInfo courseOfferingInfo : courseOfferingInfos) {
        if (StringUtils.equals(
            courseOfferingInfo.getStateKey(), LuiServiceConstants.LUI_CO_STATE_OFFERED_KEY)) {
          CourseOfferingEditWrapper co = new CourseOfferingEditWrapper(courseOfferingInfo);
          co.setGradingOption(
              CourseOfferingManagementUtil.getGradingOption(
                  courseOfferingInfo.getGradingOptionId()));
          coWrapper.getExistingOfferingsInCurrentTerm().add(co);
        }
      }

      // Get past 5 years CO
      Calendar termStart = Calendar.getInstance();
      termStart.setTime(term.getStartDate());
      String termYear = Integer.toString(termStart.get(Calendar.YEAR));
      String termMonth = Integer.toString((termStart.get(Calendar.MONTH) + 1));
      String termDayOfMonth = Integer.toString((termStart.getActualMaximum(Calendar.DAY_OF_MONTH)));

      org.kuali.student.r2.core.search.dto.SearchRequestInfo searchRequest =
          new org.kuali.student.r2.core.search.dto.SearchRequestInfo(
              CourseOfferingHistorySearchImpl.PAST_CO_SEARCH.getKey());
      searchRequest.addParam(
          CourseOfferingHistorySearchImpl.COURSE_ID, coWrapper.getCourse().getId());

      searchRequest.addParam(
          CourseOfferingHistorySearchImpl.TARGET_DAY_OF_MONTH_PARAM, termDayOfMonth);
      searchRequest.addParam(CourseOfferingHistorySearchImpl.TARGET_MONTH_PARAM, termMonth);
      searchRequest.addParam(CourseOfferingHistorySearchImpl.TARGET_YEAR_PARAM, termYear);
      searchRequest.addParam(
          CourseOfferingHistorySearchImpl.SearchParameters.CROSS_LIST_SEARCH_ENABLED,
          BooleanUtils.toStringTrueFalse(true));
      org.kuali.student.r2.core.search.dto.SearchResultInfo searchResult =
          CourseOfferingManagementUtil.getSearchService().search(searchRequest, null);

      List<String> courseOfferingIds = new ArrayList<String>(searchResult.getTotalResults());

      /* Checks whether the course is cross-listed and Set the codes that are cross listed to the cross-listed list */

      for (org.kuali.student.r2.core.search.dto.SearchResultRowInfo row : searchResult.getRows()) {
        for (SearchResultCellInfo cellInfo : row.getCells()) {
          String value = StringUtils.EMPTY;
          if (cellInfo.getValue() != null) {
            value = cellInfo.getValue();
          }
          if (CourseOfferingHistorySearchImpl.SearchResultColumns.CO_ID.equals(cellInfo.getKey())) {
            courseOfferingIds.add(value);
          } else if (CourseOfferingHistorySearchImpl.SearchResultColumns.IS_CROSS_LISTED.equals(
              cellInfo.getValue())) {
            coWrapper.setCrossListedCo(BooleanUtils.toBoolean(value));
          } else if (CourseOfferingHistorySearchImpl.SearchResultColumns.CROSS_LISTED_COURSES
              .equals(cellInfo.getKey())) {
            coWrapper.setAlternateCOCodes(Arrays.asList(StringUtils.split(value, ",")));
          }
        }
      }

      /*
       * Avoid duplicates in case there is a cross Listed
       */
      HashSet hs = new HashSet();
      hs.addAll(courseOfferingIds);
      courseOfferingIds.clear();
      courseOfferingIds.addAll(hs);

      courseOfferingInfos =
          CourseOfferingManagementUtil.getCourseOfferingService()
              .getCourseOfferingsByIds(courseOfferingIds, contextInfo);

      for (CourseOfferingInfo courseOfferingInfo : courseOfferingInfos) {
        CourseOfferingEditWrapper co = new CourseOfferingEditWrapper(courseOfferingInfo);
        TermInfo termInfo =
            CourseOfferingManagementUtil.getAcademicCalendarService()
                .getTerm(courseOfferingInfo.getTermId(), contextInfo);
        co.setTerm(termInfo);
        co.setGradingOption(
            CourseOfferingManagementUtil.getGradingOption(courseOfferingInfo.getGradingOptionId()));
        co.setAlternateCOCodes(coWrapper.getAlternateCOCodes());
        coWrapper.getExistingTermOfferings().add(co);
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  @Override
  protected Object save(Object dto, Map<String, Object> properties, ContextInfo contextInfo)
      throws Exception {
    if (dto instanceof MajorDisciplineInfo) {
      MajorDisciplineInfo mdInfo = (MajorDisciplineInfo) dto;
      if (mdInfo.getId() == null && mdInfo.getVersion() != null) {

        String majorVersionIndId = mdInfo.getVersion().getVersionIndId();

        // Get the current Major Dicipline from the service
        VersionDisplayInfo mdVersionInfo =
            programService.getCurrentVersion(
                ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI,
                majorVersionIndId,
                ContextUtils.getContextInfo());
        mdInfo =
            programService.getMajorDiscipline(mdVersionInfo.getId(), ContextUtils.getContextInfo());

        // set the prev start term to be the most recent of the major and all variations
        AtpInfo latestStartAtp = atpService.getAtp(mdInfo.getStartTerm(), contextInfo);
        for (ProgramVariationInfo variation : mdInfo.getVariations()) {
          AtpInfo variationAtp = atpService.getAtp(variation.getStartTerm(), contextInfo);
          if (variationAtp != null
              && variationAtp.getStartDate() != null
              && variationAtp.getStartDate().compareTo(latestStartAtp.getStartDate()) > 0) {
            latestStartAtp = variationAtp;
          }
        }

        // Save the start and end terms from the old version and put into filter properties
        String startTerm = latestStartAtp.getId();
        String endTerm = mdInfo.getEndTerm();
        String endProgramEntryTerm = mdInfo.getEndProgramEntryTerm();
        String endInstAdmitTerm =
            mdInfo.getAttributeValue(ProgramConstants.END_INSTITUTIONAL_ADMIT_TERM);

        //
        Map<String, String> proposalAttributes = new HashMap<String, String>();
        if (startTerm != null) proposalAttributes.put("prevStartTerm", startTerm);
        if (endTerm != null) proposalAttributes.put("prevEndTerm", endTerm);
        if (endProgramEntryTerm != null)
          proposalAttributes.put("prevEndProgramEntryTerm", endProgramEntryTerm);
        if (endInstAdmitTerm != null)
          proposalAttributes.put("prevEndInstAdmitTerm", endInstAdmitTerm);
        properties.put(ProposalWorkflowFilter.PROPOSAL_ATTRIBUTES, proposalAttributes);

        mdInfo =
            programService.createNewMajorDisciplineVersion(
                majorVersionIndId, "New major discipline version", ContextUtils.getContextInfo());
      } else if (mdInfo.getId() == null) {
        mdInfo =
            programService.createMajorDiscipline(
                mdInfo.getId(), mdInfo, ContextUtils.getContextInfo());
      } else {
        mdInfo = programService.updateMajorDiscipline(null, mdInfo, ContextUtils.getContextInfo());
      }
      return mdInfo;
    } else {
      throw new InvalidParameterException(
          "Only persistence of MajorDiscipline is supported by this DataService implementation.");
    }
  }
 @Override
 protected List<ValidationResultInfo> validate(Object dto, ContextInfo contextInfo)
     throws Exception {
   return programService.validateMajorDiscipline(
       "OBJECT", (MajorDisciplineInfo) dto, ContextUtils.getContextInfo());
 }