package delegates;

import com.sun.xml.internal.ws.util.StringUtils;

import javax.swing.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.awt.event.ActionEvent;

/**
 * User: fleipold
 * Date: Sep 1, 2008
 * Time: 11:18:45 PM
 */

public class ActionReflector {
    public static void reflectActions(Object handler) {
        for (Field field : handler.getClass().getDeclaredFields()) {
            if (!Action.class.isAssignableFrom(field.getType())) {
                continue;
            }
            reflectAction(handler, field);
        }
    }

    static void reflectAction(Object handler, Field field) {
        field.setAccessible(true);

        try {
            if (field.get(handler) != null) return;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        String actionName = field.getName();
        Method actionMethod = reflectHandler(handler, actionName);

        Action a = new ReflectiveAction(actionMethod, handler);

        try {
            field.set(handler, a);
        }
        catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    static Method reflectHandler(Object handler, String actionName) {
        try {
            return handler.getClass().getMethod(actionName);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("Action '"+actionName+"' has no handler.\n Provide handler void "+actionName+"() or initialise the field prior to running reflectActions()" , e);
        }
    }

    static class ReflectiveAction extends AbstractAction {
        private final Method actionMethod;
        private final Object presentationModel;

        public ReflectiveAction(Method actionMethod, Object handler) {
            super (actionMethod.getName());
            this.actionMethod = actionMethod;
            this.presentationModel = handler;
        }

        public void actionPerformed(ActionEvent e) {
             try {
                actionMethod.invoke(presentationModel);
            } catch (IllegalAccessException e1) {
                throw new RuntimeException(e1);
            } catch (InvocationTargetException e1) {
                throw new RuntimeException(e1);
            }
        }
    }
}

