@Override
 public void updatePanel(Solution solution) {
   NurseRoster nurseRoster = (NurseRoster) solution;
   List<ShiftDate> shiftDateList = nurseRoster.getShiftDateList();
   List<Shift> shiftList = nurseRoster.getShiftList();
   Set<Employee> deadEmployeeSet = new LinkedHashSet<Employee>(employeeToPanelMap.keySet());
   deadEmployeeSet.remove(null);
   for (Employee employee : nurseRoster.getEmployeeList()) {
     deadEmployeeSet.remove(employee);
     EmployeePanel employeePanel = employeeToPanelMap.get(employee);
     if (employeePanel == null) {
       employeePanel = new EmployeePanel(this, shiftDateList, shiftList, employee);
       employeeListPanel.add(employeePanel);
       employeeToPanelMap.put(employee, employeePanel);
     }
     employeePanel.clearShiftAssignments();
   }
   unassignedPanel.clearShiftAssignments();
   for (ShiftAssignment shiftAssignment : nurseRoster.getShiftAssignmentList()) {
     Employee employee = shiftAssignment.getEmployee();
     EmployeePanel employeePanel = employeeToPanelMap.get(employee);
     employeePanel.addShiftAssignment(shiftAssignment);
   }
   for (Employee deadEmployee : deadEmployeeSet) {
     EmployeePanel deadEmployeePanel = employeeToPanelMap.remove(deadEmployee);
     employeeListPanel.remove(deadEmployeePanel);
   }
   for (EmployeePanel employeePanel : employeeToPanelMap.values()) {
     employeePanel.update();
   }
 }
 @Override
 public void updatePanel(Solution solution) {
   NurseRoster nurseRoster = (NurseRoster) solution;
   List<ShiftDate> shiftDateList = nurseRoster.getShiftDateList();
   List<Shift> shiftList = nurseRoster.getShiftList();
   Set<Employee> deadEmployeeSet = new LinkedHashSet<Employee>(employeeToPanelMap.keySet());
   deadEmployeeSet.remove(null);
   for (Employee employee : nurseRoster.getEmployeeList()) {
     deadEmployeeSet.remove(employee);
     EmployeePanel employeePanel = employeeToPanelMap.get(employee);
     if (employeePanel == null) {
       employeePanel = new EmployeePanel(this, shiftDateList, shiftList, employee);
       employeeListPanel.add(employeePanel);
       employeeToPanelMap.put(employee, employeePanel);
     }
   }
   Set<ShiftAssignment> deadShiftAssignmentSet =
       new LinkedHashSet<ShiftAssignment>(shiftAssignmentToPanelMap.keySet());
   for (ShiftAssignment shiftAssignment : nurseRoster.getShiftAssignmentList()) {
     deadShiftAssignmentSet.remove(shiftAssignment);
     EmployeePanel employeePanel = shiftAssignmentToPanelMap.get(shiftAssignment);
     Employee employee = shiftAssignment.getEmployee();
     if (employeePanel != null && !ObjectUtils.equals(employeePanel.getEmployee(), employee)) {
       shiftAssignmentToPanelMap.remove(shiftAssignment);
       employeePanel.removeShiftAssignment(shiftAssignment);
       employeePanel = null;
     }
     if (employeePanel == null) {
       employeePanel = employeeToPanelMap.get(employee);
       employeePanel.addShiftAssignment(shiftAssignment);
       shiftAssignmentToPanelMap.put(shiftAssignment, employeePanel);
     }
   }
   for (ShiftAssignment deadShiftAssignment : deadShiftAssignmentSet) {
     EmployeePanel deadEmployeePanel = shiftAssignmentToPanelMap.remove(deadShiftAssignment);
     deadEmployeePanel.removeShiftAssignment(deadShiftAssignment);
   }
   for (Employee deadEmployee : deadEmployeeSet) {
     EmployeePanel deadEmployeePanel = employeeToPanelMap.remove(deadEmployee);
     employeeListPanel.remove(deadEmployeePanel);
   }
   for (EmployeePanel employeePanel : employeeToPanelMap.values()) {
     employeePanel.update();
   }
 }
 private void add(ShiftAssignment shiftAssignment) {
   shiftAssignmentList.add(shiftAssignment);
   int dayIndex = shiftAssignment.getShiftDateDayIndex();
   if (dayIndex < lastDayIndex) {
     throw new IllegalStateException(
         "The shiftAssignmentList is expected to be sorted by shiftDate.");
   }
   lastDayIndex = dayIndex;
 }
  public List<Move> createMoveList(NurseRoster nurseRoster) {
    List<Employee> employeeList = nurseRoster.getEmployeeList();
    // This code assumes the shiftAssignmentList is sorted
    // Filter out every immovable ShiftAssignment
    List<ShiftAssignment> shiftAssignmentList =
        new ArrayList<ShiftAssignment>(nurseRoster.getShiftAssignmentList());
    for (Iterator<ShiftAssignment> it = shiftAssignmentList.iterator(); it.hasNext(); ) {
      ShiftAssignment shiftAssignment = it.next();
      if (!filter.accept(nurseRoster, shiftAssignment)) {
        it.remove();
      }
    }

    // Hash the assignments per employee
    Map<Employee, List<AssignmentSequence>> employeeToAssignmentSequenceListMap =
        new HashMap<Employee, List<AssignmentSequence>>(employeeList.size());
    int assignmentSequenceCapacity = nurseRoster.getShiftDateList().size() + 1 / 2;
    for (Employee employee : employeeList) {
      employeeToAssignmentSequenceListMap.put(
          employee, new ArrayList<AssignmentSequence>(assignmentSequenceCapacity));
    }
    for (ShiftAssignment shiftAssignment : shiftAssignmentList) {
      Employee employee = shiftAssignment.getEmployee();
      List<AssignmentSequence> assignmentSequenceList =
          employeeToAssignmentSequenceListMap.get(employee);
      if (assignmentSequenceList.isEmpty()) {
        AssignmentSequence assignmentSequence = new AssignmentSequence(shiftAssignment);
        assignmentSequenceList.add(assignmentSequence);
      } else {
        AssignmentSequence lastAssignmentSequence =
            assignmentSequenceList // getLast()
                .get(assignmentSequenceList.size() - 1);
        if (lastAssignmentSequence.belongsHere(shiftAssignment)) {
          lastAssignmentSequence.add(shiftAssignment);
        } else {
          AssignmentSequence assignmentSequence = new AssignmentSequence(shiftAssignment);
          assignmentSequenceList.add(assignmentSequence);
        }
      }
    }

    // The create the move list
    List<Move> moveList = new ArrayList<Move>();
    // For every 2 distinct employees
    for (ListIterator<Employee> leftEmployeeIt = employeeList.listIterator();
        leftEmployeeIt.hasNext(); ) {
      Employee leftEmployee = leftEmployeeIt.next();
      List<AssignmentSequence> leftAssignmentSequenceList =
          employeeToAssignmentSequenceListMap.get(leftEmployee);
      for (ListIterator<Employee> rightEmployeeIt =
              employeeList.listIterator(leftEmployeeIt.nextIndex());
          rightEmployeeIt.hasNext(); ) {
        Employee rightEmployee = rightEmployeeIt.next();
        List<AssignmentSequence> rightAssignmentSequenceList =
            employeeToAssignmentSequenceListMap.get(rightEmployee);

        final int SWITCH_LENGTH = 3;
        for (AssignmentSequence leftAssignmentSequence : leftAssignmentSequenceList) {
          List<ShiftAssignment> leftShiftAssignmentList =
              leftAssignmentSequence.getShiftAssignmentList();
          for (int leftIndex = 0;
              leftIndex <= leftShiftAssignmentList.size() - SWITCH_LENGTH;
              leftIndex++) {

            for (AssignmentSequence rightAssignmentSequence : rightAssignmentSequenceList) {
              List<ShiftAssignment> rightShiftAssignmentList =
                  rightAssignmentSequence.getShiftAssignmentList();
              for (int rightIndex = 0;
                  rightIndex <= rightShiftAssignmentList.size() - SWITCH_LENGTH;
                  rightIndex++) {

                List<Move> subMoveList = new ArrayList<Move>(SWITCH_LENGTH * 2);
                for (ShiftAssignment leftShiftAssignment :
                    leftShiftAssignmentList.subList(leftIndex, leftIndex + SWITCH_LENGTH)) {
                  subMoveList.add(new EmployeeChangeMove(leftShiftAssignment, rightEmployee));
                }
                for (ShiftAssignment rightShiftAssignment :
                    rightShiftAssignmentList.subList(rightIndex, rightIndex + SWITCH_LENGTH)) {
                  subMoveList.add(new EmployeeChangeMove(rightShiftAssignment, leftEmployee));
                }
                moveList.add(CompositeMove.buildMove(subMoveList));
              }
            }
          }
        }
      }
    }
    return moveList;
  }
 private boolean belongsHere(ShiftAssignment shiftAssignment) {
   return shiftAssignment.getShiftDateDayIndex() <= (lastDayIndex + 1);
 }
 private AssignmentSequence(ShiftAssignment shiftAssignment) {
   shiftAssignmentList = new ArrayList<ShiftAssignment>();
   shiftAssignmentList.add(shiftAssignment);
   firstDayIndex = shiftAssignment.getShiftDateDayIndex();
   lastDayIndex = firstDayIndex;
 }