package alekseyprochukhan.android.demo.mvvm.util;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.annotations.NonNull;
import io.realm.RealmChangeListener;
import io.realm.RealmObject;
import io.realm.RealmResults;

/**
 * Helper class that makes Realm compatible with RxJava 2
 *
 * Created by Aleksey Prochukhan <[email protected]>
 * 14/05/2017
 */
public class RxRealm {


    /**
     * Helper class to wrap RealmResults into RxJava 2 Single.
     */
    public static class RealmResultsSingle<T extends RealmObject>
            implements SingleOnSubscribe<RealmResults<T>> {

        public static <T extends RealmObject> Single<RealmResults<T>> from(RealmResults<T> realmResults) {
            return Single.create(new RealmResultsSingle<>(realmResults));
        }

        private final RealmResults<T> realmResults;

        private RealmResultsSingle(RealmResults<T> realmResults) {
            this.realmResults = realmResults;
        }

        @Override
        public void subscribe(@NonNull SingleEmitter<RealmResults<T>> emitter) throws Exception {
            // Initial element.
            emitter.onSuccess(realmResults);
        }
    }


    /**
     * Helper class to wrap RealmResults into RxJava 2 Observable.
     */
    public static class RealmResultsObservable<T extends RealmObject>
            implements ObservableOnSubscribe<RealmResults<T>> {

        public static <T extends RealmObject> Observable<RealmResults<T>> from(RealmResults<T> realmResults) {
            return Observable.create(new RealmResultsObservable<>(realmResults));
        }

        private final RealmResults<T> realmResults;

        private RealmResultsObservable(RealmResults<T> realmResults) {
            this.realmResults = realmResults;
        }

        @Override
        public void subscribe(ObservableEmitter<RealmResults<T>> emitter) throws Exception {
            // Initial element.
            emitter.onNext(realmResults);

// We don't catch changes without the resulst set since our adapter does this automatically.
            // Notify on changes.
            RealmChangeListener<RealmResults<T>> changeListener = element -> emitter.onNext(element);
            realmResults.addChangeListener(changeListener);

            // Make sure we don't listen to the changes when we are no longer interested.
            emitter.setCancellable(() -> realmResults.removeChangeListener(changeListener));
        }
    }
}