/*
* Catroid: An on-device visual programming system for Android devices
* Copyright (C) 2010-2016 The Catrobat Team
* (<http://developer.catrobat.org/credits>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* An additional term exception under section 7 of the GNU Affero
* General Public License, version 3, is available at
* http://developer.catrobat.org/license_additional_term
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.catrobat.catroid.ui.controller;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.util.Log;
import org.catrobat.catroid.ProjectManager;
import org.catrobat.catroid.R;
import org.catrobat.catroid.common.Constants;
import org.catrobat.catroid.content.Scene;
import org.catrobat.catroid.content.Sprite;
import org.catrobat.catroid.content.bricks.Brick;
import org.catrobat.catroid.content.bricks.SceneStartBrick;
import org.catrobat.catroid.content.bricks.SceneTransitionBrick;
import org.catrobat.catroid.io.StorageHandler;
import org.catrobat.catroid.ui.dialogs.CustomAlertDialogBuilder;
import org.catrobat.catroid.ui.fragment.SceneListFragment;
import org.catrobat.catroid.utils.UtilFile;
import org.catrobat.catroid.utils.Utils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class BackPackSceneController {
public static final String TAG = BackPackSceneController.class.getSimpleName();
private static final BackPackSceneController INSTANCE = new BackPackSceneController();
private BackPackSceneController() {
}
public static BackPackSceneController getInstance() {
return INSTANCE;
}
public boolean checkScenesReplaceInBackpack(List<Scene> currentSceneList) {
for (Scene scene : currentSceneList) {
if (checkSceneReplaceInBackpack(scene)) {
return true;
}
}
return false;
}
public boolean checkSceneReplaceInBackpack(Scene currentScene) {
return BackPackListManager.getInstance().backPackedScenesContains(currentScene, true);
}
public void showBackPackReplaceDialog(final List<Scene> currentSceneList, final SceneListFragment fragment) {
final Context context = fragment.getActivity();
Resources resources = context.getResources();
String replaceSceneMessage;
if (currentSceneList.size() == 1) {
replaceSceneMessage = resources.getString(R.string.backpack_replace_scene, currentSceneList.get(0)
.getName());
} else {
replaceSceneMessage = resources.getString(R.string.backpack_replace_scene_multiple);
}
AlertDialog dialog = new CustomAlertDialogBuilder(context)
.setTitle(R.string.backpack)
.setMessage(replaceSceneMessage)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
fragment.showProgressCircle();
fragment.packScenes(currentSceneList);
}
}).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
fragment.clearCheckedItems();
dialog.dismiss();
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
fragment.clearCheckedItems();
}
}).create();
dialog.setCanceledOnTouchOutside(true);
dialog.show();
}
public boolean backpackScenes(List<Scene> scenes) {
StorageHandler.getInstance().saveProject(ProjectManager.getInstance().getCurrentProject());
ArrayList<Scene> hiddenScenes = new ArrayList<>();
ArrayList<Scene> backPackedScenes = new ArrayList<>();
Map<String, String> backPackedNameMap = new HashMap<>();
for (Scene sceneToEdit : scenes) {
String sceneName = sceneToEdit.getName();
BackPackListManager.getInstance().removeItemFromSceneBackPackByName(sceneName, false);
Scene backPackScene = backpack(sceneToEdit);
if (backPackScene == null) {
return false;
}
backPackedNameMap.put(sceneToEdit.getName(), backPackScene.getName());
backPackedScenes.add(backPackScene);
BackPackListManager.searchForHiddenScenes(backPackScene, hiddenScenes, false);
BackPackListManager.getInstance().addSceneToBackPack(backPackScene);
}
for (Scene scene : hiddenScenes) {
BackPackListManager.getInstance().removeItemFromSceneBackPackByName(scene.getName(), true);
Scene hiddenBackPackScene = backpack(scene);
if (hiddenBackPackScene == null) {
return false;
}
backPackedNameMap.put(scene.getName(), hiddenBackPackScene.getName());
BackPackListManager.getInstance().addSceneToHiddenBackpack(hiddenBackPackScene);
backPackedScenes.add(hiddenBackPackScene);
}
correctTransitionAndStartSceneBricksAfterPacking(backPackedScenes, backPackedNameMap);
return true;
}
public boolean backpackScene(Scene sceneToEdit) {
ArrayList<Scene> scenes = new ArrayList<>();
scenes.add(sceneToEdit);
return backpackScenes(scenes);
}
public Scene backpack(Scene sceneToEdit) {
File sourceScene = new File(Utils.buildScenePath(sceneToEdit.getProject().getName(), sceneToEdit.getName()));
File targetScene = new File(Utils.buildBackpackScenePath(sceneToEdit.getName()));
try {
StorageHandler.copyDirectory(targetScene, sourceScene);
} catch (IOException e) {
Log.e(TAG, "Error while backpacking Scene Files !", e);
UtilFile.deleteDirectory(targetScene);
return null;
}
Scene clonedScene = sceneToEdit.clone();
clonedScene.isBackPackScene = true;
clonedScene.setProject(null);
return clonedScene;
}
public List<Scene> unpackScenes(List<Scene> scenes) {
ArrayList<Scene> unpackedScenes = new ArrayList<>();
Map<String, String> unPackedNameMap = new HashMap<>();
ArrayList<Scene> hiddenScenesToUnpack = new ArrayList<>();
for (Scene selectedScene : scenes) {
Scene unpackedScene = unpack(selectedScene);
if (unpackedScene == null) {
return null;
}
unpackedScene.setProject(ProjectManager.getInstance().getCurrentProject());
unpackedScene.getDataContainer().setProject(ProjectManager.getInstance().getCurrentProject());
unpackedScenes.add(unpackedScene);
unPackedNameMap.put(selectedScene.getName(), unpackedScene.getName());
BackPackListManager.searchForHiddenScenes(selectedScene, hiddenScenesToUnpack, true);
}
clearHiddenScenesToUnpackFromAlreadyUnpacked(hiddenScenesToUnpack, scenes);
List<Scene> result = new ArrayList<>();
result.addAll(unpackedScenes);
Scene unpackedScene;
for (Scene scene : hiddenScenesToUnpack) {
unpackedScene = unpack(scene);
if (unpackedScene == null) {
return null;
}
unpackedScenes.add(unpackedScene);
unPackedNameMap.put(scene.getName(), unpackedScene.getName());
unpackedScene.setProject(ProjectManager.getInstance().getCurrentProject());
unpackedScene.getDataContainer().setProject(ProjectManager.getInstance().getCurrentProject());
}
correctTransitionAndStartSceneBricksAfterPacking(unpackedScenes, unPackedNameMap);
return result;
}
public Scene unpackScene(Scene selectedScene) {
ArrayList<Scene> scenes = new ArrayList<>();
scenes.add(selectedScene);
List<Scene> result = unpackScenes(scenes);
return result == null ? null : result.get(0);
}
public Scene unpack(Scene selectedScene) {
if (selectedScene == null) {
return null;
}
ProjectManager projectManager = ProjectManager.getInstance();
String newName = Utils.getUniqueSceneName(selectedScene.getName(), false);
File sourceScene = new File(Utils.buildBackpackScenePath(selectedScene.getName()));
File targetScene = new File(Utils.buildScenePath(projectManager.getCurrentProject().getName(), newName));
try {
StorageHandler.copyDirectory(targetScene, sourceScene);
UtilFile.deleteDirectory(new File(targetScene, Constants.PROJECTCODE_NAME));
} catch (IOException e) {
Log.e(TAG, "Error while unpacking Scene Files !", e);
UtilFile.deleteDirectory(targetScene);
return null;
}
Scene clonedScene = selectedScene.cloneForBackPack();
if (clonedScene == null) {
return null;
}
clonedScene.setSceneName(newName);
clonedScene.isBackPackScene = false;
clonedScene.setProject(projectManager.getCurrentProject());
clonedScene.getDataContainer().setProject(projectManager.getCurrentProject());
projectManager.addScene(clonedScene);
projectManager.setCurrentScene(clonedScene);
return clonedScene;
}
private void clearHiddenScenesToUnpackFromAlreadyUnpacked(ArrayList<Scene> hiddenScenes, List<Scene>
alreadyUnpacked) {
ArrayList<Scene> toRemove = new ArrayList<>();
for (Scene hiddenScene : hiddenScenes) {
for (Scene alreadyUnpackedScene : alreadyUnpacked) {
if (hiddenScene.getName().equals(alreadyUnpackedScene.getName())) {
toRemove.add(hiddenScene);
}
}
}
hiddenScenes.removeAll(toRemove);
}
private void correctTransitionAndStartSceneBricksAfterPacking(ArrayList<Scene> scenesToCorrect, Map<String, String> visibleHiddenMap) {
for (Scene scene : scenesToCorrect) {
for (Sprite sprite : scene.getSpriteList()) {
for (Brick brick : sprite.getListWithAllBricks()) {
if (brick instanceof SceneTransitionBrick) {
SceneTransitionBrick trans = (SceneTransitionBrick) brick;
trans.setSceneForTransition(visibleHiddenMap.get(trans.getSceneForTransition()));
}
if (brick instanceof SceneStartBrick) {
SceneStartBrick start = (SceneStartBrick) brick;
start.setSceneToStart(visibleHiddenMap.get(start.getSceneToStart()));
}
}
}
}
}
}