/*
 * Copyright 2016 Peter Kenji Yamanaka
 *
 * 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.pyamsoft.powermanager.dagger.modifier.preference;

import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import com.pyamsoft.powermanager.PowerManagerPreferences;
import com.pyamsoft.powermanager.app.service.ForegroundService;
import rx.Observable;
import rx.Scheduler;
import rx.Subscription;
import rx.subscriptions.Subscriptions;
import timber.log.Timber;

abstract class PreferenceModifier {

  // KLUDGE Holds reference to application context
  @SuppressWarnings("WeakerAccess") @NonNull final Context appContext;
  @SuppressWarnings("WeakerAccess") @NonNull final Intent service;
  @SuppressWarnings("WeakerAccess") @NonNull final PowerManagerPreferences preferences;
  @NonNull private final Scheduler subscribeScheduler;
  @NonNull private final Scheduler observeScheduler;
  @NonNull private Subscription subscription = Subscriptions.empty();

  PreferenceModifier(@NonNull Context context, @NonNull PowerManagerPreferences preferences,
      @NonNull Scheduler subscribeScheduler, @NonNull Scheduler observeScheduler) {
    Timber.d("New PreferenceModifier");
    this.appContext = context.getApplicationContext();
    this.preferences = preferences;
    this.service = new Intent(appContext, ForegroundService.class);
    this.subscribeScheduler = subscribeScheduler;
    this.observeScheduler = observeScheduler;
  }

  @SuppressWarnings("WeakerAccess") void unsub() {
    if (!subscription.isUnsubscribed()) {
      subscription.unsubscribe();
    }
  }

  void wrapInSubscription(@NonNull WrappedSubscription wrappedSubscription) {
    unsub();
    subscription = Observable.defer(() -> {
      Timber.d("Run modifier on subscription thread");
      wrappedSubscription.call(preferences);
      return Observable.just(true);
    }).subscribeOn(subscribeScheduler).observeOn(observeScheduler).subscribe(aBoolean -> {
      Timber.d("Modifier success");
      appContext.startService(service);
    }, throwable -> Timber.e(throwable, "onError wrapInSubscription"), this::unsub);
  }

  interface WrappedSubscription {

    void call(@NonNull PowerManagerPreferences preferences);
  }
}


@@ -724,16 +724,63 @@
 Intent;%0A
+import android.support.annotation.CheckResult;%0A
 import a
@@ -1003,16 +1003,49 @@
 iption;%0A
+import rx.schedulers.Schedulers;%0A
 import r
@@ -1816,251 +1816,1124 @@
 %22);%0A
-    this.appContext = context.getApplicationContext();%0A    this.preferences = preferences;%0A    this.service = new Intent(appContext, ForegroundService.class);%0A    this.subscribeScheduler = subscribeScheduler;%0A    this.observeScheduler = observ
+%0A    if (isBackgroundScheduler(observeScheduler)) %7B%0A      throw new RuntimeException(%22Cannot observe on a background scheduler%22);%0A    %7D%0A%0A    if (!isBackgroundScheduler(subscribeScheduler)%0A        && subscribeScheduler != Schedulers.immediate()) %7B%0A      throw new RuntimeException(%22Cannot subscribe on a foreground scheduler%22);%0A    %7D%0A%0A    this.appContext = context.getApplicationContext();%0A    this.preferences = preferences;%0A    this.service = new Intent(appContext, ForegroundService.class);%0A    this.subscribeScheduler = subscribeScheduler;%0A    this.observeScheduler = observeScheduler;%0A  %7D%0A%0A  /**%0A   * Returns whether the given scheduler is one that runs operations in a background thread%0A   */%0A  @CheckResult private boolean isBackgroundScheduler(@NonNull Scheduler scheduler) %7B%0A    return scheduler == Schedulers.computation()%0A        %7C%7C scheduler == Schedulers.io()%0A        %7C%7C scheduler == Schedulers.newThread();%0A  %7D%0A%0A  @NonNull @CheckResult protected Scheduler getObserveScheduler() %7B%0A    return observeScheduler;%0A  %7D%0A%0A  @NonNull @CheckResult protected Scheduler getSubscribeScheduler() %7B%0A    return subscrib
 eSch

Enforce proper threading for schedulers