/*
 * Copyright 2018 location
 *
 * 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.location.mvp.mvproutelibrary.scheduler;

import android.os.Looper;
import android.support.annotation.IntRange;
import android.view.View;

import com.location.mvp.mvproutelibrary.base.RouteManager;
import com.location.mvp.mvproutelibrary.error.ExceptionHandle;

import org.reactivestreams.Subscription;

import java.util.concurrent.TimeUnit;

import io.reactivex.Flowable;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;


/**
 * 对rxjava分装的工具类
 * {@link #countDown(View, int, CountDownListener)} rxJava的倒计时工具
 * <br>
 * {@link #click(View.OnClickListener, View...)} rxJava的防止view多次点击
 * 默认1秒内不允许重复点击
 * <br>
 * 网络模块{@linkplain compose 调度器}  调度器包含 线程的切换 网络异常的统一处理
 * <br>
 * <br>
 * 网络模块  异常处理  {@link HandlerException}
 */
public class RxScheduler {


	/**
	 * 倒计时
	 *
	 * @param view     倒计时所用到的view
	 * @param second   倒计时时长  单位 秒
	 * @param listener 倒计时回调
	 * @param <T>
	 * @return Disposable  返回 Disposable  在Activity的onDestroy方法中
	 * disposable.dispose() 取消掉  防止内存泄漏
	 * @see CountDownListener  回调接口
	 */
	public static <T extends View> Disposable countDown(final T view, @IntRange(from = 1) final int second, final CountDownListener<T> listener) {
		if (listener == null || second <= 0) return null;
		return Flowable.intervalRange(0, second + 1, 0, 1, TimeUnit.SECONDS).observeOn(AndroidSchedulers.mainThread())
				.doOnNext(new Consumer<Long>() {
					@Override
					public void accept(Long aLong) throws Exception {
						listener.onCountDownProgress(view, (int) (second - aLong));
					}
				}).doOnComplete(new Action() {
					@Override
					public void run() throws Exception {
						listener.onCountDownComplete(view);
					}
				}).doOnSubscribe(new Consumer<Subscription>() {
					@Override
					public void accept(Subscription subscription) throws Exception {
						listener.onBindCountDown(view);
					}
				}).subscribe();

	}

	/**
	 * 防止 view多次点击  默认1秒内只允许点击一次
	 *
	 * @param views     需要点击的view  接受一个可变参数
	 * @param listener 点击view的回调
	 * @throws IllegalStateException 当操作的时候在子线程的时候会抛出此异常
	 */
	public static void click( final View.OnClickListener listener, View... views) {
		if (Looper.getMainLooper() != Looper.myLooper()) {
			throw new IllegalStateException("Click must be executed in the main thread,you thread in " + Thread.currentThread().getName());
		}
		if (views == null ||views.length<=0|| listener == null) return;
		for (View view : views) {
			Observable.create(new ViewObservable(view))
					.throttleFirst(RouteManager.getFikterClickTime(), TimeUnit.SECONDS)
					.subscribe(new Consumer<View>() {
						@Override
						public void accept(View view) throws Exception {
							listener.onClick(view);
						}
					});
		}

	}


	private static class ViewObservable implements ObservableOnSubscribe<View> {
		private View view;

		ViewObservable(View view) {
			this.view = view;
		}

		@Override
		public void subscribe(final ObservableEmitter<View> emitter) throws Exception {
			View.OnClickListener listener = new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					if (!emitter.isDisposed()) {
						emitter.onNext(view);
					}
				}
			};
			view.setOnClickListener(listener);
		}
	}

	/**
	 * 在此方法中 默认实现了线程调度 和  异常处理
	 *
	 * @param <T>
	 */
	public static class compose<T> implements ObservableTransformer<T, T> {

		@Override
		public ObservableSource<T> apply(io.reactivex.Observable<T> upstream) {
			return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).onErrorResumeNext(new HandlerException<T>());
		}
	}


	/**
	 * 网络请求异常处理
	 *
	 * @param <T>
	 */
	public static class HandlerException<T> implements Function<Throwable, Observable<T>> {

		@Override
		public Observable<T> apply(Throwable throwable) throws Exception {
			ExceptionHandle.ResponseThrowable responseThrowable = ExceptionHandle.handleException(throwable);
			return Observable.error(responseThrowable);
		}
	}

	/**
	 * 倒计时 回调
	 * {@link RxScheduler#countDown(View, int, CountDownListener)}
	 *
	 * @param <T>
	 */
	public interface CountDownListener<T extends View> {
		/**
		 * 倒计时 与view绑定时的操作   只会调用一次
		 * 在这里可以对view的Enabled 字体颜色  做操作
		 *
		 * @param view
		 */
		void onBindCountDown(T view);

		/**
		 * 倒计时 进行中  会多次调用
		 *
		 * @param view
		 * @param second 当前剩余的秒数
		 */
		void onCountDownProgress(T view, int second);

		/**
		 * 倒计时 完成  只会调用一次
		 * 这里可以恢复view的状态等
		 *
		 * @param view
		 */
		void onCountDownComplete(T view);
	}

}
