package com.github.ayltai.newspaper.data;

import java.util.Collection;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.github.ayltai.newspaper.util.Irrelevant;
import com.github.ayltai.newspaper.util.RxUtils;
import com.github.ayltai.newspaper.util.TestUtils;

import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.Scheduler;
import io.reactivex.Single;
import io.realm.Realm;

public abstract class RealmLoader<D> extends RxLoader<D> {
    protected static final String KEY_REFRESH = "refresh";

    private Realm realm;

    protected RealmLoader(@NonNull final Context context) {
        super(context);
    }

    protected RealmLoader(@NonNull final Context context, @Nullable final Bundle args) {
        super(context, args);
    }

    @NonNull
    protected Scheduler getScheduler() {
        return DataManager.SCHEDULER;
    }

    @Nullable
    protected Realm getRealm() {
        return this.realm;
    }

    protected boolean isValid() {
        if (this.realm == null) {
            if (TestUtils.isLoggable()) throw new IllegalStateException("No Realm instance is available");

            return false;
        }

        return true;
    }

    @NonNull
    @Override
    protected Flowable<D> load(@NonNull final Context context, @Nullable final Bundle args) {
        if (RealmLoader.isForceRefresh(args)) return this.loadFromRemoteSource(context, args);

        if (this.isValid()) {
            return Flowable.create(emitter -> this.loadFromLocalSource(context, args)
                .compose(RxUtils.applyFlowableSchedulers(this.getScheduler()))
                .subscribe(
                    data -> {
                        if (data instanceof Collection && !((Collection)data).isEmpty()) emitter.onNext(data);

                        this.loadFromRemoteSource(context, args).subscribe(emitter::onNext);
                    },
                    error -> {
                        if (TestUtils.isLoggable()) Log.e(this.getClass().getSimpleName(), error.getMessage(), error);
                    }), BackpressureStrategy.LATEST);
        }

        return this.loadFromRemoteSource(context, args);
    }

    @NonNull
    protected abstract Flowable<D> loadFromLocalSource(@NonNull Context context, @Nullable Bundle args);

    @NonNull
    protected abstract Flowable<D> loadFromRemoteSource(@NonNull Context context, @Nullable Bundle args);

    @CallSuper
    @Override
    protected void onForceLoad() {
        Single.<Realm>create(emitter -> emitter.onSuccess(DaggerDataComponent.builder()
                .dataModule(new DataModule(this.getContext()))
                .build()
                .realm()))
            .compose(RxUtils.applySingleSchedulers(this.getScheduler()))
            .subscribe(
                realm -> {
                    this.realm = realm;

                    if (TestUtils.isLoggable()) Log.d(this.getClass().getSimpleName(), "A Realm instance is created");

                    super.onForceLoad();
                },
                error -> {
                    if (TestUtils.isLoggable()) Log.e(this.getClass().getSimpleName(), error.getMessage(), error);
                });
    }

    @CallSuper
    @Override
    protected boolean onCancelLoad() {
        final boolean result = super.onCancelLoad();

        Single.<Irrelevant>create(
            emitter -> {
                if (this.realm != null) {
                    this.realm.close();
                    this.realm = null;
                }

                emitter.onSuccess(Irrelevant.INSTANCE);
            })
            .compose(RxUtils.applySingleSchedulers(this.getScheduler()))
            .subscribe(
                irrelevant -> {
                    if (TestUtils.isLoggable()) Log.d(this.getClass().getSimpleName(), "A Realm instance is closed");
                },
                error -> {
                    if (TestUtils.isLoggable()) Log.e(this.getClass().getSimpleName(), error.getMessage(), error);
                });

        return result;
    }

    protected static boolean isForceRefresh(@Nullable final Bundle args) {
        return args != null && args.getBoolean(RealmLoader.KEY_REFRESH, false);
    }
}

@@ -282,16 +282,69 @@
 l.Log;%0A%0A
+import com.github.ayltai.newspaper.net.NetworkUtils;%0A
 import c
@@ -387,16 +387,16 @@
 levant;%0A
-
 import c
@@ -1555,20 +1555,98 @@
         
-if (
+final boolean isOnline = NetworkUtils.isOnline(context);%0A%0A        if (isOnline && 
 RealmLoa
@@ -2082,24 +2082,68 @@
 ext(data);%0A%0A
+                        if (isOnline) %7B%0A    
             
@@ -2198,36 +2198,520 @@
 rgs)
-.subscribe(
+%0A                                .subscribe(items -%3E %7B%0A                                    if (items instanceof Collection && !((Collection)items).isEmpty()) %7B%0A                                        
 emitter
-::
+.
 onNext
-);
+(items);%0A                                    %7D else %7B%0A                                        emitter.onNext(data);%0A                                    %7D%0A                                %7D);%0A                        %7D else %7B%0A                            emitter.onNext(data);%0A                        %7D
 %0A   

Load from remote source only if it is online