private RuleResult createRuleResultForMaxCreditsExceededInExternalCycle(
     IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
     final CreditsLimitInExternalCycle creditsLimitInExternalCycle,
     final Double totalCreditsInExternalCycle,
     final Double totalCreditsInPreviousCycle) {
   if (sourceDegreeModuleToEvaluate.isEnroled() && sourceDegreeModuleToEvaluate.isLeaf()) {
     return RuleResult.createImpossible(
         sourceDegreeModuleToEvaluate.getDegreeModule(),
         "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.external.cycle.limit.exceeded",
         creditsLimitInExternalCycle.getExternalCurriculumGroup().getName().getContent(),
         totalCreditsInExternalCycle.toString(),
         creditsLimitInExternalCycle
             .getMaxCreditsInExternalCycle(totalCreditsInPreviousCycle)
             .toString(),
         totalCreditsInPreviousCycle.toString());
   }
   return RuleResult.createFalse(
       sourceDegreeModuleToEvaluate.getDegreeModule(),
       "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.external.cycle.limit.exceeded",
       creditsLimitInExternalCycle.getExternalCurriculumGroup().getName().getContent(),
       totalCreditsInExternalCycle.toString(),
       creditsLimitInExternalCycle
           .getMaxCreditsInExternalCycle(totalCreditsInPreviousCycle)
           .toString(),
       totalCreditsInPreviousCycle.toString());
 }
  @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());
  }
  private RuleResult createRuleResultForEnrolingDissertation(
      final IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
      final CreditsLimitInExternalCycle creditsLimitInExternalCycle) {

    if (sourceDegreeModuleToEvaluate.isEnroled() && sourceDegreeModuleToEvaluate.isLeaf()) {
      return RuleResult.createImpossible(
          sourceDegreeModuleToEvaluate.getDegreeModule(),
          "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.enroling.dissertation");
    }
    return RuleResult.createFalse(
        sourceDegreeModuleToEvaluate.getDegreeModule(),
        "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.enroling.dissertation");
  }
  private boolean isEnrolingDissertation(
      final EnrolmentContext enrolmentContext,
      final ExternalCurriculumGroup externalCurriculumGroup) {

    for (final IDegreeModuleToEvaluate degreeModuleToEvaluate :
        enrolmentContext.getDegreeModulesToEvaluate()) {
      if (degreeModuleToEvaluate.isDissertation()
          && externalCurriculumGroup.hasCurriculumModule(
              degreeModuleToEvaluate.getCurriculumGroup())
          && isEnrolingInSemester(enrolmentContext, degreeModuleToEvaluate)) {
        return true;
      }
    }
    return false;
  }
 @Override
 protected RuleResult executeEnrolmentInEnrolmentEvaluation(
     final ICurricularRule curricularRule,
     final IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
     final EnrolmentContext enrolmentContext) {
   return RuleResult.createNA(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);
  }
  private Double calculateApprovedAndEnrollingTotalCredits(
      final EnrolmentContext enrolmentContext,
      final ExternalCurriculumGroup externalCurriculumGroup) {
    double result = 0;
    final ExecutionSemester executionSemester = enrolmentContext.getExecutionPeriod();
    for (final IDegreeModuleToEvaluate degreeModuleToEvaluate :
        enrolmentContext.getDegreeModulesToEvaluate()) {
      if (degreeModuleToEvaluate.isLeaf()
          && externalCurriculumGroup.hasCurriculumModule(
              degreeModuleToEvaluate.getCurriculumGroup())) {
        result += degreeModuleToEvaluate.getEctsCredits(executionSemester);
      }
    }

    result += externalCurriculumGroup.getAprovedEctsCredits();

    return result;
  }
  private boolean isToApply(
      IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
      final EnrolmentContext enrolmentContext,
      final ExternalCurriculumGroup externalCurriculumGroup) {
    if (!sourceDegreeModuleToEvaluate.isLeaf()) {
      return false;
    }

    for (final IDegreeModuleToEvaluate degreeModuleToEvaluate :
        enrolmentContext.getDegreeModulesToEvaluate()) {
      if (externalCurriculumGroup.hasCurriculumModule(degreeModuleToEvaluate.getCurriculumGroup())
          && (isEnrolingInSemester(enrolmentContext, degreeModuleToEvaluate))) {
        return true;
      }
    }

    return false;
  }
 private RuleResult createImpossibleRuleResult(
     final RestrictionDoneDegreeModule rule,
     final IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate) {
   return RuleResult.createImpossible(
       sourceDegreeModuleToEvaluate.getDegreeModule(),
       "curricularRules.ruleExecutors.RestrictionDoneDegreeModuleExecutor.student.is.not.approved.to.precendenceDegreeModule",
       rule.getDegreeModuleToApplyRule().getName(),
       rule.getPrecedenceDegreeModule().getName());
 }
  @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());
  }
  private RuleResult createRuleResultForNotSatisfiedCreditsForPreviousCycle(
      IDegreeModuleToEvaluate sourceDegreeModuleToEvaluate,
      final CreditsLimitInExternalCycle creditsLimitInExternalCycle,
      final CycleCurriculumGroup previousCycleCurriclumGroup) {
    if (sourceDegreeModuleToEvaluate.isEnroled() && sourceDegreeModuleToEvaluate.isLeaf()) {
      return RuleResult.createImpossible(
          sourceDegreeModuleToEvaluate.getDegreeModule(),
          "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.previous.cycle.minimum.credits.not.fulfilled",
          creditsLimitInExternalCycle.getExternalCurriculumGroup().getName().getContent(),
          creditsLimitInExternalCycle.getMinCreditsInPreviousCycle().toString(),
          previousCycleCurriclumGroup.getName().getContent());
    }

    return RuleResult.createFalse(
        sourceDegreeModuleToEvaluate.getDegreeModule(),
        "curricularRules.ruleExecutors.CreditsLimitInExternalCycleExecutor.previous.cycle.minimum.credits.not.fulfilled",
        creditsLimitInExternalCycle.getExternalCurriculumGroup().getName().getContent(),
        creditsLimitInExternalCycle.getMinCreditsInPreviousCycle().toString(),
        previousCycleCurriclumGroup.getName().getContent());
  }
  private boolean isEnroledIn(
      IDegreeModuleToEvaluate degreeModuleToEvaluate, ExecutionSemester executionSemester) {
    if (degreeModuleToEvaluate.isLeaf()) {
      final EnroledCurriculumModuleWrapper curriculumModuleEnroledWrapper =
          (EnroledCurriculumModuleWrapper) degreeModuleToEvaluate;
      final CurriculumLine curriculumLine =
          (CurriculumLine) (curriculumModuleEnroledWrapper).getCurriculumModule();

      if (curriculumLine.isEnrolment()) {
        return curriculumLine.getExecutionPeriod() == executionSemester;
      }

      return false;
    }

    return false;
  }
 private boolean isEnrolingInSemester(
     final EnrolmentContext enrolmentContext,
     final IDegreeModuleToEvaluate degreeModuleToEvaluate) {
   return degreeModuleToEvaluate.isEnroling()
       || isEnroledIn(degreeModuleToEvaluate, enrolmentContext.getExecutionPeriod());
 }