package org.rr.jeborker.gui.action;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.rr.commons.log.LoggerFactory;
import org.rr.commons.mufs.IResourceHandler;
import org.rr.commons.utils.ReflectionUtils;
import org.rr.jeborker.db.item.EbookPropertyItem;
import org.rr.jeborker.event.RefreshAbstractAction;
import org.rr.jeborker.gui.MainController;
class MultiActionWrapper extends AbstractAction {
private static final long serialVersionUID = -2128569488506763407L;
public static final String SELECTED_ROWS_TO_REFRESH_KEY = "SELECTED_ROWS_TO_REFRESH_KEY";
public static final String SELECTED_ITEMS_TO_REFRESH_KEY = "SELECTED_ITEMS_TO_REFRESH_KEY";
private final Action firstActionInstance;
private List<IResourceHandler> handlers;
private int[] selectedRowsToRefresh;
private List<EbookPropertyItem> selectedItemsToRefresh;
private HashMap<String, Object> values = new HashMap<String, Object>();
public MultiActionWrapper(final Class<? extends Action> actionClass, List<EbookPropertyItem> items, final List<IResourceHandler> handlers, int[] selectedRowsToRefresh) {
this.handlers = handlers;
this.selectedRowsToRefresh = selectedRowsToRefresh;
this.firstActionInstance = createInstance(actionClass, (handlers.isEmpty() ? null : handlers.get(0)), selectedRowsToRefresh);
this.selectedItemsToRefresh = items;
init();
}
private void init() {
putValue(Action.NAME, String.valueOf(firstActionInstance.getValue(Action.NAME)));
putValue(Action.SMALL_ICON, firstActionInstance.getValue(Action.SMALL_ICON));
putValue(Action.LARGE_ICON_KEY, firstActionInstance.getValue(Action.LARGE_ICON_KEY));
putValue(ApplicationAction.NON_THREADED_ACTION_KEY, firstActionInstance.getValue(ApplicationAction.NON_THREADED_ACTION_KEY));
putValue(ApplicationAction.SINGLETON_ACTION_KEY, firstActionInstance.getValue(ApplicationAction.SINGLETON_ACTION_KEY));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void actionPerformed(ActionEvent e) {
final Iterator<IResourceHandler> iterator = handlers.iterator();
final int size = handlers.size();
//skip the first and use the firstActionInstance action we have already created with the constructor
if(iterator.hasNext()) {
iterator.next();
}
Object doOnce;
transferValues(firstActionInstance);
if(firstActionInstance instanceof IDoOnlyOnceAction<?>) {
doOnce = ((IDoOnlyOnceAction<?>)firstActionInstance).doOnce();
} else {
doOnce = null;
}
List<Action> actions = new ArrayList<>(size);
actions.add(this.doActionAt(firstActionInstance, e, 0, size));
//create an action instance for all the other handlers.
for (int i = 1; iterator.hasNext(); i++) {
MainController.getController().getProgressMonitor().setProgress(i, handlers.size());
IResourceHandler handler = iterator.next();
Action action = createInstance(firstActionInstance.getClass(), handler, selectedRowsToRefresh);
if(action != null) {
if(doOnce != null && action instanceof IDoOnlyOnceAction<?>) {
((IDoOnlyOnceAction)action).setDoOnceResult(doOnce);
}
actions.add(this.doActionAt(action, e, i, size));
} else {
LoggerFactory.logWarning(this, "could not create action for " + handler, null);
}
}
MainController.getController().getProgressMonitor().resetProgress();
//do the finalize for all actions
if(firstActionInstance instanceof IFinalizeAction) {
for(int i = 0; i < actions.size() ; i++) {
Action action = actions.get(i);
((IFinalizeAction) action).finalizeAction(i);
}
}
//clean the results for all action instances
if(firstActionInstance instanceof IDoOnlyOnceAction) {
for(int i = 0; i < actions.size() ; i++) {
Action action = actions.get(i);
((IDoOnlyOnceAction) action).setDoOnceResult(null);
}
}
}
/**
* Invokes the action method to the given action.
* @param action The action to be executed.
*/
public Action doActionAt(Action action, ActionEvent e, int entryIndex, int entrySize) {
if(firstActionInstance instanceof IDoOnlyOnceAction<?>) {
((IDoOnlyOnceAction<?>)action).prepareFor(entryIndex, entrySize);
}
action.actionPerformed(e);
return action;
}
/**
* Creates the action instance from the given class and {@link IResourceHandler}.
* @param clazz The class to be instantiated.
* @param handler The handler for the first constructor parameter.
* @return The desired action.
*/
private Action createInstance(final Class<? extends Action> clazz, final IResourceHandler handler, int[] selectedRowsToRefresh) {
Action objectInstance = (Action) ReflectionUtils.getObjectInstance(clazz, new Object[] {handler});
if(objectInstance == null) {
throw new RuntimeException("Could not create instance for " + clazz);
} else if(objectInstance instanceof RefreshAbstractAction) {
((RefreshAbstractAction)objectInstance).setSelectedRowsToRefresh(selectedRowsToRefresh);
}
transferValues(objectInstance);
return objectInstance;
}
@Override
public void putValue(String key, Object newValue) {
super.putValue(key, newValue);
values.put(key, newValue);
}
@Override
public Object getValue(String key) {
if(super.getValue(key) != null) {
return super.getValue(key);
}
return firstActionInstance.getValue(key);
}
private void transferValues(Action objectInstance) {
objectInstance.putValue(SELECTED_ROWS_TO_REFRESH_KEY, this.selectedRowsToRefresh);
objectInstance.putValue(SELECTED_ITEMS_TO_REFRESH_KEY, this.selectedItemsToRefresh);
for (Entry<String, Object> e : values.entrySet()) {
objectInstance.putValue(e.getKey(), e.getValue());
}
}
}