private void initializeExamList(
      LocalSearchSolverScope localSearchSolverScope, Examination examination) {
    List<Period> periodList = examination.getPeriodList();
    List<Room> roomList = examination.getRoomList();
    List<Exam> examList =
        new ArrayList<Exam>(
            examination
                .getTopicList()
                .size()); // TODO this can be returned from createExamAssigningScoreList
    WorkingMemory workingMemory = localSearchSolverScope.getWorkingMemory();

    List<ExamInitializationWeight> examInitialWeightList =
        createExamAssigningScoreList(examination);

    for (ExamInitializationWeight examInitialWeight : examInitialWeightList) {
      Score unscheduledScore = localSearchSolverScope.calculateScoreFromWorkingMemory();
      Exam leader = examInitialWeight.getExam();
      FactHandle leaderHandle = null;

      List<ExamToHandle> examToHandleList = new ArrayList<ExamToHandle>(5);
      if (leader.getExamCoincidence() == null) {
        examToHandleList.add(new ExamToHandle(leader));
      } else {
        for (Exam coincidenceExam : leader.getExamCoincidence().getCoincidenceExamSet()) {
          examToHandleList.add(new ExamToHandle(coincidenceExam));
        }
      }

      List<PeriodScoring> periodScoringList = new ArrayList<PeriodScoring>(periodList.size());
      for (Period period : periodList) {
        for (ExamToHandle examToHandle : examToHandleList) {
          if (examToHandle.getExamHandle() == null) {
            examToHandle.getExam().setPeriod(period);
            examToHandle.setExamHandle(workingMemory.insert(examToHandle.getExam()));
            if (examToHandle.getExam().isCoincidenceLeader()) {
              leaderHandle = examToHandle.getExamHandle();
            }
          } else {
            examToHandle.getExam().setPeriod(period);
            workingMemory.update(examToHandle.getExamHandle(), examToHandle.getExam());
          }
        }
        Score score = localSearchSolverScope.calculateScoreFromWorkingMemory();
        periodScoringList.add(new PeriodScoring(period, score));
      }
      Collections.sort(periodScoringList);

      scheduleLeader(
          periodScoringList,
          roomList,
          localSearchSolverScope,
          workingMemory,
          unscheduledScore,
          examToHandleList,
          leader,
          leaderHandle);
      examList.add(leader);

      // Schedule the non leaders
      for (ExamToHandle examToHandle : examToHandleList) {
        Exam exam = examToHandle.getExam();
        // Leader already has a room
        if (!exam.isCoincidenceLeader()) {
          scheduleNonLeader(
              roomList, localSearchSolverScope, workingMemory, exam, examToHandle.getExamHandle());
          examList.add(exam);
        }
      }
    }
    Collections.sort(examList, new PersistableIdComparator());
    examination.setExamList(examList);
  }
 private void scheduleLeader(
     List<PeriodScoring> periodScoringList,
     List<Room> roomList,
     LocalSearchSolverScope localSearchSolverScope,
     WorkingMemory workingMemory,
     Score unscheduledScore,
     List<ExamToHandle> examToHandleList,
     Exam leader,
     FactHandle leaderHandle) {
   boolean perfectMatch = false;
   Score bestScore = DefaultHardAndSoftScore.valueOf(Integer.MIN_VALUE, Integer.MIN_VALUE);
   Period bestPeriod = null;
   Room bestRoom = null;
   for (PeriodScoring periodScoring : periodScoringList) {
     if (bestScore.compareTo(periodScoring.getScore()) >= 0) {
       // No need to check the rest
       break;
     }
     for (ExamToHandle examToHandle : examToHandleList) {
       examToHandle.getExam().setPeriod(periodScoring.getPeriod());
       workingMemory.update(examToHandle.getExamHandle(), examToHandle.getExam());
     }
     for (Room room : roomList) {
       leader.setRoom(room);
       workingMemory.update(leaderHandle, leader);
       Score score = localSearchSolverScope.calculateScoreFromWorkingMemory();
       if (score.compareTo(unscheduledScore) < 0) {
         if (score.compareTo(bestScore) > 0) {
           bestScore = score;
           bestPeriod = periodScoring.getPeriod();
           bestRoom = room;
         }
       } else if (score.equals(unscheduledScore)) {
         perfectMatch = true;
         break;
       } else {
         throw new IllegalStateException(
             "The score ("
                 + score
                 + ") cannot be higher than unscheduledScore ("
                 + unscheduledScore
                 + ").");
       }
     }
     if (perfectMatch) {
       break;
     }
   }
   if (!perfectMatch) {
     if (bestPeriod == null || bestRoom == null) {
       throw new IllegalStateException(
           "The bestPeriod ("
               + bestPeriod
               + ") or the bestRoom ("
               + bestRoom
               + ") cannot be null.");
     }
     leader.setRoom(bestRoom);
     workingMemory.update(leaderHandle, leader);
     for (ExamToHandle examToHandle : examToHandleList) {
       examToHandle.getExam().setPeriod(bestPeriod);
       workingMemory.update(examToHandle.getExamHandle(), examToHandle.getExam());
     }
   }
   logger.debug("    Exam ({}) initialized for starting solution.", leader);
 }