/*******************************************************************************
* Copyright (c) 2010 Denis Solonenko.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Denis Solonenko - initial API and implementation
******************************************************************************/
package ru.orangesoftware.financisto2.backup;
import android.content.ContentValues;
import android.content.Context;
import android.util.Log;
import com.google.android.gms.drive.DriveContents;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackInputStream;
import java.util.zip.GZIPInputStream;
import ru.orangesoftware.financisto2.db.CategoryRepository;
import ru.orangesoftware.financisto2.db.Database;
import ru.orangesoftware.financisto2.db.DatabaseAdapter;
import ru.orangesoftware.financisto2.db.DatabaseSchemaEvolution;
import ru.orangesoftware.financisto2.export.Export;
import ru.orangesoftware.financisto2.export.dropbox.Dropbox;
import ru.orangesoftware.financisto2.model.AccountType;
import ru.orangesoftware.financisto2.model.ElectronicPaymentType;
public class DatabaseImport extends FullDatabaseImport {
private static final int FINANCISTO1_VERSION = 100;
private final DatabaseSchemaEvolution schemaEvolution;
private final InputStream backupStream;
public static DatabaseImport createFromFileBackup(Context context, DatabaseAdapter db, CategoryRepository categoryRepository, String backupFile) throws FileNotFoundException {
File backupPath = Export.getBackupFolder(context);
File file = new File(backupPath, backupFile);
FileInputStream inputStream = new FileInputStream(file);
return new DatabaseImport(context, db, categoryRepository, inputStream);
}
public static DatabaseImport createFromGoogleDriveBackup(Context context, DatabaseAdapter db, CategoryRepository categoryRepository, DriveContents driveFileContents)
throws IOException {
InputStream inputStream = driveFileContents.getInputStream();
InputStream in = new GZIPInputStream(inputStream);
return new DatabaseImport(context, db, categoryRepository, in);
}
public static DatabaseImport createFromDropboxBackup(Context context, DatabaseAdapter db, CategoryRepository categoryRepository, Dropbox dropbox, String backupFile)
throws Exception {
InputStream inputStream = dropbox.getFileAsStream(backupFile);
InputStream in = new GZIPInputStream(inputStream);
return new DatabaseImport(context, db, categoryRepository, in);
}
private DatabaseImport(Context context, DatabaseAdapter db, CategoryRepository categoryRepository, InputStream backupStream) {
super(context, db, categoryRepository);
this.schemaEvolution = new DatabaseSchemaEvolution(context, Database.DATABASE_NAME, null, Database.DATABASE_VERSION);
this.backupStream = backupStream;
}
@Override
protected void restoreDatabase() throws IOException {
InputStream s = decompressStream(backupStream);
InputStreamReader isr = new InputStreamReader(s, "UTF-8");
BufferedReader br = new BufferedReader(isr, 65535);
try {
recoverDatabase(br);
} finally {
br.close();
}
}
private InputStream decompressStream(InputStream input) throws IOException {
PushbackInputStream pb = new PushbackInputStream(input, 2);
byte[] bytes = new byte[2];
pb.read(bytes);
pb.unread(bytes);
int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
if (GZIPInputStream.GZIP_MAGIC == head) {
return new GZIPInputStream(pb);
} else {
return pb;
}
}
private void recoverDatabase(BufferedReader br) throws IOException {
boolean insideEntity = false;
ContentValues values = new ContentValues();
String line;
String tableName = null;
boolean isFinancisto1 = false;
while ((line = br.readLine()) != null) {
if (line.startsWith("VERSION_CODE:")) {
int i = line.indexOf(":");
if (i > 0) {
String value = line.substring(i + 1);
int version = Integer.parseInt(value);
isFinancisto1 = version <= FINANCISTO1_VERSION;
}
} else if (line.startsWith("$")) {
if ("$$".equals(line)) {
if (tableName != null && values.size() > 0) {
if (shouldRestoreTable(tableName)) {
cleanupValues(tableName, values);
if (values.size() > 0) {
sqlDb.insert(tableName, null, values);
}
}
tableName = null;
insideEntity = false;
}
} else {
int i = line.indexOf(":");
if (i > 0) {
tableName = line.substring(i+1);
insideEntity = true;
values.clear();
}
}
} else {
if (insideEntity) {
int i = line.indexOf(":");
if (i > 0) {
String columnName = line.substring(0, i);
String value = line.substring(i+1);
values.put(columnName, value);
}
}
}
}
}
private boolean shouldRestoreTable(String tableName) {
if ("locations".equals(tableName)) return false;
return true;
}
private void cleanupValues(String tableName, ContentValues values) {
// remove system entities
Integer id = values.getAsInteger("_id");
if (id != null && id <= 0) {
Log.w("Financisto", "Removing system entity: "+values);
values.clear();
return;
}
// fix columns
if ("transactions".equals(tableName)) {
values.remove("location_id");
values.remove("provider");
values.remove("accuracy");
values.remove("latitude");
values.remove("longitude");
} else if ("category".equals(tableName)) {
values.remove("last_location_id");
values.remove("sort_order");
} else if ("account".equals(tableName)) {
values.remove("sort_order");
String type = values.getAsString("type");
if ("PAYPAL".equals(type)) {
values.put("type", AccountType.ELECTRONIC.name());
values.put("card_issuer", ElectronicPaymentType.PAYPAL.name());
}
}
}
}