package com.arondor.common.reflection.gwt.client.presenter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.arondor.common.reflection.gwt.client.service.GWTReflectionServiceAsync;
import com.arondor.common.reflection.gwt.client.view.MyValueChangeEvent;
import com.arondor.common.reflection.model.config.ObjectConfiguration;
import com.arondor.common.reflection.model.config.ObjectConfigurationMap;
import com.arondor.common.reflection.model.java.AccessibleClass;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.rpc.AsyncCallback;
public class DefaultImplementingClassPresenter implements ImplementingClassPresenter
{
private static final Logger LOG = Logger.getLogger(ImplementingClassPresenter.class.getName());
private final String baseClassName;
private ImplementingClass currentImplementingClass = ImplementingClass.NULL_CLASS;
private final Display display;
private final GWTReflectionServiceAsync rpcService;
private final List<ImplementingClass> implementingClasses = new ArrayList<ImplementingClass>();
public DefaultImplementingClassPresenter(GWTReflectionServiceAsync rpcService,
ObjectConfigurationMap objectConfigurationMap, String baseClassName, Display display)
{
this.baseClassName = baseClassName;
this.display = display;
this.rpcService = rpcService;
this.display.setBaseClassName(baseClassName);
bind();
addImplementingClass(ImplementingClass.NULL_CLASS);
fetchBaseClass();
fetchImplementations();
if (objectConfigurationMap != null)
{
fetchObjectConfigurations(objectConfigurationMap);
}
}
private void fetchObjectConfigurations(ObjectConfigurationMap objectConfigurationMap)
{
for (Map.Entry<String, ObjectConfiguration> entry : objectConfigurationMap.entrySet())
{
final String referenceName = entry.getKey();
final String referenceClassName = entry.getValue().getClassName();
final ImplementingClass implementingClass = new ImplementingClass(true, referenceName);
if (referenceClassName.equals(baseClassName))
{
addImplementingClass(implementingClass);
}
else
{
rpcService.getAccessibleClass(referenceClassName, new AsyncCallback<AccessibleClass>()
{
public void onFailure(Throwable caught)
{
}
public void onSuccess(AccessibleClass result)
{
for (String interfaceName : result.getAllInterfaces())
{
if (interfaceName.equals(baseClassName))
{
addImplementingClass(implementingClass);
}
}
}
});
}
}
}
public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<ImplementingClass> valueChangeHandler)
{
return this.display.addValueChangeHandler(new ValueChangeHandler<String>()
{
public void onValueChange(ValueChangeEvent<String> event)
{
ImplementingClass implementingClass = ImplementingClass.parseImplementingClass(event.getValue());
valueChangeHandler.onValueChange(new MyValueChangeEvent<ImplementingClass>(implementingClass));
}
});
}
private void bind()
{
display.addValueChangeHandler(new ValueChangeHandler<String>()
{
public void onValueChange(ValueChangeEvent<String> event)
{
currentImplementingClass = ImplementingClass.parseImplementingClass(event.getValue());
LOG.finest("Changed implementClassName=" + currentImplementingClass);
}
});
}
private void addImplementingClass(ImplementingClass implementingClass)
{
if (implementingClasses.contains(implementingClass))
{
return;
}
implementingClasses.add(implementingClass);
updateDisplay();
}
private boolean updateDisplayScheduled = false;
private void updateDisplay()
{
if (updateDisplayScheduled)
{
return;
}
updateDisplayScheduled = true;
if (GWT.isClient())
{
Scheduler.get().scheduleFixedDelay(new RepeatingCommand()
{
public boolean execute()
{
doUpdateDisplay();
return false;
}
}, 2000);
}
else
{
doUpdateDisplay();
}
}
private void doUpdateDisplay()
{
Collections.sort(implementingClasses);
List<String> names = new ArrayList<String>();
for (ImplementingClass implementingClass : implementingClasses)
{
names.add(implementingClass.toString());
}
display.setImplementingClasses(names);
LOG.finest("currentImplementingClass=" + currentImplementingClass);
if (implementingClasses.contains(currentImplementingClass))
{
display.selectImplementingClass(currentImplementingClass.toString());
}
updateDisplayScheduled = false;
}
private void fetchBaseClass()
{
rpcService.getAccessibleClass(baseClassName, new AsyncCallback<AccessibleClass>()
{
public void onFailure(Throwable caught)
{
}
public void onSuccess(AccessibleClass result)
{
if (isInstantiatable(result))
{
addImplementingClass(new ImplementingClass(false, result.getName()));
}
}
});
}
protected boolean isInstantiatable(AccessibleClass result)
{
return result.getSuperclass() != null && !result.isAbstract();
}
private void fetchImplementations()
{
rpcService.getImplementingAccessibleClasses(baseClassName, new AsyncCallback<Collection<AccessibleClass>>()
{
public void onSuccess(Collection<AccessibleClass> result)
{
for (AccessibleClass clazz : result)
{
if (isInstantiatable(clazz))
{
addImplementingClass(new ImplementingClass(false, clazz.getName()));
}
}
}
public void onFailure(Throwable caught)
{
}
});
}
public String getBaseClassName()
{
return baseClassName;
}
public void setImplementingClass(ImplementingClass implementingClass)
{
this.currentImplementingClass = implementingClass;
display.selectImplementingClass(currentImplementingClass.toString());
}
public ImplementingClass getImplementingClass()
{
return currentImplementingClass;
}
}