/*
 * Copyright (C) 2012 The Cat Hive Developers.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cathive.fx.guice.thread;

import javafx.application.Platform;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.cathive.fx.guice.FxApplicationThread;

/**
 * This class can be used as an AOP interceptor in conjunction with the
 * {@link FxApplicationThread} annotation. It enforces method calls on the
 * JavaFX Application Thread.
 * <p>Basically, this class offers some wrapper functionality around
 * the {@link Platform#runLater(Runnable) runLater()-Method} provided by
 * the JavaFX Platform class.</p>
 * 
 * @see FxApplicationThread
 * @see Platform#runLater(Runnable)
 * 
 * @author Benjamin P. Jung
 */
class FxApplicationThreadMethodInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {

        final FxApplicationThread annotation = invocation.getMethod().getAnnotation(FxApplicationThread.class);
        final FxTask fxTask = new FxTask(invocation);

        if (annotation == null) {
            throw new IllegalStateException("Method is not annotated with '@FxApplicationThread'!");
        }

        if (!invocation.getMethod().getReturnType().equals(Void.class)) {
            throw new RuntimeException(String.format("[%s#%s] Only methods with return type 'void' can be annotated with @FXApplicationThread!", invocation.getThis().getClass().getName(), invocation.getMethod().getName()));
        }

        if (invocation.getMethod().getExceptionTypes().length > 0) {
            throw new RuntimeException("Only methods that don't declare exception types can be annotated with @FxApplicationThread!");
        }

        final Object retval;
        if (Platform.isFxApplicationThread()) {
            retval = invocation.proceed();
        } else {
            Platform.runLater(fxTask);
            retval = null;
        }
        return retval;

    }


    /**
     * 
     * @author Benjamin P. Jung
     */
    private static class FxTask implements Runnable {

        private final MethodInvocation methodInvocation;
        private Object returnValue;

        private FxTask(MethodInvocation methodInvocation) {
            super();
            this.methodInvocation = methodInvocation;
        }
        @Override
        public void run() {
            try {
                this.returnValue = methodInvocation.proceed();
            } catch (Throwable t) {
                throw new RuntimeException(t);
            }
        }

    }

}

@@ -17,16 +17,21 @@
 (C) 2012
+-2013
  The Cat
@@ -1785,13 +1785,36 @@
     
-if (!
+final Class%3C?%3E returnType = 
 invo
@@ -1847,16 +1847,75 @@
 rnType()
+;%0A        if (!(returnType.equals(void.class) %7C%7C returnType
 .equals(
@@ -1926,16 +1926,17 @@
 .class))
+)
  %7B%0A     

Enable interceptor for 'void' AND 'Void' methods.