package org.nocket.gen.page.guiservice;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.mutable.MutableBoolean;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.visit.IVisit;
import org.apache.wicket.util.visit.IVisitor;
import org.nocket.gen.page.DMDWebGenPageContext;
import org.nocket.gen.page.element.synchronizer.SynchronizerHelper;
import org.nocket.gen.page.element.synchronizer.TouchedListenerModelWrapper;
public class TouchedRegistry implements Serializable {
private DMDWebGenPageContext parentCtx;
public TouchedRegistry(DMDWebGenPageContext ctx) {
this.parentCtx = ctx;
}
public boolean registerTouchedListener(final IModel<? extends TouchedListener> listener, String... wicketIdPrefixes) {
final MutableBoolean changed = new MutableBoolean(false);
doWithMatchingModels(new ModelCallback() {
@Override
public boolean doWithModel(TouchedListenerModelWrapper<?> model) {
if (model.registerTouchedListener(listener)) {
changed.setValue(true);
}
return true;
}
}, wicketIdPrefixes);
return changed.booleanValue();
}
public boolean unregisterTouchedListener(final IModel<? extends TouchedListener> listener,
String... wicketIdPrefixes) {
final MutableBoolean changed = new MutableBoolean(false);
doWithMatchingModels(new ModelCallback() {
@Override
public boolean doWithModel(TouchedListenerModelWrapper<?> model) {
if (model.unregisterTouchedListener(listener)) {
changed.setValue(true);
}
return true;
}
}, wicketIdPrefixes);
return changed.booleanValue();
}
public boolean touched(String... wicketIdPrefixes) {
final MutableBoolean touched = new MutableBoolean(false);
doWithMatchingModels(new ModelCallback() {
@Override
public boolean doWithModel(TouchedListenerModelWrapper<?> model) {
touched.setValue(model.isTouched());
return !touched.booleanValue();
}
}, wicketIdPrefixes);
return touched.booleanValue();
}
public void touch(String... wicketIdPrefixes) {
setTouched(true, wicketIdPrefixes);
}
public void untouch(String... wicketIdPrefixes) {
setTouched(false, wicketIdPrefixes);
}
private void setTouched(final boolean touched, String... wicketIdPrefixes) {
doWithMatchingModels(new ModelCallback() {
@Override
public boolean doWithModel(TouchedListenerModelWrapper<?> model) {
model.setTouched(touched);
return true;
}
}, wicketIdPrefixes);
}
private void doWithMatchingModels(ModelCallback callback, String... wicketIdPrefixes) {
// TODO ES: startsWith ist nicht die beste Lösung. Bei einem Prefix von hallo.name würde hallo.name, halle.nameDenIchGarnichtWill gefunden werden. Letzteres ist nicht korrekt
for (TouchedRegistryData data : getDatas()) {
for (TouchedListenerModelWrapper<?> l : data.getModels().values()) {
if (wicketIdPrefixes == null || wicketIdPrefixes.length == 0
|| StringUtils.startsWithAny(l.getWicketId(), wicketIdPrefixes)) {
boolean abort = !callback.doWithModel(l);
if (abort) {
return;
}
}
}
}
}
private List<TouchedRegistryData> getDatas() {
final List<TouchedRegistryData> datas = new ArrayList<TouchedRegistryData>();
MarkupContainer root = SynchronizerHelper.findRoot(parentCtx.getPage());
IVisitor<Component, Object> visitor = new IVisitor<Component, Object>() {
@Override
public void component(Component object, IVisit<Object> visit) {
DMDWebGenPageContext ctx = object.getMetaData(DMDWebGenPageContext.CONTEXT_KEY);
if (ctx != null) {
datas.add(ctx.getTouchedRegistryData());
}
}
};
visitor.component(root, null);
root.visitChildren(visitor);
return datas;
}
private interface ModelCallback {
boolean doWithModel(TouchedListenerModelWrapper<?> model);
}
}