/*
* Copyright (C) 2011 eXo Platform SAS.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.portal.mop.navigation;
import org.exoplatform.portal.mop.Utils;
import org.exoplatform.portal.tree.diff.Adapters;
import org.exoplatform.portal.tree.diff.HierarchyAdapter;
import org.exoplatform.portal.tree.diff.HierarchyChangeIterator;
import org.exoplatform.portal.tree.diff.HierarchyChangeType;
import org.exoplatform.portal.tree.diff.HierarchyDiff;
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
*/
class TreeUpdate<N1, N2> {
static <N1, N2> void perform(TreeContext<N1> src, HierarchyAdapter<String[], NodeContext<N1>, String> srcAdatper, N2 dst,
TreeUpdateAdapter<N2> updateAdapter, NodeChangeListener<NodeContext<N1>> listener, Scope.Visitor visitor) {
TreeUpdate<N1, N2> update = new TreeUpdate<N1, N2>(src, srcAdatper, dst, updateAdapter, listener, visitor);
//
update.perform();
}
private TreeUpdate(TreeContext<N1> src, HierarchyAdapter<String[], NodeContext<N1>, String> srcAdatper, N2 dst,
TreeUpdateAdapter<N2> updateAdapter, NodeChangeListener<NodeContext<N1>> listener, Scope.Visitor visitor) {
// We create the diff object
HierarchyDiff<String[], NodeContext<N1>, String[], N2, String> diff = HierarchyDiff.create(Adapters.<String> list(),
srcAdatper, Adapters.<String> list(), updateAdapter, Utils.<String> comparator());
// We obtain the iterator
HierarchyChangeIterator<String[], NodeContext<N1>, String[], N2, String> it = diff.iterator(src.root, dst);
//
this.it = it;
this.updateAdapter = updateAdapter;
this.visitor = visitor;
this.depth = 0;
this.last = null;
this.listener = listener;
}
/** . */
private final HierarchyChangeIterator<String[], NodeContext<N1>, String[], N2, String> it;
/** . */
private final TreeUpdateAdapter<N2> updateAdapter;
/** . */
private final Scope.Visitor visitor;
/** . */
private int depth;
/** . */
private NodeContext<N1> last;
/** . */
private NodeChangeListener<NodeContext<N1>> listener;
private void perform() {
// Consume the first ENTER that we won't skip
HierarchyChangeType change = it.next();
// Start recursion
perform(it.getSource());
}
private void perform(NodeContext<N1> parent) {
// Compute visit
final N2 d = it.getDestination();
final NodeData data = updateAdapter.getData(d);
//
final VisitMode visit;
if (data != null) {
visit = visitor.enter(depth, data.id, data.name, data.state);
} else {
visit = null;
}
// Cut the recursion if necessary
if (visit != VisitMode.ALL_CHILDREN) {
it.skip();
// Consume leave
it.next();
} else {
depth++;
// Expand if needed
if (!parent.isExpanded()) {
parent.expand();
}
//
while (true) {
HierarchyChangeType change = it.next();
if (change == HierarchyChangeType.LEAVE) {
// End recursion here
break;
} else {
if (change == HierarchyChangeType.KEEP) {
// Consume ENTER
it.next();
// Recurse
perform(it.getSource());
} else if (change == HierarchyChangeType.ADDED) {
// Consume ENTER
it.next();
//
NodeContext<N1> previous;
NodeContext<N1> added;
NodeData addedData = updateAdapter.getData(it.getDestination());
if (last == null || last.getParent() != parent) {
previous = null;
added = parent.insertAt(0, addedData);
} else {
previous = last;
added = last.insertAfter(addedData);
}
//
if (listener != null) {
listener.onAdd(added, parent, previous);
}
// Recurse
perform(added);
} else if (change == HierarchyChangeType.MOVED_IN) {
// Consume ENTER
it.next();
//
NodeContext<N1> to = parent;
NodeContext<N1> moved = it.getSource();
NodeContext<N1> from = moved.getParent();
NodeContext<N1> previous;
if (last == null || last.getParent() != parent) {
previous = null;
to.insertAt(0, moved);
} else {
previous = last;
last.insertAfter(moved);
}
//
if (listener != null) {
listener.onMove(moved, from, to, previous != null ? previous : null);
}
// Recurse
perform(it.getSource());
} else if (change == HierarchyChangeType.MOVED_OUT) {
// Do nothing
} else if (change == HierarchyChangeType.REMOVED) {
NodeContext<N1> removed = it.getSource();
NodeContext<N1> removedParent = removed.getParent();
//
removed.remove();
//
if (listener != null) {
listener.onRemove(removed, removedParent);
}
} else {
throw new UnsupportedOperationException("Not supported " + change);
}
}
}
//
depth--;
}
//
if (data != null) {
if (!parent.data.state.equals(data.state)) {
if (listener != null) {
listener.onUpdate(parent, data.state);
}
}
//
if (!parent.data.name.equals(data.name)) {
parent.name = data.name;
if (listener != null) {
listener.onRename(parent, parent.getParent(), data.name);
}
}
//
parent.state = updateAdapter.getState(d);
parent.name = updateAdapter.getName(d);
parent.data = data;
//
visitor.leave(depth, data.id, data.name, data.state);
}
//
last = parent;
}
}