package pl.temomuko.autostoprace.util;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import rx.Scheduler;
import rx.android.plugins.RxAndroidPlugins;
import rx.android.plugins.RxAndroidSchedulersHook;
import rx.plugins.RxJavaPlugins;
import rx.plugins.RxJavaSchedulersHook;
import rx.schedulers.Schedulers;

/**
 * Created by Szymon Kozak on 2016-01-22.
 */

/**
 * This rule registers SchedulerHooks for RxJava and RxAndroid to ensure that subscriptions
 * always subscribeOn and observeOn Schedulers.immediate().
 * Warning, this rule will reset RxAndroidPlugins and RxJavaPlugins before and after each test so
 * if the application code uses RxJava plugins this may affect the behaviour of the testing method.
 */
public class RxSchedulersOverrideRule implements TestRule {

    private final RxJavaSchedulersHook mRxJavaSchedulersHook = new RxJavaSchedulersHook() {
        @Override
        public Scheduler getIOScheduler() {
            return Schedulers.immediate();
        }

        @Override
        public Scheduler getNewThreadScheduler() {
            return Schedulers.immediate();
        }
    };

    private final RxAndroidSchedulersHook mRxAndroidSchedulersHook = new RxAndroidSchedulersHook() {
        @Override
        public Scheduler getMainThreadScheduler() {
            return Schedulers.immediate();
        }
    };

    // Hack to get around RxJavaPlugins.reset() not being public
    // See https://github.com/ReactiveX/RxJava/issues/2297
    // Hopefully the method will be public in new releases of RxAndroid and we can remove the hack.
    private void callResetViaReflectionIn(RxJavaPlugins rxJavaPlugins)
            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Method method = rxJavaPlugins.getClass().getDeclaredMethod("reset");
        method.setAccessible(true);
        method.invoke(rxJavaPlugins);
    }

    @Override
    public Statement apply(final Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                RxAndroidPlugins.getInstance().reset();
                RxAndroidPlugins.getInstance().registerSchedulersHook(mRxAndroidSchedulersHook);
                callResetViaReflectionIn(RxJavaPlugins.getInstance());
                RxJavaPlugins.getInstance().registerSchedulersHook(mRxJavaSchedulersHook);

                base.evaluate();

                RxAndroidPlugins.getInstance().reset();
                callResetViaReflectionIn(RxJavaPlugins.getInstance());
            }
        };
    }
}

@@ -150,94 +150,8 @@
 t;%0A%0A
-import java.lang.reflect.InvocationTargetException;%0Aimport java.lang.reflect.Method;%0A%0A
 impo
@@ -167,16 +167,16 @@
 eduler;%0A
+
 import r
@@ -1413,555 +1413,8 @@
 %7D;%0A%0A
-    // Hack to get around RxJavaPlugins.reset() not being public%0A    // See https://github.com/ReactiveX/RxJava/issues/2297%0A    // Hopefully the method will be public in new releases of RxAndroid and we can remove the hack.%0A    private void callResetViaReflectionIn(RxJavaPlugins rxJavaPlugins)%0A            throws InvocationTargetException, IllegalAccessException, NoSuchMethodException %7B%0A        Method method = rxJavaPlugins.getClass().getDeclaredMethod(%22reset%22);%0A        method.setAccessible(true);%0A        method.invoke(rxJavaPlugins);%0A    %7D%0A%0A
     
@@ -1761,16 +1761,17 @@
 sHook);%0A
+%0A
         
@@ -1782,33 +1782,8 @@
     
-callResetViaReflectionIn(
 RxJa
@@ -1797,32 +1797,39 @@
 ns.getInstance()
+.reset(
 );%0A             
@@ -2017,33 +2017,8 @@
     
-callResetViaReflectionIn(
 RxJa
@@ -2040,16 +2040,23 @@
 stance()
+.reset(
 );%0A     
@@ -2081,10 +2081,9 @@
 ;%0A    %7D%0A
+
 %7D
-%0A

Remove RxSchedulersOverrideRule hack