/**
* 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.editor.model;
import com.google.inject.Singleton;
import es.eucm.ead.importer.annotation.ImportAnnotator;
import es.eucm.ead.model.elements.BasicElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* An annotator that can be used to build EditorNodes.
* @author mfreire
*/
@Singleton
public class EditorAnnotator implements ImportAnnotator {
private static final Logger logger = LoggerFactory
.getLogger(EditorAnnotator.class);
private ArrayList<BasicElement> stack = new ArrayList<BasicElement>();
private HashMap<BasicElement, ArrayList<Annotation>> annotations = new HashMap<BasicElement, ArrayList<Annotation>>();
private HashMap<BasicElement, HashSet<BasicElement>> children = new HashMap<BasicElement, HashSet<BasicElement>>();
public EditorAnnotator() {
logger.warn("warning level enabled");
logger.info("info level enabled");
logger.debug("debug level enabled");
}
public class Annotation {
private ArrayList<BasicElement> context = new ArrayList<BasicElement>();
private ImportAnnotator.Type type;
private Object key;
private Object value;
private Annotation(ImportAnnotator.Type type, Object key, Object value) {
context.addAll(stack);
this.type = type;
this.key = key;
this.value = value;
}
public ArrayList<BasicElement> getContext() {
return context;
}
public ImportAnnotator.Type getType() {
return type;
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
}
public static class PlaceHolder extends BasicElement {
private String id;
private PlaceHolder(String id) {
this.id = id;
}
@Override
public boolean equals(Object obj) {
return (obj != null && ((PlaceHolder) obj).id.equals(id));
}
@Override
public int hashCode() {
return this.id.hashCode();
}
@Override
public String getId() {
return id;
}
@Override
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "<" + id + ">";
}
}
public void reset() {
stack.clear();
annotations.clear();
}
/**
* Ids may be changed by the editor; this makes sure that the 'get'
* operations works with updated ids.
*/
public void rebuild() {
HashMap<BasicElement, ArrayList<Annotation>> annotationBackup = new HashMap<BasicElement, ArrayList<Annotation>>();
annotationBackup.putAll(annotations);
annotations = annotationBackup;
HashMap<BasicElement, HashSet<BasicElement>> childrenBackup = new HashMap<BasicElement, HashSet<BasicElement>>();
childrenBackup.putAll(children);
for (Map.Entry<BasicElement, HashSet<BasicElement>> p : children
.entrySet()) {
HashSet<BasicElement> set = new HashSet<BasicElement>();
set.addAll(p.getValue());
p.setValue(set);
}
}
private static final ArrayList<Annotation> emptyAnnotations = new ArrayList<Annotation>();
public ArrayList<Annotation> get(BasicElement element) {
ArrayList<Annotation> al = annotations.get(element);
return (al != null) ? al : emptyAnnotations;
}
/**
* Returns all elements with 'element' as their direct
* context-ancestor
* @param element
* @return
*/
private static final HashSet<BasicElement> emptyChildren = new HashSet<BasicElement>();
public HashSet<BasicElement> getChildren(BasicElement element) {
HashSet<BasicElement> rc = children.get(element);
return (rc != null) ? rc : emptyChildren;
}
/**
* Returns all values of annotations on an element with Key.Role
* starting with typePrefix.
* @param element
* @param typePrefix
* @return
*/
public HashSet<String> get(BasicElement element, String typePrefix) {
HashSet<String> results = new HashSet<String>();
for (Annotation a : get(element)) {
String v = a.getValue().toString();
if (a.getType().equals(Type.Entry)) {
logger.debug("evaluating {}::{} vs {}", new Object[] {
a.getKey(), a.getValue(), typePrefix });
if (a.getKey().equals(Key.Role) && v.startsWith(typePrefix)) {
results.add(v);
}
}
}
return results;
}
@Override
public void annotate(Type key, Object... values) {
annotate(stack.get(stack.size() - 1), key, values);
}
@Override
public void annotate(BasicElement element, Type key, Object... values) {
if (element == null) {
element = new PlaceHolder(values[0].toString());
}
if (!stack.isEmpty()) {
BasicElement parent = stack.get(stack.size() - 1);
HashSet<BasicElement> cs = children.get(parent);
if (cs == null) {
cs = new HashSet<BasicElement>();
children.put(parent, cs);
}
cs.add(element);
}
switch (key) {
case Open: {
logger.debug("Entering {}", element);
stack.add(element);
break;
}
case Close: {
logger.debug("Exiting {}", element);
int i = stack.lastIndexOf(element);
if (i < 0) {
logger.error(
"Exiting {} -- no such element currently open in {}",
new Object[] { element, stack });
} else if (i != stack.size() - 1) {
logger.error("Exiting {} -- element is not last in {}",
new Object[] { element, stack });
stack.remove(i);
} else {
stack.remove(i);
}
break;
}
case Comment: {
if (!annotations.containsKey(element)) {
annotations.put(element, new ArrayList<Annotation>());
}
for (Object o : values) {
annotations.get(element).add(
new Annotation(key, Type.Comment.name(), o.toString()));
}
logger.debug("Commenting {}({}) with {}: {} --> {}", new Object[] {
element, stack, key, Type.Comment.name(), values[0] });
break;
}
default: {
if (!annotations.containsKey(element)) {
annotations.put(element, new ArrayList<Annotation>());
}
annotations.get(element).add(
new Annotation(key, values[0], values[1]));
logger.debug("Annotating {}({}) with {}: {} --> {}", new Object[] {
element, stack, key, values[0], values[1] });
}
}
}
}