package de.elatexam.editor.components.panels.tree;
import java.util.Iterator;
import java.util.List;
import wicketdnd.Anchor;
import wickettree.ITreeProvider;
import de.elatexam.editor.user.BasicUser;
import de.elatexam.editor.util.Stuff;
import de.elatexam.model.Category;
import de.elatexam.model.ComplexTaskDef;
import de.elatexam.model.Indexed;
import de.elatexam.model.SubTaskDef;
import de.elatexam.model.manual.HomogeneousTaskBlock;
/**
* This class knows about the concrete class hierarchy of the generated complextaskdef domain model. It allows to find
* direct references between parents and children and knows how to remove these references. This allows deleting the
* child objects without throwing up hibernate.
*
* @author Steffen Dienst
*
*/
public class ComplexTaskHierarchyFacade {
private ITreeProvider<Indexed> treeProvider;
/**
* Default constructor.
*
* @param treeProvider
*/
public ComplexTaskHierarchyFacade(ITreeProvider<Indexed> treeProvider) {
this.treeProvider = treeProvider;
}
/**
* Removes object from it's parent. Returns that object, that needs to get deleted from the database.
*
* @param child
* @return the object to delete
*/
public Indexed removeFromParent(final Indexed child) {
final Indexed parent = findParentOf(child);
if (parent != null) {
if (parent instanceof BasicUser) {
((BasicUser) parent).getTaskdefs().remove(child);
} else if (parent instanceof ComplexTaskDef) {
((ComplexTaskDef) parent).getCategory().remove(child);
} else
return clearPhysicalParent(child, parent);
}
return child;
}
/**
* Find the model where is true: this.getChildren(parent).contains(child).
*
* @param child
* @return
*/
public Indexed findParentOf(final Indexed child) {
final Iterator<? extends Indexed> it = treeProvider.getRoots();
while (it.hasNext()) {
final Indexed root = it.next();
final Indexed parent = findParentOf(root, child);
if (parent != null)
return parent;
}
return null;
}
/**
* Move element from original parent to the new one depending on the types of domain objects involved.
* @param element
* @param to
* @param anchor
* @return true if a move occured, false if not
*/
public boolean moveElement(Object element, Object to, Anchor anchor) {
if (element == to)
return false;
if (to instanceof HomogeneousTaskBlock) {
if(element instanceof SubTaskDef)
return move((SubTaskDef)element, (HomogeneousTaskBlock)to,anchor,true);
else if(element instanceof HomogeneousTaskBlock){
return move((HomogeneousTaskBlock)element,(HomogeneousTaskBlock)to,anchor,true);
}
} else if (to instanceof SubTaskDef) {
return move((SubTaskDef)element,(SubTaskDef)to,anchor);
}else if (to instanceof Category){
return move((HomogeneousTaskBlock)element,(Category)to,anchor,true);
}
return false;
}
/**
* Copy element from original parent to the new one depending on the types of domain objects involved.
* @param droppedObject
* @param droppedOn
* @param anchor
* @return
*/
public boolean copyElement(Object droppedObject, Object droppedOn,
Anchor anchor) {
if( droppedObject instanceof HomogeneousTaskBlock && droppedOn instanceof Category){
// FIXME create a copy of the taskblock, doesn't work this way
return move((HomogeneousTaskBlock)droppedObject,(Category)droppedOn,anchor,false);
}else if(droppedObject instanceof SubTaskDef){
if(droppedOn instanceof HomogeneousTaskBlock){
return move((SubTaskDef)droppedObject, (HomogeneousTaskBlock)droppedOn, anchor,false);
}
}
return false;
}
private boolean move(HomogeneousTaskBlock tb, HomogeneousTaskBlock to, Anchor anchor, boolean isMove) {
Category fromC = (Category) findParentOf(tb);
Category toC = (Category) findParentOf(to);
if(fromC!=toC){
return move(tb,toC,anchor,isMove);
}else{
//TODO how can the order of taskblocks be changed? JPA does not keep list semantics (uses persistent bag....)
}
return false;
}
private boolean move(HomogeneousTaskBlock element, Category to, Anchor anchor, boolean isMove) {
Category fromC = (Category) findParentOf(element);
HomogeneousTaskBlock b = (HomogeneousTaskBlock) element;
if(isMove && fromC!=null)
fromC.getTaskBlocks().remove(b);
to.getTaskBlocks().add(b);
Stuff.saveAll(fromC,to);
return true;
}
private boolean move(SubTaskDef element, SubTaskDef target, Anchor anchor) {
// change order
HomogeneousTaskBlock targetTaskblock = (HomogeneousTaskBlock) findParentOf(target);
HomogeneousTaskBlock sourceTaskblock = (HomogeneousTaskBlock) findParentOf(element);
if(sourceTaskblock!=null)
Stuff.getSubtaskDefs(sourceTaskblock).remove(element);
List<SubTaskDef> subtaskdefs = Stuff.getSubtaskDefs(targetTaskblock);
int indexOfTo = subtaskdefs.indexOf(target);
if (anchor == Anchor.BOTTOM) {
indexOfTo++;
}
subtaskdefs.add(indexOfTo, element);
Stuff.saveAll(sourceTaskblock, targetTaskblock);
return true;
}
private boolean move(SubTaskDef element, HomogeneousTaskBlock to, Anchor anchor, boolean isMove) {
Indexed parent = findParentOf(element);
if (parent != to) {
// remove from current taskblock
if(isMove && parent != null)
removeFromParent(element);
Stuff.getSubtaskDefs(to).add((SubTaskDef) element);
Stuff.saveAll(parent, to);
return true;
}
return false;
}
private Indexed clearPhysicalParent(final Indexed child, final Indexed logicalParent) {
if (child instanceof HomogeneousTaskBlock) {
final Category cat = (Category) logicalParent;
for (final HomogeneousTaskBlock tbi : cat.getTaskBlocks()) {
if (tbi == child) {
cat.getTaskBlocks().remove(tbi);
return tbi;
}
}
} else if (child instanceof SubTaskDef) {
final HomogeneousTaskBlock tb = (HomogeneousTaskBlock) logicalParent;
try {
final List<? extends SubTaskDef> itemsList = tb.getSubtaskDefs();
for (final SubTaskDef subtaskdef : itemsList) {
if (subtaskdef == child) {
itemsList.remove(subtaskdef);
return subtaskdef;
}
}
} catch (final Exception e) {
e.printStackTrace();
}
}
// all other elements have a single child, stupid jaxb default code...
return logicalParent;
}
private Indexed findParentOf(final Indexed current, final Indexed child) {
final Iterator<? extends Indexed> it = treeProvider.getChildren(current);
while (it.hasNext()) {
final Indexed potentialParent = it.next();
if (isSamePersistedObject(potentialParent, child))
return current;
final Indexed parent = findParentOf(potentialParent, child);
if (parent != null)
return parent;
}
return null;
}
/**
* Compare the generated primary keys instead of using the semantical equals method.
*
* @param potentialParent
* @param child
* @return
*/
private boolean isSamePersistedObject(Indexed potentialParent, Indexed child) {
try {
return
// same class?
potentialParent.getClass().equals(child.getClass())
&&
// same primary key?
potentialParent.getHjid().equals(child.getHjid());
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}