aboutsummaryrefslogtreecommitdiff
path: root/src/org/happysanta/gd/Storage/LevelsManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/happysanta/gd/Storage/LevelsManager.java')
-rw-r--r--src/org/happysanta/gd/Storage/LevelsManager.java503
1 files changed, 503 insertions, 0 deletions
diff --git a/src/org/happysanta/gd/Storage/LevelsManager.java b/src/org/happysanta/gd/Storage/LevelsManager.java
new file mode 100644
index 0000000..697c9ff
--- /dev/null
+++ b/src/org/happysanta/gd/Storage/LevelsManager.java
@@ -0,0 +1,503 @@
+package org.happysanta.gd.Storage;
+
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.os.StatFs;
+import org.happysanta.gd.API.API;
+import org.happysanta.gd.API.DownloadFile;
+import org.happysanta.gd.API.DownloadHandler;
+import org.happysanta.gd.Callback;
+import org.happysanta.gd.DoubleCallback;
+import org.happysanta.gd.GDActivity;
+import org.happysanta.gd.Global;
+import org.happysanta.gd.Levels.LevelHeader;
+import org.happysanta.gd.Levels.Reader;
+import org.happysanta.gd.Menu.Menu;
+import org.happysanta.gd.Menu.MenuScreen;
+import org.happysanta.gd.R;
+import org.happysanta.gd.Settings;
+import org.acra.ACRA;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import static org.happysanta.gd.Helpers.getGDActivity;
+import static org.happysanta.gd.Helpers.getGameMenu;
+import static org.happysanta.gd.Helpers.getString;
+import static org.happysanta.gd.Helpers.getTimestamp;
+import static org.happysanta.gd.Helpers.isOnline;
+import static org.happysanta.gd.Helpers.logDebug;
+import static org.happysanta.gd.Helpers.showAlert;
+
+public class LevelsManager {
+
+ private LevelsDataSource dataSource;
+ private boolean dbOK = false;
+ private Level currentLevel;
+
+ public LevelsManager() {
+ GDActivity gd = getGDActivity();
+ dataSource = new LevelsDataSource(gd);
+
+ try {
+ dataSource.open();
+
+ if (!dataSource.isDefaultLevelCreated()) {
+ Level level = dataSource.createLevel("GDTR original", "Codebrew Software", 10, 10, 10, 0, 0, true, 1);
+ logDebug("LevelsManager: Default level created!");
+ logDebug(level);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ logDebug("LevelsManager: db feels bad :(");
+ // return;
+ }
+
+ logDebug("LevelsManager: db feels OK :)");
+
+ // Shared prefs
+ // SharedPreferences settings = getSharedPreferences();
+ // long levelId = settings.getLong(PREFS_LEVEL_ID, 0);
+ long levelId = Settings.getLevelId();
+ if (levelId < 1 || !mrgIsAvailable(levelId)) {
+ logDebug("LevelsManager: levelId = " + levelId + ", < 1 or mrg is not available; now: reset id");
+ /*SharedPreferences.Editor editor = settings.edit();
+ editor.putLong(PREFS_LEVEL_ID, 1);
+ editor.commit();*/
+ resetId();
+ }
+
+ reload();
+ dbOK = true;
+ }
+
+ public void resetId() {
+ Settings.setLevelId(1);
+ }
+
+ public void reload() {
+ long id = Settings.getLevelId();
+ currentLevel = dataSource.getLevel(id);
+
+ if (currentLevel == null) {
+ logDebug("LevelsManager: failed to load currentLevel; currentId = " + id);
+ } else {
+ logDebug("LevelsManager: level = " + currentLevel);
+ }
+
+ if (Global.ACRA_ENABLED) {
+ ACRA.getErrorReporter().putCustomData("level_api_id:", String.valueOf(currentLevel.getApiId()));
+ }
+ }
+
+ public void closeDataSource() {
+ dataSource.close();
+ }
+
+ public long getCurrentId() {
+ return currentLevel.getId();
+ }
+
+ public void setCurrentId(long id) {
+ // currentId = id;
+ Settings.setLevelId(id);
+ /*SharedPreferences settings = getSharedPreferences();
+ SharedPreferences.Editor edit = settings.edit();
+ edit.putLong(PREFS_LEVEL_ID, id);
+ edit.commit();*/
+ }
+
+ public Level getCurrentLevel() {
+ return currentLevel;
+ }
+
+ public File getCurrentLevelsFile() {
+ if (currentLevel.getId() > 1)
+ return getMrgFileById(currentLevel.getId());
+
+ return null;
+ }
+
+ private boolean mrgIsAvailable(long id) {
+ if (id == 1) // This is default built-in levels.mrg
+ return true;
+
+ File file = getMrgFileById(id);
+ return isExternalStorageReadable() && file.exists();
+ }
+
+ public boolean isDbOK() {
+ return dbOK;
+ }
+
+ public long install(File file, String name, String author, long apiId) throws Exception {
+ if (!isSpaceAvailable(file.length())) {
+ throw new Exception(getString(R.string.e_no_space_left));
+ }
+
+ InputStream inputStream = new FileInputStream(file);
+ LevelHeader header = Reader.readHeader(inputStream);
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+
+ if (!header.isCountsOk()) {
+ throw new IOException(file.getName() + " is not valid");
+ }
+
+ Level level = dataSource.createLevel(name, author, header.getCount(0), header.getCount(1), header.getCount(2), 0, getTimestamp(), false, apiId);
+ long id = level.getId();
+ if (id < 1) {
+ throw new Exception(getString(R.string.e_cannot_save_level));
+ }
+
+ File newFile = getMrgFileById(id);
+ copy(file, newFile);
+
+ return id;
+ }
+
+ public void installAsync(File file, String name, String author, long apiId, final DoubleCallback callback) {
+ GDActivity gd = getGDActivity();
+ final ProgressDialog progressDialog = ProgressDialog.show(gd, getString(R.string.install), getString(R.string.installing), true);
+
+ new AsyncInstallLevel() {
+ @Override
+ protected void onPostExecute(Object result) {
+ progressDialog.dismiss();
+
+ if (result instanceof Throwable) {
+ Throwable throwable = (Throwable) result;
+ throwable.printStackTrace();
+ showAlert(getString(R.string.error), throwable.getMessage(), null);
+ if (callback != null)
+ callback.onFail();
+ return;
+ }
+
+ if (callback != null)
+ callback.onDone((long) result);
+ }
+ }.execute(file, name, author, apiId);
+ }
+
+ public void load(Level level) throws RuntimeException {
+ /*File file = getMrgFileById(level.getId());
+ if (!mrgIsAvailable(level.getId())) {
+ throw new RuntimeException("Unable to load levels \"" +level.getName() + "\"");
+ }*/
+
+ // Loader loader = getLevelLoader();
+ // Menu menu = getGameMenu();
+
+ // loader.setLevelsFile(file);
+ // menu.reloadLevels();
+
+ setCurrentId(level.getId());
+ getGDActivity().restartApp();
+ }
+
+ public boolean isApiIdInstalled(long apiId) {
+ return dataSource.isApiIdInstalled(apiId);
+ }
+
+ public Level[] getInstalledLevels(int offset, int count) {
+ return dataSource.getLevels(offset, count).toArray(new Level[0]);
+ }
+
+ public Level getLeveL(long id) {
+ return dataSource.getLevel(id);
+ }
+
+ public Level[] getAllInstalledLevels() {
+ return dataSource.getAllLevels().toArray(new Level[0]);
+ }
+
+ public synchronized HashMap<String, Double> getLevelsStat() {
+ Level[] levels = getAllInstalledLevels();
+ HashMap<String, Double> stat = new HashMap<>();
+ if (levels.length > 0) {
+ for (Level level : levels) {
+ int[] completed = level.getUnlockedAll();
+ int completedCount = 0;
+ for (int i = 0; i < completed.length; i++) {
+ if (completed[i] < 0) completed[i] = 0;
+ completedCount += completed[i];
+ }
+
+ double totalCount = level.getCountEasy() + level.getCountMedium() + level.getCountHard();
+ double per = completedCount / totalCount * 100;
+
+ stat.put(String.valueOf(level.getApiId()), per);
+ }
+ }
+ return stat;
+ }
+
+ public void delete(Level level) {
+ dataSource.deleteLevel(level);
+ File file = getMrgFileById(level.getId());
+ try {
+ if (file.exists()) {
+ file.delete();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void deleteAsync(Level level, final Runnable callback) {
+ GDActivity gd = getGDActivity();
+ final ProgressDialog progressDialog = ProgressDialog.show(gd, getString(R.string.delete), getString(R.string.deleting), true);
+
+ new AsyncDeleteLevel() {
+ @Override
+ protected void onPostExecute(Void v) {
+ progressDialog.dismiss();
+ if (callback != null)
+ callback.run();
+ }
+ }.execute(level);
+ }
+
+ public void updateLevelSettings() {
+ dataSource.updateLevel(currentLevel);
+ }
+
+ public void downloadLevel(final Level level, final Callback successCallback) {
+ final GDActivity gd = getGDActivity();
+ File outputDir = gd.getCacheDir();
+
+ try {
+ boolean readable = isExternalStorageReadable();
+ if (!readable) {
+ throw new Exception(getString(R.string.e_external_storage_is_not_readable));
+ }
+
+ if (!isOnline()) {
+ throw new Exception(getString(R.string.e_no_network_connection));
+ }
+
+ if (!isSpaceAvailable(level.getSize())) {
+ throw new Exception(getString(R.string.e_no_space_left));
+ }
+
+ final File outputFile = File.createTempFile("levels" + level.getApiId(), "mrg", outputDir);
+ FileOutputStream out = new FileOutputStream(outputFile);
+
+ // logDebug("downloadLevel: 4");
+ // final API api = new API();
+ final ProgressDialog progress;
+ final DownloadFile downloadFile = new DownloadFile(API.getMrgURL(level.getApiId()), out);
+
+ progress = new ProgressDialog(gd);
+ progress.setMessage(getString(R.string.downloading));
+ progress.setIndeterminate(true);
+ progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progress.setCancelable(true);
+
+ final DownloadHandler handler = new DownloadHandler() {
+ @Override
+ public void onFinish(Throwable error) {
+ progress.dismiss();
+
+ if (error != null) {
+ // error.printStackTrace();
+ error.printStackTrace();
+ showAlert(getString(R.string.error), error.getMessage(), null);
+
+ outputFile.delete();
+ return;
+ }
+
+ // Install
+ installAsync(outputFile, level.getName(), level.getAuthor(), level.getApiId(), new DoubleCallback() {
+ @Override
+ public void onDone(Object... objects) {
+ long id = (long) objects[0];
+ outputFile.delete();
+
+ if (successCallback != null)
+ successCallback.onDone(id);
+ }
+
+ @Override
+ public void onFail() {
+ outputFile.delete();
+ }
+ });
+ }
+
+ @Override
+ public void onStart() {
+ progress.show();
+ }
+
+ @Override
+ public void onProgress(int pr) {
+ progress.setIndeterminate(false);
+ progress.setMax(100);
+ progress.setProgress(pr);
+ }
+ };
+ progress.setOnCancelListener(new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ downloadFile.cancel();
+ handler.onFinish(new InterruptedException(getString(R.string.e_downloading_was_interrupted)));
+ }
+ });
+
+ downloadFile.setDownloadHandler(handler);
+ downloadFile.start();
+ } catch (Exception e) {
+ showAlert(getString(R.string.error), e.getMessage(), null);
+ }
+ }
+
+ public void showSuccessfullyInstalledDialog() {
+ GDActivity gd = getGDActivity();
+ AlertDialog success = new AlertDialog.Builder(gd)
+ .setTitle(getString(R.string.installed))
+ .setMessage(getString(R.string.successfully_installed))
+ .setPositiveButton(getString(R.string.ok), null)
+ .setNegativeButton(getString(R.string.open_installed), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Menu menu = getGameMenu();
+ MenuScreen currentMenu = getGameMenu().getCurrentMenu(),
+ newMenu = menu.managerInstalledScreen;
+
+ if (currentMenu == menu.managerDownloadScreen || currentMenu.getNavTarget() == menu.managerDownloadScreen) {
+ menu.managerDownloadScreen.onHide(menu.managerScreen);
+ }
+
+ menu.setCurrentMenu(newMenu, false);
+ }
+ })
+ .create();
+ success.show();
+ }
+
+ public HashMap<Long, Long> findInstalledLevels(ArrayList<Long> apiIds) {
+ return dataSource.findInstalledLevels(apiIds);
+ }
+
+ public HighScores getHighScores(int level, int track) {
+ HighScores scores = dataSource.getHighScores(currentLevel.getId(), level, track);
+ // logDebug("LevelsManager.getHighScores: " + scores);
+ return scores;
+ }
+
+ public void saveHighScores(HighScores scores) {
+ dataSource.updateHighScores(scores);
+ }
+
+ public void clearHighScores() {
+ dataSource.clearHighScores(currentLevel.getId());
+ }
+
+ public void clearAllHighScores() {
+ dataSource.clearHighScores(0);
+ }
+
+ public void resetAllLevelsSettings() {
+ dataSource.resetAllLevelsSettings();
+
+ logDebug("All levels now: " + dataSource.getAllLevels());
+ logDebug("Level#1: " + dataSource.getLevel(1));
+ }
+
+ public static boolean isExternalStorageWritable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) ||
+ Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static File getLevelsDirectory() {
+ File file = new File(Environment.getExternalStorageDirectory(), "GDLevels");
+ if (!file.mkdirs()) {
+ logDebug("LevelsManager.getLevelsDirectory: directory not created");
+ }
+ return file;
+ }
+
+ public static String getMrgFileNameById(long id) {
+ return getLevelsDirectory().getAbsolutePath() + "/" + id + ".mrg";
+ }
+
+ public static File getMrgFileById(long id) {
+ if (id == 1) return null;
+ return new File(getMrgFileNameById(id));
+ }
+
+ public static void copy(File src, File dst) throws IOException {
+ InputStream in = new FileInputStream(src);
+ OutputStream out = new FileOutputStream(dst);
+
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+
+ in.close();
+ out.close();
+ }
+
+ public static boolean isSpaceAvailable(long bytes) {
+ StatFs stat = new StatFs(getLevelsDirectory().getPath());
+ long bytesAvailable = (long) stat.getBlockSize() * (long) stat.getAvailableBlocks();
+ return bytesAvailable >= bytes;
+ }
+
+ private class AsyncDeleteLevel extends AsyncTask<Level, Void, Void> {
+ @Override
+ protected Void doInBackground(Level... levels) {
+ delete(levels[0]);
+ return null;
+ }
+ }
+
+ private class AsyncInstallLevel extends AsyncTask<Object, Void, Object> {
+ @Override
+ protected Object doInBackground(Object... objects) {
+ File file = (File) objects[0];
+ String name = (String) objects[1];
+ String author = (String) objects[2];
+ long apiId = (long) objects[3];
+
+ long id = 0;
+ try {
+ id = install(file, name, author, apiId);
+ } catch (Throwable e) {
+ return e;
+ }
+
+ return id;
+ }
+ }
+
+}