/*
* 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.content;
import android.util.Log;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.catrobat.catroid.ProjectManager;
import org.catrobat.catroid.common.BroadcastSequenceMap;
import org.catrobat.catroid.common.BroadcastWaitSequenceMap;
import org.catrobat.catroid.common.Constants;
import org.catrobat.catroid.content.actions.BroadcastNotifyAction;
import java.util.ArrayList;
import java.util.HashMap;
public final class BroadcastHandler {
private static Multimap<String, String> actionsToRestartMap = ArrayListMultimap.create();
private static HashMap<Action, Script> actionScriptMap = new HashMap<>();
private static HashMap<Script, Sprite> scriptSpriteMap = new HashMap<>();
private static HashMap<String, Action> stringActionMap = new HashMap<>();
private static final String TAG = "BroadcastHandler";
private BroadcastHandler() {
throw new AssertionError();
}
public static void doHandleBroadcastEvent(Look look, String broadcastMessage) {
String sceneName = ProjectManager.getInstance().getSceneToPlay().getName();
if (!BroadcastSequenceMap.containsKey(broadcastMessage, sceneName)) {
return;
}
for (SequenceAction action : BroadcastSequenceMap.get(broadcastMessage, sceneName)) {
Script scriptOfAction = actionScriptMap.get(action);
if (!handleAction(action, scriptOfAction)) {
addOrRestartAction(look, action);
}
}
if (BroadcastWaitSequenceMap.containsKey(broadcastMessage, sceneName)) {
for (SequenceAction action : BroadcastWaitSequenceMap.get(broadcastMessage, sceneName)) {
addOrRestartAction(look, action);
}
if (BroadcastWaitSequenceMap.getCurrentBroadcastEvent() != null) {
BroadcastWaitSequenceMap.getCurrentBroadcastEvent().resetEventAndResumeScript();
}
}
}
public static void doHandleBroadcastFromWaiterEvent(Look look, BroadcastEvent event, String broadcastMessage) {
String sceneName = ProjectManager.getInstance().getSceneToPlay().getName();
if (!BroadcastSequenceMap.containsKey(broadcastMessage, sceneName)) {
return;
}
if (!BroadcastWaitSequenceMap.containsKey(broadcastMessage, sceneName)) {
addBroadcastMessageToBroadcastWaitSequenceMap(look, event, broadcastMessage);
} else {
if (BroadcastWaitSequenceMap.getCurrentBroadcastEvent() == event
&& BroadcastWaitSequenceMap.getCurrentBroadcastEvent() != null) {
for (SequenceAction action : BroadcastWaitSequenceMap.get(broadcastMessage, sceneName)) {
BroadcastWaitSequenceMap.getCurrentBroadcastEvent().resetNumberOfFinishedReceivers();
addOrRestartAction(look, action);
}
} else {
if (BroadcastWaitSequenceMap.getCurrentBroadcastEvent() != null) {
BroadcastWaitSequenceMap.getCurrentBroadcastEvent().resetEventAndResumeScript();
}
addBroadcastMessageToBroadcastWaitSequenceMap(look, event, broadcastMessage);
}
}
}
private static void addOrRestartAction(Look look, Action action) {
if (action.getActor() == null) {
if (!look.getActions().contains(action, false)) {
look.addAction(action);
}
} else {
if (!Look.actionsToRestartContains(action)) {
Look.actionsToRestartAdd(action);
}
}
}
private static void addBroadcastMessageToBroadcastWaitSequenceMap(Look look, BroadcastEvent event,
String broadcastMessage) {
ArrayList<SequenceAction> actionList = new ArrayList<SequenceAction>();
BroadcastWaitSequenceMap.setCurrentBroadcastEvent(event);
String sceneName = ProjectManager.getInstance().getSceneToPlay().getName();
for (SequenceAction action : BroadcastSequenceMap.get(broadcastMessage, sceneName)) {
SequenceAction broadcastWaitAction = ActionFactory.sequence(action,
ActionFactory.createBroadcastNotifyAction(event));
Script receiverScript = actionScriptMap.get(action);
actionScriptMap.put(broadcastWaitAction, receiverScript);
Sprite receiverSprite = scriptSpriteMap.get(receiverScript);
String actionName = broadcastWaitAction.toString() + Constants.ACTION_SPRITE_SEPARATOR + receiverSprite.getName() + receiverSprite.getScriptIndex(receiverScript);
stringActionMap.put(actionName, broadcastWaitAction);
if (!handleActionFromBroadcastWait(broadcastWaitAction)) {
event.raiseNumberOfReceivers();
actionList.add(broadcastWaitAction);
addOrRestartAction(look, broadcastWaitAction);
}
}
if (actionList.size() > 0) {
BroadcastWaitSequenceMap.put(sceneName, broadcastMessage, actionList);
}
}
private static boolean handleAction(Action action, Script scriptOfAction) {
Sprite spriteOfAction = scriptSpriteMap.get(scriptOfAction);
String actionToHandle = action.toString() + Constants.ACTION_SPRITE_SEPARATOR + spriteOfAction.getName() + spriteOfAction.getScriptIndex(scriptOfAction);
if (!actionsToRestartMap.containsKey(actionToHandle)) {
return false;
}
for (String actionString : actionsToRestartMap.get(actionToHandle)) {
Action actionOfLook = stringActionMap.get(actionString);
if (actionOfLook == null) {
Log.d(TAG, "Action of look is skipped with action: " + actionString + ". It is probably a BroadcastNotify-Action that must not be restarted yet");
continue;
}
if (actionOfLook.getActor() == null) {
return false;
}
Look.actionsToRestartAdd(actionOfLook);
}
return true;
}
private static boolean handleActionFromBroadcastWait(SequenceAction sequenceActionWithBroadcastNotifyAction) {
Action actualAction = sequenceActionWithBroadcastNotifyAction.getActions().get(0);
for (Sprite sprites : ProjectManager.getInstance().getCurrentProject().getSpriteListWithClones()) {
for (Action actionOfLook : sprites.look.getActions()) {
Action actualActionOfLook = null;
if (actionOfLook instanceof SequenceAction && ((SequenceAction) actionOfLook).getActions().size > 0) {
actualActionOfLook = ((SequenceAction) actionOfLook).getActions().get(0);
}
if (sequenceActionWithBroadcastNotifyAction == actionOfLook) {
((BroadcastNotifyAction) ((SequenceAction) actionOfLook).getActions().get(1)).getEvent()
.resetNumberOfFinishedReceivers();
sprites.look.actionsToRestartAdd(actionOfLook);
return true;
} else {
if (actualActionOfLook != null && actualActionOfLook == actualAction) {
((BroadcastNotifyAction) ((SequenceAction) actionOfLook).getActions().get(1)).getEvent()
.resetEventAndResumeScript();
sprites.look.actionsToRestartAdd(actionOfLook);
return false;
} else {
addOrRestartAction(sprites.look, sequenceActionWithBroadcastNotifyAction);
return false;
}
}
}
}
return false;
}
public static void clearActionMaps() {
actionsToRestartMap.clear();
actionScriptMap.clear();
stringActionMap.clear();
}
public static Multimap<String, String> getActionsToRestartMap() {
return actionsToRestartMap;
}
public static HashMap<Action, Script> getActionScriptMap() {
return actionScriptMap;
}
public static HashMap<Script, Sprite> getScriptSpriteMap() {
return scriptSpriteMap;
}
public static HashMap<String, Action> getStringActionMap() {
return stringActionMap;
}
}