/**
* eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the
* <e-UCM> research group.
*
* Copyright 2005-2010 <e-UCM> research group.
*
* You can access a list of all the contributors to eAdventure at:
* http://e-adventure.e-ucm.es/contributors
*
* <e-UCM> is a research group of the Department of Software Engineering
* and Artificial Intelligence at the Complutense University of Madrid
* (School of Computer Science).
*
* C Profesor Jose Garcia Santesmases sn,
* 28040 Madrid (Madrid), Spain.
*
* For more info please visit: <http://e-adventure.e-ucm.es> or
* <http://www.e-ucm.es>
*
* ****************************************************************************
*
* This file is part of eAdventure, version 2.0
*
* eAdventure is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* eAdventure 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with eAdventure. If not, see <http://www.gnu.org/licenses/>.
*/
package es.eucm.ead.importer.subconverters.effects;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import es.eucm.ead.importer.AdventureConverter;
import es.eucm.ead.importer.EAdElementsCache;
import es.eucm.ead.importer.ModelQuerier;
import es.eucm.ead.importer.StringsConverter;
import es.eucm.ead.importer.UtilsConverter;
import es.eucm.ead.importer.resources.ResourcesConverter;
import es.eucm.ead.importer.subconverters.conditions.ConditionsConverter;
import es.eucm.ead.importer.subconverters.effects.variables.ActivateFlagConverter;
import es.eucm.ead.importer.subconverters.effects.variables.DeactivateFlagConverter;
import es.eucm.ead.importer.subconverters.effects.variables.DecrementVarConverter;
import es.eucm.ead.importer.subconverters.effects.variables.IncrementVarConverter;
import es.eucm.ead.importer.subconverters.effects.variables.RandomEffectConverter;
import es.eucm.ead.importer.subconverters.effects.variables.SetValueConverter;
import es.eucm.ead.model.elements.BasicElement;
import es.eucm.ead.model.elements.conditions.Condition;
import es.eucm.ead.model.elements.conditions.EmptyCond;
import es.eucm.ead.model.elements.effects.ChangeSceneEf;
import es.eucm.ead.model.elements.effects.Effect;
import es.eucm.ead.model.elements.effects.EmptyEffect;
import es.eucm.ead.model.elements.effects.sceneelements.ChangeColorEf;
import es.eucm.ead.model.elements.effects.variables.ChangeFieldEf;
import es.eucm.ead.model.elements.extra.EAdList;
import es.eucm.ead.model.elements.operations.ElementField;
import es.eucm.ead.model.elements.scenes.SceneElement;
import es.eucm.eadventure.common.data.chapter.effects.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Singleton
public class EffectsConverter {
static private Logger logger = LoggerFactory
.getLogger(EffectsConverter.class);
private ResourcesConverter resourcesConverter;
private ModelQuerier modelQuerier;
private EAdElementsCache elementsCache;
private Map<Class<?>, EffectConverter<?>> converters;
private ConditionsConverter conditionConverter;
private StringsConverter stringsConverter;
private UtilsConverter utilsConverter;
private ElementField ghostEffectsVisible = new ElementField(
new BasicElement(AdventureConverter.EFFECTS_GHOST_ID),
SceneElement.VAR_VISIBLE);
public ChangeFieldEf showGhostEffects = new ChangeFieldEf(
ghostEffectsVisible, EmptyCond.TRUE);
public ChangeFieldEf hideGhostEffects = new ChangeFieldEf(
ghostEffectsVisible, EmptyCond.FALSE);
@Inject
public EffectsConverter(ModelQuerier modelQuerier,
ConditionsConverter conditionsConverter,
EAdElementsCache elementsCache, StringsConverter stringsConverter,
UtilsConverter utilsConverter, ResourcesConverter resourcesConverter) {
this.modelQuerier = modelQuerier;
this.conditionConverter = conditionsConverter;
this.elementsCache = elementsCache;
this.utilsConverter = utilsConverter;
this.stringsConverter = stringsConverter;
this.resourcesConverter = resourcesConverter;
modelQuerier.setEffectsConverter(this);
setConverters();
}
private void setConverters() {
converters = new HashMap<Class<?>, EffectConverter<?>>();
converters.put(MacroReferenceEffect.class, new TriggerMacroConverter(
modelQuerier, elementsCache));
ChangeSceneConverter changeSceneConverter = new ChangeSceneConverter(
this, modelQuerier);
converters.put(TriggerSceneEffect.class, changeSceneConverter);
converters.put(TriggerCutsceneEffect.class, changeSceneConverter);
converters.put(TriggerLastSceneEffect.class, changeSceneConverter);
converters.put(DeactivateEffect.class, new DeactivateFlagConverter(
modelQuerier));
converters.put(ActivateEffect.class, new ActivateFlagConverter(
modelQuerier));
converters.put(SetValueEffect.class,
new SetValueConverter(modelQuerier));
converters.put(IncrementVarEffect.class, new IncrementVarConverter(
modelQuerier));
converters.put(DecrementVarEffect.class, new DecrementVarConverter(
modelQuerier));
MoveEffectConverter moveEffectConverter = new MoveEffectConverter(
elementsCache);
converters.put(MoveNPCEffect.class, moveEffectConverter);
converters.put(MovePlayerEffect.class, moveEffectConverter);
converters.put(MoveObjectEffect.class, moveEffectConverter);
converters.put(WaitTimeEffect.class, new WaitConverter());
converters.put(HighlightItemEffect.class, new HighlightItemConverter(
elementsCache));
converters.put(TriggerConversationEffect.class,
new TriggerConversationConverter(modelQuerier));
SpeakEffectConverter speakConverter = new SpeakEffectConverter(
modelQuerier, stringsConverter, utilsConverter);
converters.put(ShowTextEffect.class, speakConverter);
converters.put(SpeakCharEffect.class, speakConverter);
converters.put(SpeakPlayerEffect.class, speakConverter);
converters.put(RandomEffect.class, new RandomEffectConverter(this));
converters.put(PlaySoundEffect.class, new PlaySoundConverter(
resourcesConverter));
// factoryMap.put(CancelActionEffect.class,
// CancelActionEffectImporter.class);
// factoryMap.put(ConsumeObjectEffect.class,
// ConsumeObjectEffectImporter.class);
// factoryMap.put(GenerateObjectEffect.class,
// GenerateObjectEffectImporter.class);
// factoryMap.put(MoveObjectEffect.class,
// MoveObjectEffectImporter.class);
// factoryMap.put(MovePlayerEffect.class,
// MovePlayerEffectImporter.class);
// factoryMap.put(PlayAnimationEffect.class,
// PlayAnimationEffectImporter.class);
// factoryMap
// .put(TriggerBookEffect.class, TriggerBookEffectImporter.class);
}
@SuppressWarnings( { "rawtypes", "unchecked" })
public List<Effect> convert(AbstractEffect e) {
EffectConverter converter = converters.get(e.getClass());
if (converter == null) {
logger.warn("No effect converter for {}", e.getClass());
} else {
List<Effect> effects = converter.convert(e);
for (Effect effect : effects) {
if (effect.getId() == null) {
effect.setId("ef#"
+ BasicElement.classToString(effect.getClass())
+ "$"
+ elementsCache.newReference(BasicElement
.classToString(effect.getClass())));
}
}
if (e.getConditions() != null) {
Condition cond = conditionConverter.convert(e.getConditions());
effects.get(0).setCondition(cond);
}
for (es.eucm.ead.model.elements.effects.Effect effect : effects) {
// Effects are always executed (conditions may prevent its
// execution later)
effect.setNextEffectsAlways(true);
}
return effects;
}
return Collections.emptyList();
}
public interface EffectConverter<T extends es.eucm.eadventure.common.data.chapter.effects.Effect> {
List<Effect> convert(T e);
}
/**
* Returns a list of effects. This effects are already concatenated one to
* the other, so most of cases you'll only need to use the first element of
* the list (For example, to add it to scene element with an addBehavior
* method)
* <p/>
* You'll also use the last effect of the list when you need to add more
* affects AFTER all the effects on the list has been executed
*
* @param ef
* @return
*/
public EAdList<Effect> convert(Effects ef) {
EAdList<Effect> effects = new EAdList<Effect>();
Effect effect = null;
for (AbstractEffect e : ef.getEffects()) {
List<Effect> nextEffects = convert(e);
if (nextEffects.size() > 0) {
effects.addAll(nextEffects);
if (effect != null) {
Effect nextEffect = simplifyEffects(nextEffects).get(0);
effect.addNextEffect(nextEffect);
}
effect = nextEffects.get(nextEffects.size() - 1);
}
}
boolean nextShow = false;
int i = 0;
for (Effect e : effects) {
if (i == 0) {
e.addSimultaneousEffect(showGhostEffects);
}
if (nextShow) {
nextShow = false;
e.addSimultaneousEffect(showGhostEffects);
}
if (e instanceof ChangeSceneEf) {
nextShow = true;
e.addNextEffect(hideGhostEffects);
}
if (i == effects.size() - 1) {
e.addNextEffect(hideGhostEffects);
}
i++;
}
return effects;
}
private List<Effect> simplifyEffects(List<Effect> nextEffects) {
if (nextEffects.size() < 2) {
return nextEffects;
}
int i = 0;
boolean hasNotQueue = false;
while (!hasNotQueue && i < nextEffects.size()) {
hasNotQueue = isNotQueueable(nextEffects.get(i++));
}
if (!hasNotQueue) {
return nextEffects;
}
ArrayList<Effect> list = new ArrayList<Effect>();
int index = 0;
while (i < nextEffects.size()) {
while (i < nextEffects.size()
&& isNotQueueable(nextEffects.get(i++))) {
;
if (i - index == 0) {
list.add(nextEffects.get(i));
} else {
if (i == 0 && i - index > 2) {
EmptyEffect effect = new EmptyEffect();
for (int j = i; j < index; j++) {
Effect e = nextEffects.get(j);
e.getNextEffects().clear();
effect.addNextEffect(e);
list.add(effect);
}
} else {
for (int j = i; j < index; j++) {
list.add(nextEffects.get(j));
}
}
}
index = i;
}
}
for (int j = index; j < i; j++) {
list.add(nextEffects.get(j));
}
return list;
}
private boolean isNotQueueable(Effect e) {
return e.getSimultaneousEffects().size() == 0
&& e.getNextEffects().size() == 1
&& (e instanceof ChangeFieldEf || e instanceof ChangeColorEf);
}
}