@Override
  protected RuleResult executeEnrolmentWithRulesAndTemporaryEnrolment(
      ICurricularRule curricularRule,
      IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
      EnrolmentContext enrolmentContext) {
    final CreditsLimitInExternalCycle creditsLimitInExternalCycle =
        (CreditsLimitInExternalCycle) curricularRule;
    final ExternalCurriculumGroup externalCurriculumGroup =
        creditsLimitInExternalCycle.getExternalCurriculumGroup();

    if (!isToApply(sourceDegreeModuleToEvaluate, enrolmentContext, externalCurriculumGroup)) {
      return RuleResult.createNA(sourceDegreeModuleToEvaluate.getDegreeModule());
    }

    if (isEnrolingDissertation(enrolmentContext, externalCurriculumGroup)) {
      return createRuleResultForEnrolingDissertation(
          sourceDegreeModuleToEvaluate, creditsLimitInExternalCycle);
    }

    final CycleCurriculumGroup previousCycleCurriclumGroup =
        creditsLimitInExternalCycle.getPreviousCycleCurriculumGroup();
    final Double totalCreditsInPreviousCycle = previousCycleCurriclumGroup.getAprovedEctsCredits();

    if (!creditsLimitInExternalCycle.creditsInPreviousCycleSufficient(
        totalCreditsInPreviousCycle)) {
      return createRuleResultForNotSatisfiedCreditsForPreviousCycle(
          sourceDegreeModuleToEvaluate, creditsLimitInExternalCycle, previousCycleCurriclumGroup);
    }

    final Double totalCredits =
        calculateApprovedAndEnrollingTotalCredits(enrolmentContext, externalCurriculumGroup);
    if (creditsLimitInExternalCycle.creditsExceedMaximumInExternalCycle(
        totalCredits, totalCreditsInPreviousCycle)) {
      return createRuleResultForMaxCreditsExceededInExternalCycle(
          sourceDegreeModuleToEvaluate,
          creditsLimitInExternalCycle,
          totalCredits,
          totalCreditsInPreviousCycle);
    }

    final Double totalEctsWithEnroledEctsCreditsFromPreviousPeriod =
        totalCredits
            + externalCurriculumGroup.getEnroledEctsCredits(
                enrolmentContext.getExecutionPeriod().getPreviousExecutionPeriod());
    if (creditsLimitInExternalCycle.creditsExceedMaximumInExternalCycle(
        totalEctsWithEnroledEctsCreditsFromPreviousPeriod, totalCreditsInPreviousCycle)) {
      return RuleResult.createTrue(
          EnrolmentResultType.TEMPORARY,
          sourceDegreeModuleToEvaluate.getDegreeModule(),
          "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.external.cycle.limit.exceeded",
          creditsLimitInExternalCycle.getExternalCurriculumGroup().getName().getContent(),
          totalEctsWithEnroledEctsCreditsFromPreviousPeriod.toString(),
          creditsLimitInExternalCycle
              .getMaxCreditsInExternalCycle(totalCreditsInPreviousCycle)
              .toString(),
          totalCreditsInPreviousCycle.toString());
    }

    return RuleResult.createTrue(sourceDegreeModuleToEvaluate.getDegreeModule());
  }
  @Override
  protected RuleResult executeEnrolmentWithRulesAndTemporaryEnrolment(
      final ICurricularRule curricularRule,
      final IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
      final EnrolmentContext enrolmentContext) {

    final RestrictionDoneDegreeModule rule = (RestrictionDoneDegreeModule) curricularRule;
    final ExecutionSemester executionSemester = enrolmentContext.getExecutionPeriod();

    if (!canApplyRule(enrolmentContext, rule)) {
      return RuleResult.createNA(sourceDegreeModuleToEvaluate.getDegreeModule());
    }

    final CurricularCourse curricularCourse = rule.getPrecedenceDegreeModule();

    if (isEnrolling(enrolmentContext, curricularCourse)
        || isEnroled(enrolmentContext, curricularCourse, executionSemester)) {
      return RuleResult.createFalse(
          sourceDegreeModuleToEvaluate.getDegreeModule(),
          "curricularRules.ruleExecutors.RestrictionDoneDegreeModuleExecutor.cannot.enrol.simultaneously.to.degreeModule.and.precedenceDegreeModule",
          rule.getDegreeModuleToApplyRule().getName(),
          rule.getPrecedenceDegreeModule().getName());
    }

    if (isApproved(enrolmentContext, curricularCourse)) {
      return RuleResult.createTrue(sourceDegreeModuleToEvaluate.getDegreeModule());
    }

    if (hasEnrolmentWithEnroledState(
        enrolmentContext, curricularCourse, executionSemester.getPreviousExecutionPeriod())) {
      return RuleResult.createTrue(
          EnrolmentResultType.TEMPORARY, sourceDegreeModuleToEvaluate.getDegreeModule());
    }

    /*
     * CurricularCourse is not approved and is not enroled in previous
     * semester If DegreeModule is Enroled in current semester then
     * Enrolment must be impossible
     */
    if (isEnroled(enrolmentContext, rule.getDegreeModuleToApplyRule(), executionSemester)) {
      return createImpossibleRuleResult(rule, sourceDegreeModuleToEvaluate);
    }

    return createFalseRuleResult(rule, sourceDegreeModuleToEvaluate);
  }
  @Override
  protected RuleResult executeEnrolmentVerificationWithRules(
      ICurricularRule curricularRule,
      IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
      EnrolmentContext enrolmentContext) {

    final CreditsLimitInExternalCycle creditsLimitInExternalCycle =
        (CreditsLimitInExternalCycle) curricularRule;
    final ExternalCurriculumGroup externalCurriculumGroup =
        creditsLimitInExternalCycle.getExternalCurriculumGroup();

    if (!isToApply(sourceDegreeModuleToEvaluate, enrolmentContext, externalCurriculumGroup)) {
      return RuleResult.createNA(sourceDegreeModuleToEvaluate.getDegreeModule());
    }

    if (isEnrolingDissertation(enrolmentContext, externalCurriculumGroup)) {
      return createRuleResultForEnrolingDissertation(
          sourceDegreeModuleToEvaluate, creditsLimitInExternalCycle);
    }

    final CycleCurriculumGroup previousCycleCurriclumGroup =
        creditsLimitInExternalCycle.getPreviousCycleCurriculumGroup();
    final Double totalCreditsInPreviousCycle = previousCycleCurriclumGroup.getAprovedEctsCredits();

    if (!creditsLimitInExternalCycle.creditsInPreviousCycleSufficient(
        totalCreditsInPreviousCycle)) {
      return createRuleResultForNotSatisfiedCreditsForPreviousCycle(
          sourceDegreeModuleToEvaluate, creditsLimitInExternalCycle, previousCycleCurriclumGroup);
    }

    final Double totalCreditsInExternalCycle =
        calculateApprovedAndEnrollingTotalCredits(enrolmentContext, externalCurriculumGroup);
    if (creditsLimitInExternalCycle.creditsExceedMaximumInExternalCycle(
        totalCreditsInExternalCycle, totalCreditsInPreviousCycle)) {
      return createRuleResultForMaxCreditsExceededInExternalCycle(
          sourceDegreeModuleToEvaluate,
          creditsLimitInExternalCycle,
          totalCreditsInExternalCycle,
          totalCreditsInPreviousCycle);
    }

    return RuleResult.createTrue(sourceDegreeModuleToEvaluate.getDegreeModule());
  }