/*
 * COPYRIGHT (c) 2018 All rights reserved by HANWHA LIFE.
 */
package kr.co.zumo.app.lifeplus.model;

import android.arch.lifecycle.ViewModel;
import android.util.Log;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import kr.co.zumo.app.lifeplus.ILifeCycle;
import kr.co.zumo.app.lifeplus.application.App;
import kr.co.zumo.app.lifeplus.network.NetworkWatcher;
import kr.co.zumo.app.lifeplus.util.StringUtil;
import kr.co.zumo.app.lifeplus.view.Event;
import kr.co.zumo.app.lifeplus.view.fragment.factory.BasicFragmentFactory;
import kr.co.zumo.app.lifeplus.view.fragment.factory.FragmentFactory;
import kr.co.zumo.app.lifeplus.view.presenter.Presenter;

/**
 * Model
 * - Activity 에는 하나의 Model 을 이용한다.
 * - Activity 와 Fragment 에서 모델로 접근을 쉽게 하기 위해서 Android 의 ViewModel 을 이용한다.
 * - dispose() 는 onCleared() 에서 처리하므로 별도로 수행하지 않는다.
 * - 생성은 new Model() 대신 {@code ViewModelProviders.of(this).get(Model.class)} 를 이용한다.
 * <pre>
 * </pre>
 *
 * @author 민효동
 * @version 1.0
 * @history 민효동   [2018. 9. 21.]   [최초 작성]
 * @since 2018. 9. 21.
 */
public abstract class Model extends ViewModel implements ILifeCycle {

  private IModelResult listener;
  private Disposable networkDisposable;
  protected Presenter presenter;
  private FragmentFactory fragmentFactory;

  public Model() {
    Log.w("APP# Model | Model", "| >>>>>>>>>>>> " + this.getClass().getSimpleName());
  }

  /***********************************
   * own
   ***********************************/

  /**
   * 네트워크의 연결 상태를 감시한다.
   * 변동이 있을 때 presenter 로 알려준다.
   */
  private void watchNetwork() {
    Log.w("APP# Model | watchNetwork", "| " + this.getClass().getSimpleName() + " - Start network watching............");
    networkDisposable =
      NetworkWatcher.watch(App.getInstance().getContext())
        .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        .subscribe(isConnectedAll -> {
          Log.i("APP# Model | watchNetwork", "|" + "isConnectedAll: +++++++++" + isConnectedAll);
          if (null != presenter) {
            presenter.onChangedConnection(isConnectedAll, 0);
          }
        }, e -> {
          Log.i("APP# Model | watchNetwork", "|" + "isConnectedAll: ++++++++++" + "error ");
          if (null != presenter) {
            presenter.onChangedConnection(false, 0);
          }
        });
  }

  private void stopNetworkWatching() {
    Log.w("APP# Model | stopNetworkWatching", "| " + this.getClass().getSimpleName() + " - Stop network watching___________");
    if (null != networkDisposable) {
      networkDisposable.dispose();
      networkDisposable = null;
    }
  }

  protected void onResult(Event event) {
    try {
      listener.onResult(event);
    } catch (Throwable throwable) {
      throwable.printStackTrace();
      FinalAlert.create(event);
    }
  }

  /**
   * Model 로 부터 결과 값을 전달 받을 수 있는 interface 객체
   *
   * @return IModelResult
   */
  public IModelResult getListener() {
    return listener;
  }

  /**
   * Model 로 부터 결과 값을 전달 받을 객체 지정
   *
   * @param listener IModelResult
   */
  public void setListener(IModelResult listener) {
    this.listener = listener;
  }

  /**
   * set Presenter
   *
   * @param presenter
   */
  public void setPresenter(Presenter presenter) {
    Log.w("APP# Model | setPresenter", "|" + presenter.getClass().getSimpleName());
    this.presenter = presenter;
  }

  public Presenter getPresenter() {
    return this.presenter;
  }

  /**
   * Preferences 반환
   *
   * @return LifeplusPreferences
   */
  public LifeplusPreferences getPreferences() {
    return SuperModel.getInstance().getPreferences();
  }

  /**
   * is update from zumo?
   *
   * @return
   */
  public boolean isUpdateUser() {
    LifeplusPreferences preferences = getPreferences();
    return StringUtil.isFull(preferences.getZumoUserNo()) && preferences.isZumoUserUpdateCompleted() == false;
  }


  /**
   * 네비게이션에 사용할 FragmentFactory 를 리턴한다.
   *
   * @return
   */
  public FragmentFactory getFragmentFactory() {
    if (null == fragmentFactory) {
      fragmentFactory = new BasicFragmentFactory();
    }
    return fragmentFactory;
  }

  /**
   * 네비게이션 FragmentFactory 지정
   *
   * @param factory
   */
  public void setFragmentFactory(FragmentFactory factory) {
    this.fragmentFactory = factory;
  }

  /***********************************
   * ILifeCycle
   ***********************************/
  @Override
  public final void start() {
    Log.w("APP#  Model | start", "| -------->> " + this.getClass().getSimpleName());
    startInternal();
  }

  @Override
  public final void resume() {
    Log.w("APP# Model | resume", "| -------->> " + this.getClass().getSimpleName());
    watchNetwork();
    resumeInternal();
  }

  @Override
  public final void pause() {
    Log.w("APP#  Model | pause", "| " + this.getClass().getSimpleName() + " <<--------");
    stopNetworkWatching();
    pauseInternal();
  }

  @Override
  public final void stop() {
    Log.w("APP# Model | stop", "| " + this.getClass().getSimpleName() + " <<--------");
    stopInternal();
  }

  /**
   * dispose
   * - Model 은 Activity 가 destroy 될 때 함께 destroy 된다.
   */
  @Override
  public final void destroy() {
    Log.w("APP# Model | destroy", "| " + this.getClass().getSimpleName() + "<<<<<<<<<<<<");
    destroyInternal();
  }

  protected abstract void destroyInternal();

  protected abstract void startInternal();

  protected abstract void stopInternal();

  protected abstract void resumeInternal();

  protected abstract void pauseInternal();


  /***********************************
   * ViewModel
   ***********************************/
  @Override
  protected void onCleared() {
    super.onCleared();

    destroy();
  }
}
