package com.catchnotes.api;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import org.apache.http.HttpResponse;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.os.Build;
import android.text.format.Time;
import android.util.Log;
import android.util.TimeFormatException;
public static final long ERROR_RESPONSE_NULL = -1;
public static final long ERROR_PARAMETERS_NULL = -2;
private static final String XML_TAG_NOTES = "notes";
private static final String XML_TAG_NOTE = "note";
private static final String XML_TAG_CREATED = "created_at";
private static final String XML_TAG_MODIFIED = "modified_at";
private static final String XML_TAG_REMINDER = "reminder_at";
private static final String XML_TAG_SERVER_MODIFIED = "server_modified_at";
private static final String XML_TAG_ID = "id";
private static final String XML_TAG_SOURCE = "source";
private static final String XML_TAG_SOURCE_URL = "source_url";
private static final String XML_TAG_TEXT = "text";
private static final String XML_TAG_SUMMARY = "summary";
private static final String XML_TAG_USER = "user";
private static final String XML_TAG_USER_NAME = "user_name";
private static final String XML_TAG_COMMENTS = "comments";
private static final String XML_TAG_COMMENT = "comment";
private static final String XML_TAG_MODE = "mode";
private static final String XML_TAG_BROWSER_URL = "browser_url";
private static final String XML_TAG_TAGS = "tags";
private static final String XML_TAG_TAG = "tag";
private static final String XML_TAG_MEDIA_LIST = "media_list";
private static final String XML_TAG_MEDIA = "media";
private static final String XML_TAG_CONTENT_TYPE = "type";
private static final String XML_TAG_SRC = "src";
private static final String XML_TAG_SIZE = "size";
private static final String XML_TAG_FILENAME = "filename";
private static final String XML_TAG_VOICE_HINT = "voicenote_hint";
private static final String XML_TAG_LOCATION = "location";
private static final String XML_TAG_LATITUDE = "latitude";
private static final String XML_TAG_LONGITUDE = "longitude";
private static final String XML_TAG_ALTITUDE = "altitude";
private static final String XML_TAG_SPEED = "speed";
private static final String XML_TAG_BEARING = "bearing";
private static final String XML_TAG_ACCURACY_POSITION = "accuracy_position";
private static final String XML_TAG_ACCURACY_ALTITUDE = "accuracy_altitude";
private static final boolean PARSE_TRACING_OUTPUT_ENABLED = false;
private static final String LOGCAT_NAME = "CatchParser";
public static final String CATCH_NAMESPACE_PREFIX = "catch";
private Time timestamper;
private SimpleDateFormat rfc3339;
try {
if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.ECLAIR_0_1) {
timestamper = new Time();
}
} catch (Exception e) { }
}
public void parseSyncV2XML(HttpResponse response, List<CatchNoteRef> noteRefs)
throws XmlPullParserException, IOException, IllegalArgumentException {
if (response == null || noteRefs == null) {
throw new IllegalArgumentException();
}
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(response.getEntity().getContent(), null);
int eventType = parser.getEventType();
String startTag;
String endTag;
String nextText = "";
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
parse_trace("Beginning XML pullparse.");
} else if (eventType == XmlPullParser.START_TAG) {
startTag = parser.getName();
if (XML_TAG_NOTES.equals(startTag)) {
parse_trace("Parsing noteRefs.");
} else if (XML_TAG_NOTE.equals(startTag)) {
parse_trace("Parsing a note.");
CatchNoteRef noteRef = new CatchNoteRef();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
startTag = parser.getName();
if (XML_TAG_ID.equals(startTag)) {
nextText = parser.nextText();
noteRef.nodeId = nextText;
parse_trace("Note ID is " + noteRef.nodeId);
} else if (XML_TAG_SERVER_MODIFIED.equals(startTag)) {
nextText = parser.nextText();
noteRef.serverModified = nextText;
parse_trace("Server modification time is " + noteRef.serverModified);
}
} else if (eventType == XmlPullParser.END_TAG) {
endTag = parser.getName();
if (XML_TAG_NOTE.equals(endTag)) {
parse_trace("Parsing noteRef complete.");
break;
}
}
eventType = parser.next();
}
noteRefs.add(noteRef);
} else {
parse_trace("(parseSyncV2XML) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
endTag = parser.getName();
if (XML_TAG_NOTES.equals(endTag)) {
parse_trace("Parsed " + noteRefs.size() + " noteRefs.");
}
}
eventType = parser.next();
}
}
ArrayList<CatchNote> notes, long parentId)
throws XmlPullParserException, IOException, IllegalArgumentException {
if (response == null || notes == null) {
throw new IllegalArgumentException();
}
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser parser = factory.newPullParser();
parser.setInput(response.getEntity().getContent(), null);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_DOCUMENT) {
parse_trace("Beginning XML pullparse.");
} else if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
if (XML_TAG_NOTES.equals(startTag)) {
parse_trace("Parsing notes.");
} else if (XML_TAG_NOTE.equals(startTag)) {
parse_trace("Parsing a note.");
parseNote(parser, notes, parentId);
} else {
parse_trace("(parseNotesXml) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_NOTES.equals(endTag)) {
parse_trace("Parsed " + notes.size() + " notes.");
}
}
eventType = parser.next();
}
}
ArrayList<CatchNote> returnVal, long parentId)
throws XmlPullParserException, IOException {
CatchNote note = new CatchNote();
returnVal.add(note);
note.parentId = parentId;
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
String nextText = "";
if (parser.getNamespace().equals(XmlPullParser.NO_NAMESPACE)) {
if (XML_TAG_ID.equals(startTag)) {
nextText = parser.nextText();
note.id = nextText;
parse_trace("Note ID is " + note.id);
} else if (XML_TAG_SOURCE.equals(startTag)) {
nextText = parser.nextText();
note.source = nextText;
parse_trace("Note source is " + note.source);
} else if (XML_TAG_SOURCE_URL.equals(startTag)) {
nextText = parser.nextText();
note.sourceUrl = nextText;
parse_trace("Note source URL is " + note.sourceUrl);
} else if (XML_TAG_CREATED.equals(startTag)) {
nextText = parser.nextText();
note.creationTime = parse3339(nextText);
parse_trace("Creation time is " + nextText + " (" +
note.creationTime + ')');
} else if (XML_TAG_MODIFIED.equals(startTag)) {
nextText = parser.nextText();
note.modificationTime = parse3339(nextText);
parse_trace("Modification time is " + nextText +
" (" + note.modificationTime + ')');
} else if (XML_TAG_REMINDER.equals(startTag)) {
nextText = parser.nextText();
note.reminderTime = parse3339(nextText);
parse_trace("Reminder time is " + nextText + " (" +
note.reminderTime + ')');
} else if (XML_TAG_SERVER_MODIFIED.equals(startTag)) {
nextText = parser.nextText();
note.serverModifiedAt= parse3339(nextText);
parse_trace("ServerModifiedAt time is " + nextText + " (" +
note.serverModifiedAt + ')');
} else if (XML_TAG_TEXT.equals(startTag)) {
nextText = parser.nextText();
note.text = nextText;
parse_trace("Note text is \"" + note.text + '"');
} else if (XML_TAG_SUMMARY.equals(startTag)) {
nextText = parser.nextText();
note.summary = nextText;
parse_trace("Note summary is \"" + note.summary + '"');
} else if (XML_TAG_COMMENTS.equals(startTag)) {
note.children = 0;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
startTag = parser.getName();
if (XML_TAG_COMMENT.equals(startTag)) {
note.children++;
parse_trace("found comment");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_COMMENTS.equals(endTag)) {
parse_trace("Parsing comments complete.");
break;
}
}
eventType = parser.next();
}
parse_trace("Comment count is " + note.children);
} else if (XML_TAG_MODE.equals(startTag)) {
nextText = parser.nextText();
note.mode = nextText;
parse_trace("Mode is " + note.mode);
} else if (XML_TAG_BROWSER_URL.equals(startTag)) {
nextText = parser.nextText();
note.browserUrl = nextText;
parse_trace("Browser URL is " + note.browserUrl);
}
else if (XML_TAG_USER.equals(startTag)) {
parse_trace("Parsing note owner data.");
parseNoteOwner(parser, note);
} else if (XML_TAG_TAGS.equals(startTag)) {
parse_trace("Parsing note tags.");
parseTags(parser, note);
} else if (XML_TAG_LOCATION.equals(startTag)) {
parse_trace("Parsing geotag.");
parseLocation(parser, note);
} else if (XML_TAG_MEDIA_LIST.equals(startTag)) {
parse_trace("Parsing media list.");
parseMediaList(parser, note);
} else {
parse_trace("(parseNote) unknown XML tag: <" + startTag + ">");
}
} else if (parser.getPrefix().equals(CATCH_NAMESPACE_PREFIX)) {
parse_trace("Parsing annotation.");
if (note.annotations == null) {
note.annotations = new HashMap<String, String>();
}
note.annotations.put(startTag, parser.nextText());
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_NOTE.equals(endTag)) {
parse_trace("Parsing note complete.");
break;
}
}
eventType = parser.next();
}
}
private void parseTags(XmlPullParser parser, CatchNote note)
throws XmlPullParserException, IOException {
ArrayList<CharSequence> tags = new ArrayList<CharSequence>();
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
if (XML_TAG_TAG.equals(startTag)) {
String tag = parser.nextText();
tags.add(tag);
parse_trace("Added tag \"" + tag + '"');
} else {
parse_trace("(parseTags) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_TAGS.equals(endTag)) {
note.tags = tags;
parse_trace("Note had " + note.tags.size()
+ " tag(s).");
break;
}
}
eventType = parser.next();
}
}
throws XmlPullParserException, IOException {
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
if (XML_TAG_MEDIA.equals(startTag)) {
parse_trace("Parsing a media item.");
parseMedia(parser, note);
} else {
parse_trace("(parseMediaList) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_MEDIA_LIST.equals(endTag)) {
parse_trace("Parsing media list complete.");
break;
}
}
eventType = parser.next();
}
}
private void parseMedia(XmlPullParser parser, CatchNote note)
throws XmlPullParserException, IOException {
CatchMedia media = new CatchMedia();
media.note_id = note.id;
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
String nextText = "";
if (XML_TAG_SRC.equals(startTag)) {
nextText = parser.nextText();
media.src = nextText;
parse_trace("Source = " + media.src);
} else if (XML_TAG_ID.equals(startTag)) {
nextText = parser.nextText();
media.id = nextText;
parse_trace("API ID = " + media.id);
} else if (XML_TAG_CREATED.equals(startTag)) {
nextText = parser.nextText();
media.created_at = parse3339(nextText);
parse_trace("Creation time = " + nextText + " (" + media.created_at + ')');
} else if (XML_TAG_CONTENT_TYPE.equals(startTag)) {
nextText = parser.nextText();
media.content_type = nextText;
parse_trace("Type = " + media.content_type);
} else if (XML_TAG_SIZE.equals(startTag)) {
try {
nextText = parser.nextText();
long size = Long.parseLong(nextText);
media.size = size;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for media size: \"" + nextText + '"');
media.size = 0;
}
parse_trace("Size = " + media.size);
} else if (XML_TAG_VOICE_HINT.equals(startTag)) {
nextText = parser.nextText();
media.voice_hint = Boolean.parseBoolean(nextText);
parse_trace("voice hint = " + media.voice_hint);
} else if (XML_TAG_FILENAME.equals(startTag)) {
nextText = parser.nextText();
media.filename = nextText;
parse_trace("Filename = " + media.filename);
} else {
parse_trace("(parseMedia) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_MEDIA.equals(endTag)) {
if (note.mediaList == null) {
note.mediaList = new ArrayList<CatchMedia>();
}
note.mediaList.add(media);
parse_trace("Parsing media item complete.");
break;
}
}
eventType = parser.next();
}
}
throws XmlPullParserException, IOException {
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
String nextText = "";
if (XML_TAG_ID.equals(startTag)) {
try {
nextText = parser.nextText();
long ownerId = Long.parseLong(nextText);
note.ownerId = ownerId;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for note owner ID: \"" + nextText + '"');
note.ownerId = 0;
}
parse_trace("Owner ID = " + note.ownerId);
} else if (XML_TAG_USER_NAME.equals(startTag)) {
String owner = parser.nextText();
note.owner = owner;
parse_trace("Owner name = " + note.owner);
} else {
parse_trace("(parseNoteOwner) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_USER.equals(endTag)) {
parse_trace("Parsing owner data complete.");
break;
}
}
eventType = parser.next();
}
}
throws XmlPullParserException, IOException {
int eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
String startTag = parser.getName();
String nextText = "";
if (XML_TAG_LATITUDE.equals(startTag)) {
try {
nextText = parser.nextText();
double latitude = Double.parseDouble(nextText);
note.latitude = latitude;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for latitude: \"" + nextText + '"');
note.latitude = 0.0;
}
parse_trace("Latitude = " + note.latitude);
} else if (XML_TAG_LONGITUDE.equals(startTag)) {
try {
nextText = parser.nextText();
double longitude = Double.parseDouble(nextText);
note.longitude = longitude;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for longitude: \"" + nextText + '"');
note.longitude = 0.0;
}
parse_trace("Longitude = " + note.longitude);
} else if (XML_TAG_ALTITUDE.equals(startTag)) {
try {
nextText = parser.nextText();
double altitude = Double.parseDouble(nextText);
note.altitude = altitude;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for altitude: \"" + nextText + '"');
note.altitude = 0.0;
}
parse_trace("Altitude = " + note.altitude);
} else if (XML_TAG_SPEED.equals(startTag)) {
try {
nextText = parser.nextText();
double speed = Double.parseDouble(nextText);
note.speed = speed;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for speed: \"" + nextText + '"');
note.speed = 0.0;
}
parse_trace("Speed = " + note.speed);
} else if (XML_TAG_BEARING.equals(startTag)) {
try {
nextText = parser.nextText();
double bearing = Double.parseDouble(nextText);
note.bearing = bearing;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for bearing: \"" + nextText + '"');
note.bearing = 0.0;
}
parse_trace("Bearing = " + note.bearing);
} else if (XML_TAG_ACCURACY_POSITION.equals(startTag)) {
try {
nextText = parser.nextText();
double accuracyPosition = Double.parseDouble(nextText);
note.accuracyPosition = accuracyPosition;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for accuracyPosition: \"" + nextText + '"');
note.accuracyPosition = 0.0;
}
parse_trace("Positional accuracy = "
+ note.accuracyPosition);
} else if (XML_TAG_ACCURACY_ALTITUDE.equals(startTag)) {
try {
nextText = parser.nextText();
double accuracyAltitude = Double.parseDouble(nextText);
note.accuracyAltitude = accuracyAltitude;
} catch (NumberFormatException nfe) {
Log.e(LOGCAT_NAME, "unable to parse value for accuracyAltitude: \"" + nextText + '"');
note.accuracyAltitude = 0.0;
}
parse_trace("Altitude accuracy = "
+ note.accuracyAltitude);
} else {
parse_trace("(parseLocation) unknown XML tag: <" + startTag + ">");
}
} else if (eventType == XmlPullParser.END_TAG) {
String endTag = parser.getName();
if (XML_TAG_LOCATION.equals(endTag)) {
parse_trace("Parsing geotag complete.");
break;
}
}
eventType = parser.next();
}
}
if (PARSE_TRACING_OUTPUT_ENABLED) {
Log.d(LOGCAT_NAME, msg);
}
}
private synchronized long parse3339(String time) {
if (time == null || time.length() == 0) {
return 0;
}
if (timestamper != null) {
try {
timestamper.parse3339(time);
} catch (TimeFormatException e) {
Log.e(LOGCAT_NAME, "got TimeFormatException parsing timestamp: \"" + time + '"', e);
return 0;
}
return timestamper.normalize(false);
} else {
Date timestamp = null;
if (rfc3339 == null) {
rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
rfc3339.setTimeZone(TimeZone.getTimeZone("GMT+0"));
rfc3339.setLenient(true);
}
try {
timestamp = rfc3339.parse(time);
} catch (ParseException e) {
Log.e(LOGCAT_NAME, "got ParseException parsing timestamp: \"" + time + '"', e);
return 0;
}
return timestamp.getTime();
}
}
}