package com.boardgamegeek.export;
import android.Manifest.permission;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import com.boardgamegeek.R;
import com.boardgamegeek.events.ExportFinishedEvent;
import com.boardgamegeek.util.FileUtils;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonIOException;
import com.google.gson.stream.JsonWriter;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import timber.log.Timber;
public class JsonExportTask extends ImporterExporterTask {
public JsonExportTask(Context context, boolean isAutoBackupMode) {
super(context, isAutoBackupMode);
}
@Override
protected Integer doInBackground(Void... params) {
int permissionCheck = ContextCompat.checkSelfPermission(context, permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck == PackageManager.PERMISSION_DENIED) {
Timber.i("No permissions to write to external storage");
return ERROR_STORAGE_ACCESS;
}
// Ensure external storage is available
if (!FileUtils.isExtStorageAvailable()) {
Timber.i("External storage is unavailable");
return ERROR_STORAGE_ACCESS;
}
// Ensure the export directory exists
File exportPath = FileUtils.getExportPath(isAutoBackupMode);
if (!exportPath.exists()) {
if (!exportPath.mkdirs()) {
Timber.i("Export path %s can't be created", exportPath);
return ERROR_STORAGE_ACCESS;
}
}
int stepIndex = 0;
for (Step exporter : steps) {
int result = export(exportPath, exporter, stepIndex);
stepIndex++;
if (result == ERROR || isCancelled()) {
return ERROR;
}
}
//TODO: auto-backup
// if (isAutoBackupMode) {
// // store current time = last backup time
// final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
// prefs.edit().putLong(KEY_LAST_BACKUP, System.currentTimeMillis()).commit();
// }
return SUCCESS;
}
@Override
protected void onPostExecute(@NonNull Integer result) {
@StringRes int messageId;
switch (result) {
case SUCCESS:
messageId = R.string.msg_export_success;
break;
case ERROR_STORAGE_ACCESS:
messageId = R.string.msg_export_failed_nosd;
break;
default:
messageId = R.string.msg_export_failed;
break;
}
EventBus.getDefault().post(new ExportFinishedEvent(messageId));
}
private int export(File exportPath, @NonNull Step step, int stepIndex) {
final Cursor cursor = step.getCursor(context);
if (cursor == null) {
return ERROR;
}
if (cursor.getCount() == 0) {
cursor.close();
return SUCCESS;
}
publishProgress(cursor.getCount(), 0, stepIndex);
File backup = new File(exportPath, step.getFileName());
try {
OutputStream out = new FileOutputStream(backup);
writeJsonStream(out, cursor, step, stepIndex);
} catch (@NonNull JsonIOException | IOException e) {
Timber.e(e, "JSON export failed");
return ERROR;
} finally {
cursor.close();
}
return SUCCESS;
}
private void writeJsonStream(@NonNull OutputStream out, @NonNull Cursor cursor, @NonNull Step step, int stepIndex) throws IOException {
int numTotal = cursor.getCount();
int numExported = 0;
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
writer.setIndent(" ");
writer.beginArray();
while (cursor.moveToNext()) {
if (isCancelled()) {
break;
}
step.writeJsonRecord(context, cursor, gson, writer);
publishProgress(numTotal, ++numExported, stepIndex);
}
writer.endArray();
writer.close();
}
}