/*
 * 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 kr.co.zumo.app.lifeplus.view.Event;
import kr.co.zumo.app.lifeplus.view.ILifeCycle;
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 {

  protected IModelResult listener;
  protected Presenter presenter;

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

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

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

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

  public void setPresenter(Presenter presenter) {
    this.presenter = presenter;
  }

  public LifeplusPreferences getPreferences() {
    return SuperModel.getInstance().getPreferences();
  }

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

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

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

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

  /**
   * dispose
   */
  private void destroy() {
    Log.w("APP# Model | dispose", "| >>>>>>>>>>>>>> " + this.getClass().getSimpleName());
    destroyInternal();
  }

  protected abstract void destroyInternal();

  protected abstract void startInternal();

  protected abstract void stopInternal();

  protected abstract void resumeInternal();

  protected abstract void pauseInternal();

  @Override
  protected void onCleared() {
    super.onCleared();

    destroy();
  }

  protected void onResult(Event event) {
    try {
      if (null != listener) {
        listener.onResult(event);
      }
    } catch (Throwable throwable) {
      onError(new Event.Builder(Event.ERROR).build(), throwable);
    }
  }

  protected void onError(Event event, Throwable throwable) {
    Log.e("APP# Model | onResult", "|" + throwable.toString());
    try {
      if (null != listener) {
        listener.onResult(event);
      }
    } catch (Throwable e) {
      Log.e("APP# Model | onError", "|" + e.toString());
    }
  }
}
