/*******************************************************************************
* Copyright (c) 2008 SAP
* see https://research.qkal.sap.corp/mediawiki/index.php/CoMONET
*
* Date: $Date: 2009-06-17 18:01:56 +0200 (Mi, 17 Jun 2009) $
* Revision: $Revision: 7088 $
* Author: $Author: c5106462 $
*******************************************************************************/
package com.sap.furcas.runtime.parser.impl.context;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* implements a tree based structure to look up duplicates and missing references.
*/
public class Context {
/** The context element. */
private Object element;
/** The parent. */
private Context parent;
/** The contents. Does not have to be list, but makes it easier this way for testing */
private final List<Object> contents = new ArrayList<Object>();
/** The imported contexts. */
private final List<Object> importedContexts = new ArrayList<Object>();
private Collection<Context> childContexts;
private String[] tags;
// Only for root Context
/**
* Instantiates a new context.
*/
public Context() {
this.parent = null;
}
/**
* Instantiates a new context.
*
* @param element the element
* @param parent the parent
*/
private Context(Object element, Context parent) {
this();
this.parent = parent;
this.element = element;
this.parent.addChild(this);
}
/**
* @param context
*/
private void addChild(Context context) {
if (this.childContexts == null) {
this.childContexts = new ArrayList<Context>();
}
this.childContexts.add(context);
}
/**
* returns a new context which is a child of this context, adds the context to the map of elements to Contexts.
*
* @param element the element
* @param contextByElement the context by element
*
* @return the context
*/
public Context createContext(Object element) {
Context newContext = new Context(element, this);
return newContext;
}
/**
* Adds the element to this context.
*
* @param element the e
*/
public void add(Object element) {
contents.add(element);
}
/**
* Iterator.
*
* @return the context iterator
*/
public ContextIterator iterator() {
// special construction to iterate over own and imported contexts
return new ContextIterator(this, contents.iterator(), importedContexts);
}
/**
* Iterator getter for internal use only, keeps track of already traversed imported contexts.
*
* @param traversed the traversed
*
* @return the context iterator
*/
ContextIterator iterator(List<Context> traversed) {
return new ContextIterator(traversed, this, contents.iterator(), importedContexts);
}
/**
* Parent.
*
* @return the context
*/
public Context getParent() {
return parent;
}
/**
* Import context.
*
* @param c the c
*/
public void importContext(Context c) {
importedContexts.add(c);
}
/**
* Gets the element.
*
* @return the element
*/
public Object getElement() {
return element;
}
/**
* Gets the element.
*
* @return the element
*/
public void setElement(Object element) {
this.element = element;
}
@Override
public String toString() {
return this.element + " " + this.contents;
}
/**
* @return
*/
public Collection<Context> getChildContexts() {
return this.childContexts;
}
/**
* @param proxy
* @param realObject
*/
public void replaceElement(Object proxy, Object realObject) {
if (this.contents.remove(proxy)) {
contents.add(realObject);
}
}
/**
* recursive call to remove a whole subtree from the map, and remove the parent() relationships.
* @param childContext
* @param contextByElement
* @return all elements removed from subTree as a Set
*/
public static Set<Object> removeWithChildren(Context childContext) {
// initialize result HashSet and call recursive method.
Set<Object> resultSet = new HashSet<Object>();
removeWithChildren(childContext.getParent(), childContext, resultSet);
return resultSet;
}
private static void removeWithChildren(Context parentContext, Context childContext, Set<Object> deletedObjects) {
// recursively call for all sub contexts
Collection<Context> childSubContexts = childContext.childContexts;
if (childSubContexts != null) {
List<Context> toBeRemoved = new ArrayList<Context>();
for (Context subContext : childSubContexts) {
toBeRemoved.add(subContext);
}
// cannot remove while going through iterator, therefore removing here.
for (Context subContext : toBeRemoved) {
removeWithChildren(childContext, subContext, deletedObjects);
}
}
// add actual element of context for removal
deletedObjects.addAll(childContext.contents);
if (parentContext != null) {
parentContext.childContexts.remove(childContext);
parentContext.contents.remove(childContext.getElement());
// add elements in context for removal
deletedObjects.add(childContext.getElement());
childContext.parent = null;
}
}
/**
* @param proxy
*/
public void remove(Object proxy) {
this.contents.remove(proxy);
}
public String[] getTags() {
return tags;
}
public void setTags(String[] tags2) {
this.tags = tags2;
}
public List<Object> getElements() {
return contents;
}
}