summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/CelcatParser.java')
-rw-r--r--src/CelcatParser.java482
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;
+ }
+ }
+}