/************************************************************************
* Copyright (c) 2014 IoT-Solutions e.U.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
************************************************************************/
package iot.jcypher.domain.mapping.surrogate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public abstract class AbstractDeferred implements IDeferred{
protected List<IDeferred> upInTree;
protected List<IDeferred> downInTree;
public AbstractDeferred() {
super();
this.downInTree = new ArrayList<IDeferred>();
this.upInTree = new ArrayList<IDeferred>();
}
@Override
public boolean isLeaf() {
return this.downInTree.isEmpty();
}
@Override
public boolean isRoot() {
return false;
}
@Override
public Iterator<IDeferred> nextUp() {
return this.upInTree.iterator();
}
@Override
public void addNextUpInTree(IDeferred deferred) {
if (!this.upInTree.contains(deferred)) {
this.upInTree.add(deferred);
((AbstractDeferred)deferred).addDownInTree(this);
}
}
public void addDownInTree(IDeferred dit) {
this.downInTree.add(dit);
}
@Override
public void modifiedBy(IDeferred changer) {
this.downInTree.remove(changer);
}
public void removeFromDownTree(IDeferred def) {
this.downInTree.remove(def);
}
public void removeFromUpTree(IDeferred def) {
this.upInTree.remove(def);
}
protected void modifyNextUp() {
for(IDeferred def :this.upInTree) {
def.modifiedBy(this);
}
}
@Override
public void breakLoops() {
LoopContext context = new LoopContext();
detectLoops(context);
}
private void detectLoops(LoopContext context) {
context.addToPath(this);
this.walkDown(context);
context.removePathElement(this);
}
private void walkDown(LoopContext context) {
int sz = this.downInTree.size();
for (int i = sz - 1; i >= 0; i--) {
IDeferred def = this.downInTree.get(i);
IDeferred lpc = context.findLoopConnector(def);
if (lpc != null) { // loop detected
this.removeFromDownTree(lpc);
((AbstractDeferred)lpc).removeFromUpTree(this);
} else { // continue walk down
((AbstractDeferred)def).detectLoops(context);
}
}
}
/***************************************/
private static class LoopContext {
private List<IDeferred> path;
public LoopContext() {
super();
this.path = new ArrayList<IDeferred>();
}
private void addToPath(IDeferred deferred) {
if (this.path.contains(deferred))
throw new RuntimeException("error in add to path");
this.path.add(deferred);
}
private void removePathElement(IDeferred deferred) {
int level = this.path.size() - 1;
IDeferred def = this.path.remove(level);
if (!deferred.equals(def))
throw new RuntimeException("error in remove from path");
}
private IDeferred findLoopConnector(IDeferred deferred) {
for (IDeferred def : this.path) {
if (def.equals(deferred)) {
return def;
}
}
return null;
}
/*******************************/
// private class PathElement {
// private IDeferred start;
//
// private PathElement(IDeferred start) {
// super();
// this.start = start;
// }
//
// }
}
}