package com.morihacky.android.rxjava;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
import com.morihacky.android.rxjava.R;
import java.util.ArrayList;
import java.util.List;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.Subscription;
import rx.android.app.AppObservable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import timber.log.Timber;

public class ConcurrencyWithSchedulersDemoFragment
      extends BaseFragment {

    @InjectView(R.id.progress_operation_running) ProgressBar _progress;
    @InjectView(R.id.list_threading_log) ListView _logsList;

    private LogAdapter _adapter;
    private List<String> _logs;
    private Subscription _subscription;

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (_subscription != null) {
            _subscription.unsubscribe();
        }
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        _setupLogger();
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View layout = inflater.inflate(R.layout.fragment_concurrency_schedulers, container, false);
        ButterKnife.inject(this, layout);
        return layout;
    }

    @OnClick(R.id.btn_start_operation)
    public void startLongOperation() {

        _progress.setVisibility(View.VISIBLE);
        _log("Button Clicked");

        _subscription = AppObservable.bindFragment(this, _getObservable())      // Observable
              .subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(_getObserver());                             // Observer
    }

    private Observable<Boolean> _getObservable() {
        return Observable.create(new Observable.OnSubscribe<Boolean>() {

            @Override
            public void call(Subscriber<? super Boolean> observer) {

                _log("Within Observable");

                _doSomeLongOperation_thatBlocksCurrentThread();
                observer.onNext(true);
                observer.onCompleted();
            }
        });
    }

    /**
     * Observer that handles the result List<Integer> from Observable
     * through the 3 important actions:
     *
     * 1. onCompleted
     * 2. onError
     * 3. onNext
     */
    private Observer<Boolean> _getObserver() {
        return new Observer<Boolean>() {

            @Override
            public void onCompleted() {
                _log("On complete");
                _progress.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onError(Throwable e) {
                Timber.e(e, "Error in RxJava Demo concurrency");
                _log(String.format("Boo Error %s", e.getMessage()));
                _progress.setVisibility(View.INVISIBLE);
            }

            @Override
            public void onNext(Boolean aBoolean) {
                _log(String.format("onNext with return value \"%b\"", aBoolean));
            }
        };
    }

    // -----------------------------------------------------------------------------------
    // Method that help wiring up the example (irrelevant to RxJava)

    private void _doSomeLongOperation_thatBlocksCurrentThread() {
        _log("performing long operation");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Timber.d("Operation was interrupted");
        }
    }

    private void _log(String logMsg) {

        if (_isCurrentlyOnMainThread()) {
            _logs.add(0, logMsg + " (main thread) ");
            _adapter.clear();
            _adapter.addAll(_logs);
        } else {
            _logs.add(0, logMsg + " (NOT main thread) ");

            // You can only do below stuff on main thread.
            new Handler(Looper.getMainLooper()).post(new Runnable() {

                @Override
                public void run() {
                    _adapter.clear();
                    _adapter.addAll(_logs);
                }
            });
        }
    }

    private void _setupLogger() {
        _logs = new ArrayList<String>();
        _adapter = new LogAdapter(getActivity(), new ArrayList<String>());
        _logsList.setAdapter(_adapter);
    }

    private boolean _isCurrentlyOnMainThread() {
        return Looper.myLooper() == Looper.getMainLooper();
    }

    private class LogAdapter
          extends ArrayAdapter<String> {

        public LogAdapter(Context context, List<String> logs) {
            super(context, R.layout.item_log, R.id.item_log, logs);
        }
    }
}
@@ -478,47 +478,8 @@
 ck;%0A
-import com.morihacky.android.rxjava.R;%0A
 impo
@@ -498,24 +498,24 @@
 .ArrayList;%0A
+
 import java.
@@ -571,30 +571,8 @@
 er;%0A
-import rx.Subscriber;%0A
 impo
@@ -620,32 +620,32 @@
 .AppObservable;%0A
-
 import rx.androi
@@ -672,24 +672,51 @@
 Schedulers;%0A
+import rx.functions.Func1;%0A
 import rx.sc
@@ -2313,42 +2313,42 @@
 ble.
-create(new Observable.OnSubscribe%3C
+just(true).map(new Func1%3CBoolean, 
 Bool
@@ -2348,33 +2348,32 @@
 n, Boolean%3E() %7B%0A
-%0A
             @Ove
@@ -2401,102 +2401,40 @@
 lic 
-void call(Subscriber%3C? super Boolean%3E observer) %7B%0A%0A                _log(%22Within Observable%22);%0A
+Boolean call(Boolean aBoolean) %7B
 %0A   
@@ -2514,69 +2514,23 @@
     
-observer.onNext(true);%0A                observer.onCompleted()
+return aBoolean
 ;%0A  
@@ -2611,45 +2611,8 @@
 sult
- List%3CInteger%3E from Observable%0A     *
  thr
@@ -3146,16 +3146,17 @@
 mat(%22Boo
+!
  Error %25
@@ -3306,32 +3306,28 @@
 ext(Boolean 
-aB
+b
 ool
-ean
 ) %7B%0A        
@@ -3388,24 +3388,20 @@
 %22%25b%5C%22%22, 
-aB
+b
 ool
-ean
 ));%0A    

.create() -> .just() : create is an overkill