package nl.sogeti.android.gpstracker.actions.tasks;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import nl.sogeti.android.gpstracker.actions.utils.ProgressListener;
import nl.sogeti.android.gpstracker.db.DatabaseHelper;
import nl.sogeti.android.gpstracker.db.GPStracking.Stations;
import nl.sogeti.android.gpstracker.util.ByteProgressAdmin;
import nl.sogeti.android.gpstracker.util.ProgressFilterInputStream;
import nl.sogeti.android.gpstracker.util.UnicodeReader;
import org.apache.ogt.http.HttpResponse;
import org.apache.ogt.http.client.methods.HttpGet;
import org.apache.ogt.http.impl.client.DefaultHttpClient;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.concurrent.CancellationException;
/**
* Created by IntelliJ IDEA.
* User: F8Full
* Date: 12-02-16
* Time: 11:58
* This is the parser class for an XML following Bixi format -- see later comment
* it reads and create stations in the data provider
*/
public class StationsXMLParser extends AsyncTask<String, Void, Uri>
//Parameters are input/output types, GpxParser takes an URI for the file reference,
//whereas I'll have a URL
{
private static final String TAG = "F8F.StationsXMLParser";
protected String mErrorDialogMessage;
protected Exception mErrorDialogException;
protected Context mContext;
private ContentResolver mContentResolver;
private ProgressListener mProgressListener;
protected StationsXMLParserProgressAdmin mStationsXMLParserProgressAdmin;
//TODO: manage database through the conventional way with versioning and stuff
private DatabaseHelper mDbHelper;
public StationsXMLParser(Context context, ProgressListener progressListener)
{
mContext = context;
mProgressListener = progressListener;
mDbHelper = new DatabaseHelper(mContext);
mContentResolver = mContext.getContentResolver();
mStationsXMLParserProgressAdmin = new StationsXMLParserProgressAdmin();
}
protected InputStream getXMLInputStreamFromURL(String url) throws Exception{
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
mStationsXMLParserProgressAdmin.setContentLength(response.getEntity().getContentLength());
return response.getEntity().getContent();
}
public Uri importStationsFromXMLURL(String importXMLURL)
{
//This is more appropriate in the case of a tracks because there is a Uri associated with each one
//I return the uri of the whole stations table
Uri result = null;
InputStream XmlInputStream = null;
try
{
XmlInputStream = getXMLInputStreamFromURL(importXMLURL);
}
//TODO: Retrieve those string from resources
catch (UnsupportedEncodingException e) {
handleError(e, "XML opening exception");
} catch (MalformedURLException e) {
handleError(e, "XML opening exception");
} catch (IOException e) {
handleError(e, "XML opening exception");
}
catch (Exception e) {
handleError(e, "XML opening exception");
}
result = importStations(XmlInputStream);
return result;
}
//This is a one block for all stations right now, I'll probably cut it later
//to extract the import of only a single station (which will have an associated uri)
//It returns the stations uri if data have been read from input
public Uri importStations(InputStream xmlInputStream)
{
int eventType;
Uri result = null;
// <stations>
// <station>
// <id>1</id>
// <name>Notre Dame / Place Jacques Cartier</name>
// <terminalName>6001</terminalName>
// <lat>45.508183</lat>
// <long>-73.554094</long>
// <installed>true</installed>
// <locked>false</locked>
// <installDate>1276012920000</installDate>
// <removalDate />
// <temporary>false</temporary>
// <nbBikes>14</nbBikes>
// <nbEmptyDocks>17</nbEmptyDocks>
// </station>
// <station>
// ...
// </station>
// </stations>
try
{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//factory.setNamespaceAware(true);
XmlPullParser xmlParser = factory.newPullParser();
ProgressFilterInputStream pfis = new ProgressFilterInputStream(xmlInputStream, mStationsXMLParserProgressAdmin);
BufferedInputStream bis = new BufferedInputStream(pfis);
UnicodeReader ur = new UnicodeReader(bis, "UTF-8");
xmlParser.setInput(ur);
eventType = xmlParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT)
{
xmlParser.next();
eventType = xmlParser.getEventType();
if(eventType == XmlPullParser.START_TAG && xmlParser.getName().equals("stations"))
{
mDbHelper.dropStationsTable();
mDbHelper.createStationsTable();
}
if(xmlParser.getName().equals("station"))
{
ContentValues stationContent = new ContentValues();
xmlParser.next(); //will now be positioned on station ID
eventType = xmlParser.getEventType();
while ( eventType != XmlPullParser.END_DOCUMENT && !xmlParser.getName().equals("station") )
{
if(eventType == XmlPullParser.START_TAG && xmlParser.getName().equals("id"))
{
xmlParser.next(); //to get to TEXT
String stationID = xmlParser.getText();
xmlParser.next(); //END TAG
xmlParser.next(); //START TAG
eventType = xmlParser.getEventType();
stationContent.put(Stations._ID, stationID);
}
else if(eventType == XmlPullParser.START_TAG && xmlParser.getName().equals("name"))
{
xmlParser.next(); //to get to TEXT
String stationName = xmlParser.getText();
xmlParser.next(); //END TAG
xmlParser.next(); //START TAG
eventType = xmlParser.getEventType();
stationContent.put(Stations.NAME, stationName);
}
else if(eventType == XmlPullParser.START_TAG && xmlParser.getName().equals("lat"))
{
xmlParser.next(); //to get to TEXT
String stationLat = xmlParser.getText();
xmlParser.next(); //END TAG
xmlParser.next(); //START TAG
eventType = xmlParser.getEventType();
stationContent.put(Stations.LATITUDE, stationLat);
}
else if(eventType == XmlPullParser.START_TAG && xmlParser.getName().equals("long"))
{
xmlParser.next(); //to get to TEXT
String stationLong = xmlParser.getText();
xmlParser.next(); //END TAG
xmlParser.next(); //START TAG
eventType = xmlParser.getEventType();
stationContent.put(Stations.LONGITUDE, stationLong);
}
else
{
xmlParser.next();
eventType = xmlParser.getEventType();
while(eventType != XmlPullParser.START_TAG && !(eventType == XmlPullParser.END_TAG && xmlParser.getName().equals("station")))
{
xmlParser.next();
eventType = xmlParser.getEventType();
}
}
if(stationContent.size() == 4)
//I should have a complete station now
{
//This returns the URI
mContentResolver.insert(Stations.CONTENT_URI, stationContent);
stationContent.clear();
}
}
}
else if(eventType == XmlPullParser.END_TAG) //we were on the stations end, we need to do a next to reach the end of the document
{
xmlParser.next();
eventType = xmlParser.getEventType();
}
}
result = Stations.CONTENT_URI;
}
catch (XmlPullParserException e)
{
handleError(e, "error while creating XML parser");
}
catch (IOException e)
{
handleError(e, "error while creating XML parser");
}
return result;
}
/**
*
* @param dialogException
* @param dialogErrorMessage
*/
protected void handleError(Exception dialogException, String dialogErrorMessage)
{
Log.e(TAG, "Unable to save ", dialogException);
mErrorDialogException = dialogException;
mErrorDialogMessage = dialogErrorMessage;
cancel(false);
throw new CancellationException(dialogErrorMessage);
}
@Override
protected Uri doInBackground(String... params) {
String url = params[0];
return importStationsFromXMLURL(url);
}
@Override
protected void onPreExecute()
{
mProgressListener.started();
}
@Override
protected void onProgressUpdate(Void... values)
{
mProgressListener.setProgress(mStationsXMLParserProgressAdmin.getProgress());
}
@Override
protected void onPostExecute(Uri result)
{
mProgressListener.finished(result);
}
@Override
protected void onCancelled()
{
//mProgressListener.showError(mContext.getString(R.string.taskerror_gpx_import), mErrorDialogMessage, mErrorDialogException);
mProgressListener.showError("oups", mErrorDialogMessage, mErrorDialogException);
}
public class StationsXMLParserProgressAdmin extends ByteProgressAdmin
{
public void addBytesProgress(int addedBytes)
{
super.addBytesProgress(addedBytes);
considerPublishProgress();
}
@Override
public void considerPublishProgress()
{
if(mustPublishProgress())
{
publishProgress();
}
}
}
}