package org.emdev.common.backup;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.emdev.BaseDroidApp;
import org.emdev.common.backup.BackupInfo.Type;
import org.emdev.common.filesystem.CompositeFilter;
import org.emdev.common.filesystem.FileExtensionFilter;
import org.emdev.common.filesystem.FilePrefixFilter;
import org.emdev.common.log.LogContext;
import org.emdev.common.log.LogManager;
import org.emdev.utils.LengthUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class BackupManager {
public static final LogContext LCTX = LogManager.root().lctx("BackupManager");
static File BACKUP_FOLDER = new File(BaseDroidApp.APP_STORAGE, "backups");
private static final FileExtensionFilter BACKUP_FILTER = new FileExtensionFilter("jso");
private static final CompositeFilter AUTO_BACKUP_FILTER = new CompositeFilter(true, new FilePrefixFilter(Type.AUTO
.name().toLowerCase() + "."), BACKUP_FILTER);
private static final Map<String, IBackupAgent> agents = new TreeMap<String, IBackupAgent>();
private static int maxNumberOfAutoBackups = 1;
public static void addAgent(final IBackupAgent agent) {
agents.put(agent.key(), agent);
}
public static Collection<BackupInfo> getAvailableBackups() {
final Set<BackupInfo> backups = new TreeSet<BackupInfo>();
BACKUP_FOLDER.mkdirs();
final File[] list = BACKUP_FILTER.listFiles(BACKUP_FOLDER);
for (final File f : list) {
try {
backups.add(new BackupInfo(f));
} catch (final Exception ex) {
}
}
return backups;
}
public static List<BackupInfo> getAutoBackups() {
final Set<BackupInfo> backups = new TreeSet<BackupInfo>();
BACKUP_FOLDER.mkdirs();
final File[] files = BACKUP_FOLDER.listFiles(AUTO_BACKUP_FILTER);
if (LengthUtils.isNotEmpty(files)) {
for (final File f : files) {
try {
backups.add(new BackupInfo(f));
} catch (final Exception ex) {
f.delete();
}
}
}
return new ArrayList<BackupInfo>(backups);
}
public static boolean backup() {
final List<BackupInfo> old = getAutoBackups();
if (backupImpl(new BackupInfo())) {
final int count = LengthUtils.length(old);
if (count + 1 > maxNumberOfAutoBackups) {
for (int i = maxNumberOfAutoBackups - 1; i < count; i++) {
remove(old.get(i));
}
}
return true;
}
return false;
}
public static boolean backup(final BackupInfo backup) {
if (backup.type == BackupInfo.Type.USER) {
return backupImpl(backup);
}
return false;
}
public static boolean restore(final BackupInfo backup) {
return restoreImpl(backup);
}
public static boolean remove(final BackupInfo backup) {
final File file = new File(BACKUP_FOLDER, backup.getFileName());
return file.delete();
}
static boolean backupImpl(final BackupInfo backup) {
try {
backup.timestamp = new Date();
final String json = buildBackup(backup);
BACKUP_FOLDER.mkdirs();
final File file = new File(BACKUP_FOLDER, backup.getFileName());
final BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write(json);
writer.close();
return true;
} catch (final Throwable th) {
LCTX.e("Unexpected error", th);
}
return false;
}
private static String buildBackup(final BackupInfo backup) throws JSONException {
final JSONObject root = backup.toJSON();
final JSONObject chunks = new JSONObject();
root.put("chunks", chunks);
for (final IBackupAgent agent : agents.values()) {
chunks.put(agent.key(), agent.backup());
}
return root.toString(2);
}
static boolean restoreImpl(final BackupInfo backup) {
final File file = new File(BACKUP_FOLDER, backup.getFileName());
if (!file.exists()) {
return false;
}
final Map<String, JSONObject> m = new HashMap<String, JSONObject>();
try {
final JSONObject root = BackupInfo.fromJSON(file);
final JSONObject chunks = root.optJSONObject("chunks");
final JSONArray names = chunks != null ? chunks.names() : null;
if (LengthUtils.isNotEmpty(names)) {
for (int i = 0, n = names.length(); i < n; i++) {
final String key = names.getString(i);
final JSONObject value = chunks.getJSONObject(key);
m.put(key, value);
}
}
} catch (final JSONException ex) {
LCTX.e("JSON parsing error: " + ex.getMessage());
return false;
}
for (final Map.Entry<String, JSONObject> e : m.entrySet()) {
final IBackupAgent agent = agents.get(e.getKey());
if (agent != null) {
agent.restore(e.getValue());
} else {
LCTX.w("No agent found: " + e.getKey());
}
}
return true;
}
public static int getMaxNumberOfAutoBackups() {
return maxNumberOfAutoBackups;
}
public static void setMaxNumberOfAutoBackups(int maxNumberOfAutoBackups) {
BackupManager.maxNumberOfAutoBackups = maxNumberOfAutoBackups;
}
}