| summaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/CelcatParser.java')
| -rw-r--r-- | src/CelcatParser.java | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/src/CelcatParser.java b/src/CelcatParser.java new file mode 100644 index 0000000..01e0314 --- /dev/null +++ b/src/CelcatParser.java @@ -0,0 +1,482 @@ +import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Calendar; +import java.util.Locale; +import java.util.Iterator; +import java.util.TimeZone; + +import java.io.PrintWriter; + +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamException; + +/** + * This class stores the incoming data from XML. + * It is needed because of the stream nature of the XML parser. + **/ +public class CelcatParser +{ + private final HashMap<Integer, Calendar> weeks; + private final Group group; + private String day; + private String week; + private String start_time; + private String end_time; + private String uid_prefix; + private Event event; + private DataType data_type; + private ListType current_list_type; + private int event_count; + + public static void parse + ( + final XMLStreamReader stream_reader, + final Group group, + final String uid_prefix + ) + throws XMLStreamException + { + final CelcatParser parser; + + parser = new CelcatParser(group, uid_prefix); + + while (stream_reader.hasNext()) + { + switch (stream_reader.next()) + { + case XMLStreamReader.START_ELEMENT: + parser.handle_new_element(stream_reader); + break; + + case XMLStreamReader.CDATA: + case XMLStreamReader.CHARACTERS: + parser.handle_data(stream_reader.getText().trim()); + break; + + case XMLStreamReader.END_DOCUMENT: + parser.flush(); + break; + + default: + break; + } + } + } + + private CelcatParser + ( + final Group group, + final String uid_prefix + ) + { + this.group = group; + this.uid_prefix = uid_prefix; + + event = null; + event_count = 0; + weeks = new HashMap<Integer, Calendar>(); + } + + /** + * Called when entering an new element. + **/ + private void handle_new_element (final XMLStreamReader stream_reader) + { + final DataType new_data_type; + + new_data_type = DataType.get(stream_reader.getLocalName()); + + switch (new_data_type) + { + case EVENT: + /** We're done handling the previous event. **/ + flush(); + break; + + case SPAN: + /** This contains information about the weeks. **/ + weeks.put + ( + Integer.parseInt + ( + stream_reader.getAttributeValue(null, "rawix") + ), + get_calendar_from_span + ( + stream_reader.getAttributeValue(null, "date") + ) + ); + break; + + case ROOM: + /** + * Multiple rooms may be concerned, hence the List. + * Any following ITEM elements should be considered as describing + * a room for this event. + **/ + current_list_type = ListType.ROOMS; + break; + + case GROUP: + /** + * Multiple groups may be concerned, hence the List. + * Any following ITEM elements should be considered as describing + * a group for this event. + **/ + current_list_type = ListType.GROUPS; + break; + + case ITEM: + if (data_type == DataType.MODULE) + { + /** + * The XML file will consider that the event may concern + * multiple modules. It makes sense, but I've never seen + * it happen and it complicates the process. + * Not updating the data_type here will make the next + * data be considered as the Module's name instead of + * something to add to a list. + **/ + + /* [XXX][Improvement] Handle it. */ + + return; + } + break; + + default: + break; + } + + data_type = new_data_type; + } + + private void flush () + { + week = null; + start_time = null; + end_time = null; + + if (event == null) + { + /** + * This is the first event, we don't have anything to write. + **/ + + event = new Event(); + event.set_uid(uid_prefix + (event_count++)); + + return; + } + + group.add_event(event); + + event = new Event(); + event.set_uid(uid_prefix + (event_count++)); + + current_list_type = ListType.IGNORED; + } + + /** + * Called when finding actual data. + **/ + private void handle_data (final String data) + { + if (data.equals("")) + { + /** + * Data was garbage. + * It happens sometimes, I don't know why. + **/ + + /* [XXX][Improvement] Prevent this from happening. */ + return; + } + + /** + * Uses the previously set "data_type" to know where the data belongs. + **/ + switch (data_type) + { + case MODULE: + event.set_name(data); + break; + + case STARTTIME: + if ((week == null) || (day == null)) + { + start_time = data; + } + else + { + event.set_start_time + ( + get_calendar + ( + week_to_calendar(week), + day, + data + ) + ); + } + break; + + case ENDTIME: + if ((week == null) || (day == null)) + { + end_time = data; + } + else + { + event.set_end_time + ( + get_calendar + ( + week_to_calendar(week), + day, + data + ) + ); + } + break; + + case NOTES: + if (event != null) + { + event.set_description("[Notes] " + data); + } + break; + + case RAWWEEKS: + week = data; + + if ((start_time != null) && (day != null)) + { + event.set_start_time + ( + get_calendar + ( + week_to_calendar(week), + day, + start_time + ) + ); + } + + if ((end_time != null) && (day != null)) + { + event.set_end_time + ( + get_calendar + ( + week_to_calendar(week), + day, + end_time + ) + ); + } + + break; + + case DAY: + day = data; + + if ((start_time != null) && (week != null)) + { + event.set_start_time + ( + get_calendar + ( + week_to_calendar(week), + day, + start_time + ) + ); + } + + if ((end_time != null) && (week != null)) + { + event.set_end_time + ( + get_calendar + ( + week_to_calendar(week), + day, + end_time + ) + ); + } + break; + + case CATEGORY: + event.set_category(data); + break; + + case ITEM: + switch (current_list_type) + { + case ROOMS: + event.add_location(data); + break; + + case GROUPS: + event.add_attendee(data); + break; + + default: + break; + } + break; + } + } + + /** + * Retrieves the relevant data from a week description. + **/ + private Calendar get_calendar_from_span (final String spandata) + { + final String[] data; + final Calendar result; + + data = spandata.split("/"); + + result = + java.util.Calendar.getInstance + ( + TimeZone.getTimeZone("Europe/Paris"), + Locale.FRENCH + ); + + if (data.length != 3) + { + Error.ERROR.from_thread + ( + group.get_abbreviation(), + ("Invalid date format for week:" + spandata) + ); + + return null; + } + + result.set(java.util.Calendar.DAY_OF_MONTH, Integer.parseInt(data[0])); + + /* Java... don't ask... */ + result.set(java.util.Calendar.MONTH, Integer.parseInt(data[1]) - 1); + + result.set(java.util.Calendar.YEAR, Integer.parseInt(data[2])); + + return result; + } + + + /** + * Retrieves the week relevant to the event being processed. + **/ + private Calendar week_to_calendar + ( + final String week + ) + { + final java.util.Calendar result; + int pos; + + for (pos = 0; week.charAt(pos) != 'Y'; ++pos); + + result = weeks.get(pos + 1); + + if (result == null) + { + Error.ERROR.from_thread + ( + group.get_abbreviation(), + "An event appeared before its week description did." + ); + } + + return result; + } + + private java.util.Calendar get_calendar + ( + final Calendar week, + final String day, + final String hourmin + ) + { + final String[] time; + final java.util.Calendar result; + + time = hourmin.split(":"); + + result = (java.util.Calendar) week.clone(); + + result.set(java.util.Calendar.HOUR_OF_DAY, Integer.parseInt(time[0])); + result.set(java.util.Calendar.MINUTE, Integer.parseInt(time[1])); + result.add(java.util.Calendar.DAY_OF_YEAR, Integer.parseInt(day)); + + return result; + } + + private static enum ListType + { + IGNORED, ROOMS, GROUPS; + } + + /** + * This enum is used to sort what is relevant in the XML file. + * Sadly, for justified reasons, Java does not permit access to the static + * members of an enum from its constructor, hence the "static"'s redundancy. + **/ + private static enum DataType + { + IRRELEVANT, + EVENT, + DAY, + STARTTIME, + ENDTIME, + CATEGORY, + RAWWEEKS, + ITEM, + MODULE, + ROOM, + SPAN, + NOTES, + GROUP; + + private static final HashMap<String, DataType> FROM_STRING; + + static + { + FROM_STRING = new HashMap<String, DataType>(); + + FROM_STRING.put("irrelevant", IRRELEVANT); + FROM_STRING.put("event", EVENT); + FROM_STRING.put("day", DAY); + FROM_STRING.put("starttime", STARTTIME); + FROM_STRING.put("endtime", ENDTIME); + FROM_STRING.put("category", CATEGORY); + FROM_STRING.put("item", ITEM); + FROM_STRING.put("module", MODULE); + FROM_STRING.put("room", ROOM); + FROM_STRING.put("group", GROUP); + FROM_STRING.put("rawweeks", RAWWEEKS); + FROM_STRING.put("span", SPAN); + FROM_STRING.put("notes", NOTES); + } + + public static DataType get (final String e) + { + final DataType result; + + result = FROM_STRING.get(e); + + if (result == null) + { + return IRRELEVANT; + } + + return result; + } + } +} |


