/**
* @(#) LegacyDataModelPersister.java
*
* This file is part of the Course Scheduler, an open source, cross platform
* course scheduling tool, configurable for most universities.
*
* Copyright (C) 2010-2014 Devyse.io; All rights reserved.
*
* @license GNU General Public License version 3 (GPLv3)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package Scheduler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;
import io.devyse.scheduler.retrieval.CoursePersister;
/**
* A Course data persister implementation that processes course data and persists it
* into the legacy data model
*
* @author Mike Reinhold
*
*/
public class LegacyDataModelPersister implements CoursePersister {
/**
* Static logger
*/
private static XLogger logger = XLoggerFactory.getXLogger(LegacyDataModelPersister.class);
/**
* Legacy database class
*/
private Database database;
/**
* Create a new instance of the legacy datamodel persister which will store persist the
* course data into the specified database
*
* @param database the legacy database which is the target for the persisting activity
*/
public LegacyDataModelPersister(Database database) {
super();
this.database = database;
}
/**
* @return the database
*/
public Database getDatabase() {
return database;
}
/* (non-Javadoc)
* @see io.devyse.scheduler.retrieval.CoursePersister#persist(java.util.Map)
*/
@Override
public void persist(Map<String, String> data) {
//only go through the effort of outputting if the necessary logging level is enabled
if(logger.isDebugEnabled()){
List<String> keys = new ArrayList<>();
keys.addAll(data.keySet());
Collections.sort(keys);
for(String key: keys){
logger.debug("{}: {}", key, data.get(key));
}
}
Section section = new Section();
processHeaderFields(data, section);
processSectionType(data, section);
String open = data.get("seating.Remaining");
String credits = data.get("credit.Credit");
section.setCredit(credits);
section.setSeats(Integer.valueOf(open));
//TODO get notes from a field somewhere
String notes = "";
processMeetingInformation(data, section, notes);
//persist the parsed section
database.addSection(section);
}
/**
* Process the section header and extract the relevant fields
*
* @param data map of the section data extracted from the source
* @param section the section instance into which the data should be persisted
*/
private void processHeaderFields(Map<String, String> data, Section section){
String header = data.get("header");
Pattern headerPattern = Pattern.compile("(.*) - (\\d+) - ([\\w\\s]+) - ([\\S]+)");
Matcher headerMatcher = headerPattern.matcher(header);
headerMatcher.find();
String title = headerMatcher.group(1);
String requestNum = headerMatcher.group(2);
String courseID = headerMatcher.group(3);
String sectionID = headerMatcher.group(4);
section.setCRN(Integer.valueOf(requestNum));
section.setCourseID(courseID);
section.setSection(sectionID);
section.setTitle(title);
}
/**
* Process the course data to extract the section type
*
* @param data map of the section data extracted from the source
* @param section the section instance into which the data should be persisted
*/
private void processSectionType(Map<String, String> data, Section section){
String levels = data.get("levels");
String type = data.get("type");
Pattern levelsPattern = Pattern.compile("((Non Degree)?(-)?(\\w+))");
Matcher levelsMatcher = levelsPattern.matcher(levels);
List<String> levelsList = new ArrayList<>();
while(levelsMatcher.find()){
boolean degreeProgram = levelsMatcher.group(2) == null;
if(degreeProgram) levelsList.add(levelsMatcher.group(4));
}
// Legacy data model has limited ability to capture the different course types
CourseType sectionType;
if(levelsList.contains("Graduate")){
if(type.contains("Internet")){
sectionType = CourseType.campusAndDistance;
}else{
sectionType = CourseType.campusGrad;
}
}else{
sectionType = CourseType.undergrad;
}
section.setType(sectionType);
}
/**
* Process the meeting times from the course data and update the section meeting information
*
* @param data map of the section data extracted from the source
* @param section the section instance into which the data should be persisted
* @param notes the section notes field containing additional details
*/
private void processMeetingInformation(Map<String, String> data, Section section, String notes){
//check for meetings
for(int meeting=0; data.get("meeting."+meeting) != null; meeting++){
String period = data.get("meeting."+meeting+".Time");
boolean[] days = buildDayArray(data.get("meeting."+meeting+".Days"));
String location = data.get("meeting."+meeting+".Where");
String instructorString = data.get("meeting."+meeting+".Instructors");
List<String> instructorList = extractInstructorList(instructorString);
if(meeting == 0){
section.setPeriod(period);
section.setDays(days);
section.setLocation(location);
section.setInstructorList(instructorList);
}else if(meeting == 1){
section.setSecondary(true);
section.setSecPeriod(period);
section.setSecDays(days);
section.setSecLocation(location);
}else if(meeting == 2){ // don't need to add this more than once
notes += "\nThis course has more than 2 meeting times. /nPlease confirm that the additional meeting times do not impact your schedule.";
}
}
section.setNotes(notes);
}
/**
* Extract the instructor list from the provided instructor string
*
* @param instructorString the instructor string containing the instructor names
* @return the list of instructor names
*/
private List<String> extractInstructorList(String instructorString){
List<String> instructorList = new ArrayList<>();
Pattern instPattern = Pattern.compile("((?:[^\\(\\),]){2,}+)");
Matcher instMatcher = instPattern.matcher(instructorString);
while(instMatcher.find()){
String instructor = instMatcher.group(1);
if(instructor.compareTo("") != 0){
instructorList.add(instructor.trim());
}
}
return instructorList;
}
/**
* Build a day flag array based on the specified day character string
*
* @param dayString a string of characters representing the days on which a meeting occurs (eg. MWF)
* @return a day flag array indicating the days
*/
private boolean[] buildDayArray(String dayString){
boolean[] days = new boolean[Day.values().length];
if(dayString.compareTo("\u00A0") != 0){
for(char dayCode: dayString.toCharArray()){
Day day = Day.getDay(new Character(dayCode).toString());
days[day.value()] = true;
}
}
return days;
}
}