/FileExtraction/Java_unseen/labexp_osmtracker-android/app/src/main/java/net/osmtracker/osm/UploadToOpenStreetMapTask.java
package net.osmtracker.osm;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;

import net.osmtracker.OSMTracker;
import net.osmtracker.R;
import net.osmtracker.db.DataHelper;
import net.osmtracker.db.model.Track;
import net.osmtracker.util.DialogUtils;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;

/**
 * Uploads a GPX file to OpenStreetMap
 * 
 * @author Nicolas Guillaumin
 */
public class UploadToOpenStreetMapTask extends AsyncTask<Void, Void, Void> {

	private static final String TAG = UploadToOpenStreetMapTask.class.getSimpleName();
	
	/** Upload progress dialog */
	private ProgressDialog dialog;
	
	private final Activity activity;
	private final long trackId;
	
	/** OAuth consumer to sign the post request */
	private final CommonsHttpOAuthConsumer oAuthConsumer;
	
	/** File to export */
	private final File gpxFile;
	
	/** Filename to use when uploading */
	private final String filename;
	
	/** Track description */
	private final String description;
	
	/** Track tags */
	private final String tags;
	
	/** Track visibility */
	private final Track.OSMVisibility visibility;

	/**
	 * Error message, or text of the response returned by OSM
	 * if the request completed
	 */
	private String errorMsg;

	/**
	 * Either the HTTP result code, or -1 for an internal error
	 */
	private int resultCode = -1;
	
	private HttpPost request;
	private HttpResponse response;
	
	public UploadToOpenStreetMapTask(Activity activity,
			long trackId, CommonsHttpOAuthConsumer oAuthConsumer,
			File gpxFile, String filename,
			String description, String tags, Track.OSMVisibility visibility) {
		this.activity = activity;
		this.trackId = trackId;
		this.filename = filename;
		
		this.oAuthConsumer = oAuthConsumer;
		this.gpxFile = gpxFile;
		this.description = (description == null) ? "test" : description;
		this.tags = (tags == null) ? "test" : tags;
		this.visibility = (visibility == null) ? Track.OSMVisibility.Private : visibility;
	}
	
	@Override
	protected void onPreExecute() {
		try {
			// Prepare and OAuth-sign the request request
			request = new HttpPost(OpenStreetMapConstants.Api.Gpx.CREATE);
			oAuthConsumer.sign(request);
			
			final long totalSize = gpxFile.length();
			
			// Custom entity to display a progress bar while uploading
			MultipartEntity entity = new ProgressMultipartEntity(
					HttpMultipartMode.BROWSER_COMPATIBLE,
					Charset.defaultCharset(),
					new ProgressMultipartEntity.ProgressListener() {
				@Override
				public void transferred(long num) {
					dialog.incrementProgressBy((int) num);
					if (num >= totalSize) {
						// Finish sending. Switch to an indeterminate progress
						// dialog while the OSM server processes the request
						activity.runOnUiThread(new Runnable() {
							@Override
							public void run() {
						 		dialog.setIndeterminate(true);
						 		dialog.setCancelable(false);
								dialog.setTitle(activity.getResources().getString(R.string.osm_upload_waiting_response));
							}
						});
					}
					
				}
			});

			// API parameters
			entity.addPart(OpenStreetMapConstants.Api.Gpx.Parameters.FILE, new FileBody(gpxFile, filename, DataHelper.MIME_TYPE_GPX, Charset.defaultCharset().name()));
			entity.addPart(OpenStreetMapConstants.Api.Gpx.Parameters.DESCRIPTION, new StringBody(description, Charset.defaultCharset()));
			entity.addPart(OpenStreetMapConstants.Api.Gpx.Parameters.TAGS, new StringBody(tags, Charset.defaultCharset()));
			entity.addPart(OpenStreetMapConstants.Api.Gpx.Parameters.VISIBILITY, new StringBody(visibility.toString().toLowerCase(),Charset.defaultCharset()));
			request.setEntity(entity);
				
			// Display progress dialog
			dialog = new ProgressDialog(activity);
			dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
			dialog.setIndeterminate(false);
			dialog.setMax((int) totalSize);
			dialog.setTitle(
					activity.getResources().getString(R.string.osm_upload_sending)
					.replace("{0}", Long.toString(trackId)));
			dialog.setCancelable(false);
			dialog.show();

		} catch (Exception e) {
			Log.e(TAG, "onPreExecute() failed", e);
			errorMsg = e.getLocalizedMessage();
			cancel(true);
		}
	}
	
	@Override
	protected void onPostExecute(Void result) {
		switch (resultCode) {
		case -1:
			dialog.dismiss();
			// Internal error, the request didn't start at all
			DialogUtils.showErrorDialog(activity,
					activity.getResources().getString(R.string.osm_upload_error)
						+ ": " + errorMsg);
			break;
		case HttpStatus.SC_OK:
			dialog.dismiss();
			// Success ! Update database and close activity
			DataHelper.setTrackUploadDate(trackId, System.currentTimeMillis(), activity.getContentResolver());
			
			new AlertDialog.Builder(activity)
				.setTitle(android.R.string.dialog_alert_title)
				.setIcon(android.R.drawable.ic_dialog_info)
				.setMessage(R.string.osm_upload_sucess)
				.setCancelable(true)
				.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						activity.finish();
					}
				}).create().show();
			
			break;
		case HttpStatus.SC_UNAUTHORIZED:
			dialog.dismiss();
			// Authorization issue. Provide a way to clear credentials
			new AlertDialog.Builder(activity)
					.setTitle(android.R.string.dialog_alert_title)
					.setIcon(android.R.drawable.ic_dialog_alert)
					.setMessage(R.string.osm_upload_unauthorized)
					.setCancelable(true)
					.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();								
						}
					})
					.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							Editor editor = PreferenceManager.getDefaultSharedPreferences(activity).edit();
							editor.remove(OSMTracker.Preferences.KEY_OSM_OAUTH_TOKEN);
							editor.remove(OSMTracker.Preferences.KEY_OSM_OAUTH_SECRET);
							editor.commit();

							dialog.dismiss();
						}
					}).create().show();

		default:
			// Another error. Display OSM response
			BufferedReader reader = null;
			try {
				reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(response.getEntity().getContent())));
				StringBuilder sb = new StringBuilder();
				String line = null;
				while ( (line = reader.readLine()) != null) {
					sb.append(line).append(System.getProperty("line.separator"));
				}
				
				dialog.dismiss();
				
				DialogUtils.showErrorDialog(activity,
						activity.getResources().getString(R.string.osm_upload_bad_response)
							.replace("{0}", Integer.toString(resultCode))
							.replace("{1}", sb.toString()));
			} catch (IOException ioe) {
				DialogUtils.showErrorDialog(activity, activity.getResources().getString(R.string.osm_upload_error) + ": " + ioe);
			} finally {
				if (dialog.isShowing()) {
					dialog.dismiss();
				}
				
				if (reader != null) {
					try { reader.close(); }
					catch (IOException ioe) { }
				}
			}
		}
	}

	@Override
	protected Void doInBackground(Void... params) {
		try {
			// Post request and get response code
			DefaultHttpClient httpClient = new DefaultHttpClient();
			response = httpClient.execute(request);
			resultCode = response.getStatusLine().getStatusCode();
		} catch (Exception e) {
			Log.e(TAG, "doInBackground failed", e);
			errorMsg = e.getLocalizedMessage();
		}
		
		return null;
	}
}
