package app.android.gambit.ui;


import android.accounts.Account;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import app.android.gambit.R;
import app.android.gambit.local.DbProvider;
import app.android.gambit.remote.EntryNotFoundException;
import app.android.gambit.remote.FailedRequestException;
import app.android.gambit.remote.Synchronizer;
import app.android.gambit.remote.UnauthorizedException;


class SyncOperator extends AsyncTask<Void, Void, String>
{
	private final Context activityContext;
	private final Activity activity;

	private final Runnable successRunnable;

	private String documentsListAuthToken;
	private String spreadsheetsAuthToken;

	private boolean isTokensInvalidationEnabled;

	private ProgressDialogShowHelper progressDialogShowHelper;

	public SyncOperator(Context activityContext, Runnable successRunnable) {
		this.activityContext = activityContext;
		this.activity = (Activity) activityContext;

		this.successRunnable = successRunnable;

		isTokensInvalidationEnabled = false;
	}

	@Override
	protected void onPreExecute() {
		super.onPreExecute();

		progressDialogShowHelper = new ProgressDialogShowHelper();
		progressDialogShowHelper.show(activityContext, R.string.loading_sync);
	}

	@Override
	protected String doInBackground(Void... params) {
		String authorizationErrorMessage = authorize();
		if (!authorizationErrorMessage.isEmpty()) {
			return authorizationErrorMessage;
		}

		return sync();
	}

	private String authorize() {
		try {
			Account account = getAccount();

			getAuthTokens(account);
			if (isTokensInvalidationEnabled) {
				invalidateAuthTokens(account);
			}
		}
		catch (SignUpCanceledException e) {
			// Skip sign up cancel, user already knows that he did it
		}
		catch (SignUpFailedException e) {
			return activityContext.getString(R.string.error_network);
		}
		catch (AuthorizationCanceledException e) {
			// Skip revoking auth access, user already knows that he did it
		}
		catch (AuthorizationFailedException e) {
			return activityContext.getString(R.string.error_network);
		}

		return new String();
	}

	private Account getAccount() {
		try {
			return AccountSelector.select(activity);
		}
		catch (NoAccountRegisteredException e) {
			return AccountCreator.create(activity);
		}
	}

	private void getAuthTokens(Account account) {
		Authorizer authorizer = new Authorizer(activity);

		documentsListAuthToken = authorizer.getToken(Authorizer.ServiceType.DOCUMENTS_LIST, account);
		spreadsheetsAuthToken = authorizer.getToken(Authorizer.ServiceType.SPREADSHEETS, account);
	}

	private void invalidateAuthTokens(Account account) {
		Authorizer authorizer = new Authorizer(activity);

		authorizer.invalidateToken(documentsListAuthToken);
		authorizer.invalidateToken(spreadsheetsAuthToken);

		getAuthTokens(account);
	}

	private String sync() {
		try {
			if (!isSyncSpreadsheetKeyInPreferences()) {
				syncFirstTime();
			}
			else {
				syncNotFirstTime();
			}
		}
		catch (UnauthorizedException e) {
			if (!isTokensInvalidationEnabled) {
				// Run again and invalidate tokens
				isTokensInvalidationEnabled = true;
				doInBackground();
			}
			else {
				// Invalidation failed
				return activityContext.getString(R.string.error_unspecified);
			}
		}
		catch (EntryNotFoundException e) {
			// Run again and force find or create spreadsheet
			removeSyncSpreadsheetKey();
			return sync();
		}
		catch (FailedRequestException e) {
			return activityContext.getString(R.string.error_network);
		}

		return new String();
	}

	private boolean isSyncSpreadsheetKeyInPreferences() {
		return !loadSyncSpreadsheetKeyFromPreferences().isEmpty();
	}

	private String loadSyncSpreadsheetKeyFromPreferences() {
		return PreferencesOperator.get(activityContext,
			PreferencesOperator.PREFERENCE_SYNC_SPREADSHEET_KEY);
	}

	private void syncFirstTime() {
		Synchronizer synchronizer = new Synchronizer();

		String syncSpreadsheetKey;

		try {
			syncSpreadsheetKey = synchronizer.getExistingSpreadsheetKey(documentsListAuthToken);

			// Local storage is empty, so try to download remote
			if (DbProvider.getInstance().getDecks().getDecksCount() == 0) {
				synchronizer.syncFromRemoteToLocal(syncSpreadsheetKey, spreadsheetsAuthToken);
			}
		}
		catch (EntryNotFoundException e) {
			syncSpreadsheetKey = synchronizer.createSpreadsheet(documentsListAuthToken);

			// Remote storage is empty, so try to upload local
			synchronizer.syncFromLocalToRemote(syncSpreadsheetKey, spreadsheetsAuthToken);
		}

		saveSyncSpreadsheetKeyToPreferences(syncSpreadsheetKey);
	}

	private void saveSyncSpreadsheetKeyToPreferences(String syncSpreadsheetKey) {
		PreferencesOperator.set(activityContext, PreferencesOperator.PREFERENCE_SYNC_SPREADSHEET_KEY,
			syncSpreadsheetKey);
	}

	private void syncNotFirstTime() {
		Synchronizer synchronizer = new Synchronizer();
		synchronizer.synchronize(loadSyncSpreadsheetKeyFromPreferences(), spreadsheetsAuthToken);
	}

	private void removeSyncSpreadsheetKey() {
		PreferencesOperator.remove(activityContext,
			PreferencesOperator.PREFERENCE_SYNC_SPREADSHEET_KEY);
	}

	@Override
	protected void onPostExecute(String errorMessage) {
		super.onPostExecute(errorMessage);

		progressDialogShowHelper.hide();

		if (!errorMessage.isEmpty()) {
			UserAlerter.alert(activityContext, errorMessage);
		}
		else {
			successRunnable.run();
		}
	}
}
@@ -734,21 +734,22 @@
 lidation
-Enabl
+Requir
 ed;%0A%0A%09pr
@@ -1030,29 +1030,30 @@
 Invalidation
-Enabl
+Requir
 ed = false;%0A
@@ -1604,37 +1604,38 @@
 kensInvalidation
-Enabl
+Requir
 ed) %7B%0A%09%09%09%09invali
@@ -2885,18 +2885,20 @@
 %09%09%09if (!
-is
+have
 SyncSpre
@@ -3059,21 +3059,22 @@
 lidation
-Enabl
+Requir
 ed) %7B%0A%09%09
@@ -3138,13 +3138,14 @@
 tion
-Enabl
+Requir
 ed =
@@ -3407,16 +3407,31 @@
 sheetKey
+FromPreferences
 ();%0A%09%09%09r
@@ -3595,18 +3595,20 @@
 boolean 
-is
+have
 SyncSpre
@@ -5038,16 +5038,31 @@
 sheetKey
+FromPreferences
 () %7B%0A%09%09P

Rename some methods and fields in SyncOperator class.