Edit: Updated to account for "Sharon Ben Asher"'s suggestions
package com.exercise.mathplan;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXBException;
public class MathplanApplication {
static final String TIMETABLE_URL = "./src/main/resources/timetable.xml";
private static String ROOMCONFLICT_MSG = """
Course with ID '%s' and course with ID '%s' have a scheduling conflict for room '%s'
on %s %n""";
private static String CURRICULARCONFLICT_MSG = """
Course with ID '%s' and course with ID '%s' have a scheduling conflict for curriculum '%s'
on %s %n""";
public static void main(String[] args) throws FileNotFoundException, JAXBException {
List<ClassBooking> cbList =
UniversityFileParser.parseUniversityFile(TIMETABLE_URL);
resultPresentation(new ScheduleConflictDiscovery().findSchedulingConflicts(cbList));
}
private static void resultPresentation(Map<String, Set<List<ClassBooking>>> conflictMap) {
if (!conflictMap.get("room").isEmpty()) {
System.out.printf("There were %d room conflicts discovered: %n",
conflictMap.get("room").size());
}
conflictMap.get("room").forEach(st -> printRoomConflict(st));
if (!conflictMap.get("curricular").isEmpty()) {
System.out.printf("%nThere were %d curricular conflicts discovered: %n",
conflictMap.get("curricular").size());
}
conflictMap.get("curricular").forEach(st -> printCurricularConflict(st));
}
private static void printRoomConflict(List<ClassBooking> cbList) {
System.out.printf(ROOMCONFLICT_MSG, cbList.get(0).getId(), cbList.get(1).getId(),
cbList.get(0).getRoom(), cbList.get(0).getWeekday().toString().toLowerCase());
}
private static void printCurricularConflict(List<ClassBooking> cbList) {
String conflictingMajor = getConflictingMajor(cbList.get(0), cbList.get(1));
System.out.printf(CURRICULARCONFLICT_MSG, cbList.get(0).getId(),
cbList.get(1).getId(), conflictingMajor,
cbList.get(0).getWeekday().toString().toLowerCase());
}
private static String getConflictingMajor(ClassBooking cb1, ClassBooking cb2) {
Set<String> copyCurriculum1 = new HashSet<>(cb1.getInCurriculum());
copyCurriculum1.retainAll(cb2.getInCurriculum());
return copyCurriculum1.stream().findFirst().get();
}
}
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.bind.JAXBException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
private static String ROOMCONFLICT_MSG = """
Course with ID %s and course with ID %s have a scheduling conflict for room %s
on %s %n""";
private static String PROGRAMCONFLICT_MSG = """
Course with ID %s and course with ID %s have a scheduling conflict for program %s
on %s %n""";
public static void main(String[] args) throws FileNotFoundException, JAXBException {
SpringApplication.run(Application.class, args);
List<ClassBooking> cbList =
UniversityFileParser.parseUniversityFile(
"./src/main/resources/timetable.xml");
ScheduleConflictDiscovery.findSchedulingConflicts(cbList);
resultPresentation();
}
private static void resultPresentation() {
if (!ScheduleConflictDiscovery.getRoomConflicts().isEmpty()) {
System.out.printf("There were %d room conflicts discovered: %n",
ScheduleConflictDiscovery.getRoomConflicts().size());
}
ScheduleConflictDiscovery.getRoomConflicts().forEach(
st -> printRoomConflict(st));
if (!ScheduleConflictDiscovery.getRoomConflicts().isEmpty()) {
System.out.printf("%nThere were %d program conflicts discovered: %n",
ScheduleConflictDiscovery.getProgramConflicts().size());
}
ScheduleConflictDiscovery.getProgramConflicts().forEach(
st -> printProgramConflict(st));
}
private static void printRoomConflict(List<ClassBooking> cbList) {
System.out.printf(ROOMCONFLICT_MSG, cbList.get(0).getId(), cbList.get(1).getId(),
cbList.get(0).getRoom(), cbList.get(0).getWeekday().toString());
}
private static void printProgramConflict(List<ClassBooking> cbList) {
String conflictingMajor = getConflictingMajor(cbList.get(0), cbList.get(1));
System.out.printf(PROGRAMCONFLICT_MSG, cbList.get(0).getId(),
cbList.get(1).getId(), conflictingMajor,
cbList.get(0).getWeekday().toString());
}
private static String getConflictingMajor(ClassBooking cb1, ClassBooking cb2) {
Set<String> copyCurriculum1 = new HashSet<>(cb1.getInCurriculum());
copyCurriculum1.retainAll(cb2.getInCurriculum());
return copyCurriculum1.stream().findFirst().get();
}
}
@Component
public class UniversityFileParser {
private static JAXBContext jaxbContext;
private static Map<String,List<String>> curriculumMap = new HashMap<>();
static final DateTimeFormatter WEEKDAYFORMATTER = DateTimeFormatter.ofPattern("E", Locale.US);
private UniversityFileParser() throws JAXBException {
jaxbContext = JAXBContext.newInstance(University.class);
}
public static List<ClassBooking> parseUniversityFile(String fileURL)
throws FileNotFoundException, JAXBException {
University university = (University) JAXBIntrospector.getValue(
getJaxbContext()jaxbContext.createUnmarshaller().unmarshal(new FileReader(fileURL)));
return parseLecturesparseCurriculum(university);
}
private static JAXBContext getJaxbContext() throws JAXBExceptionreturn {parseLectures(university);
}
if(jaxbContext == null) {
private jaxbContextstatic =void JAXBContext.newInstanceparseCurriculum(University.class);
university) }{
return jaxbContext;
}
for (Curriculum curr: university.getCurricula().getCurriculum()){
private static Map<String, List<String>> parseCurriculum(University university) {
List<Lecture> newCurriculum Map<String,List<String>>=
curriculumMap = new HashMap<>();
universitycurr.getCurriculagetLecture().getCurriculumstream().forEachmap(
currentry -> curriculumMap.put(currLecture) entry.getNamegetValue(), )
buildStringPresentationOfCurriculum.toList(curr)));
return curriculumMap;
}
privateList<String> staticnewCurriculumString List<String>= buildStringPresentationOfCurriculumnewCurriculum.stream(Curriculum curr) { .
List<Lecture> newCurriculum =map(Lecture::getId).toList();
curr.getLecture()curriculumMap.streamput()curr.map(entry -> getName(Lecture), entry.getValue()).toList(newCurriculumString);
return newCurriculum.stream().
map(Lecture::getId).toList();}
}
private static List<ClassBooking> parseLectures(University university) {
Map<String, List<String>> curriculumMap = parseCurriculum(university);
List<List<ClassBooking>> cbList = university.getLectures().getLecture()
.stream().map(lecture -> parseBookings(lecture.getId(),
lecture.getRoombookings(), curriculumMap)).toList();
return cbList.stream().flatMap(Collection::stream).toList();
}
private static List<ClassBooking> parseBookings(String id,
Roombookings roomBookings, Map<String, List<String>> curriculumMap) {
List<ClassBooking> classBookings = new ArrayList<>();
for (Booking b: roomBookings.getBooking()) {
classBookings.add(ClassBooking cb = new ClassBooking(id, b.getRoom(),
getWeekday(b.getWeekday()),
LocalTime.of(b.getStartTime().getHour(), 0),
LocalTime.of(b.getEndTime().getHour(), 0),
addPrograms(id));
addCurriculum(id, curriculumMap))
classBookings.add(cb);
}
return classBookings;
}
private static Set<String> addCurriculumaddPrograms(String courseID,) {
Map<String,Set<String> List<String>>programSet curriculumMap)= {new HashSet<>();
returnfor (Entry<String, List<String>> degree: curriculumMap.entrySet().stream()
{
.filter(degree ->if (degree.getValue().contains(courseID)).map(Entry::getKey) {
programSet.collectadd(Collectorsdegree.toSetgetKey());
}
}
return programSet;
}
private static DayOfWeek getWeekday(String weekday) {
if ("Thur".equals(weekday)) {
return DayOfWeek.THURSDAY;
}
return DayOfWeek.from(WEEKDAYFORMATTER.parse(weekday));
}
}
private static Set<List<ClassBooking>> roomConflicts;
private static Set<List<ClassBooking>> curricularConflicts;
programConflicts;
public Map<String,static Set<List<ClassBooking>>>void findSchedulingConflicts(List<ClassBooking> cbList) {
roomConflicts = new HashSet<>();
curricularConflictsprogramConflicts = new HashSet<>();
findOverlaps(cbList);
Map<String, Set<List<ClassBooking>>> resultMap = new HashMap<>();
resultMap.put("room", roomConflicts);
resultMap.put("curricular", curricularConflicts);
return Map.ofEntries(
Map.entry("room", roomConflicts), Map.entry("curricular", curricularConflicts));
}
private static void findOverlaps(List<ClassBooking> cbList) {
for (int i = 0;i<cbList.size();i++) {
ClassBooking currCB = cbList.get(i);
List<ClassBooking> overlaps = IntStream.range(i + 1, cbList.size())
.filter(j -> hasOverLap(currCB, cbList.get(j)))
.mapToObj(cbList::get).toList();
findConflicts(currCB, overlaps);
}
}
}
private static void findConflicts(ClassBooking currentCB,
List<ClassBooking> overlaps) {
for (ClassBooking cb: overlaps) {
if (currentCB.getRoom().equals(cb.getRoom())) {
List<ClassBooking> cbSet = List.of(currentCB, cb);
roomConflicts.add(cbSet);
}
Set<String> currMajors = new HashSet<>(currentCB.getInCurriculum());
currMajors.retainAll(cb.getInCurriculum());
if (!currMajors.isEmpty()) {
List<ClassBooking> cbSet = List.of(currentCB, cb);
curricularConflictsprogramConflicts.add(cbSet);
}
}
}
private static boolean hasOverLap(ClassBooking cb1, ClassBooking cb2) {
return (cb1.getWeekday() == cb2.getWeekday()) &&
(((cb1.getBeginTime().isBefore(cb2.getBeginTime()) ||
cb1.getBeginTime().equals(cb2.getBeginTime())) &&
cb1.getEndTime().isAfter(cb2.getBeginTime())) ||
((cb1.getBeginTime().isAfter(cb2.getBeginTime()) ||
cb1.getBeginTime().equals(cb2.getBeginTime())) &&
cb1.getBeginTime().isBefore(cb2.getEndTime())));
}
public static Set<List<ClassBooking>> getRoomConflicts() {
return roomConflicts;
}
public static Set<List<ClassBooking>> getProgramConflicts() {
return programConflicts;
}
}