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

import android.support.v7.app.ActionBar;
import android.util.Log;

import com.google.gson.Gson;

import kr.co.zumo.app.lifeplus.ILifeCycle;
import kr.co.zumo.app.lifeplus.manager.IActionBarListener;
import kr.co.zumo.app.lifeplus.model.IModelResult;
import kr.co.zumo.app.lifeplus.model.Model;
import kr.co.zumo.app.lifeplus.network.INetworkReceiverListener;
import kr.co.zumo.app.lifeplus.supervisor.ScreenID;
import kr.co.zumo.app.lifeplus.view.Event;
import kr.co.zumo.app.lifeplus.view.IView;
import kr.co.zumo.app.lifeplus.view.command.ActivityChangeCommand;
import kr.co.zumo.app.lifeplus.view.command.Command;

/**
 * Presenter
 * <pre>
 * </pre>
 *
 * @author 민효동
 * @version 1.0
 * @history 민효동   [2018. 9. 21.]   [최초 작성]
 * @since 2018. 9. 21.
 */
public abstract class Presenter<M extends Model, V extends IView> implements ILifeCycle, INetworkReceiverListener, IModelResult, IActionBarListener {

  protected M model;
  protected V view;
  protected Command command;

  public Presenter(M model, V view) {
    Log.i("APP# Presenter | constructor", "|" + "------------------------->> " + this.getClass().getSimpleName());
    this.model = model;
    this.view = view;

    this.model.setListener(this);
    this.model.setPresenter(this);
  }

  /**
   * Model 을 반환한다.
   * // todo 액티비티에서만 model 의 life-cycle 을 관리하기 위해서 마련
   * - 뷰에서 모델에 접근 할 수 있게되므로 오용의 여지가 있다.
   * - presenter 를 A/F 용을 별도로 만드는 등의 다른 방법이 필요...
   *
   * @return Model
   */
  public Model getModel() {
    return model;
  }

  @Override
  public final void start() {
    startInternal();
  }

  @Override
  public final void pause() {
    pauseInternal();
  }

  @Override
  public final void resume() {
    resumeInternal();
  }

  @Override
  public final void stop() {
    stopInternal();
  }

  /**
   * destroy
   */
  @Override
  public final void destroy() {
    Log.i("APP# Presenter | destroyInternal", "|" + "<<------------------------- " + this.getClass().getSimpleName());

    destroyInternal();
  }

  /***********************************
   * abstract
   ***********************************/

  /**
   * View 로 부터 전달된 이벤트를 처리한다.
   * - 공통 처리가 필요한 이벤트를 처리한 뒤
   * - 각 Presenter.onEventInternal(Event) 에서 세부 처리한다.
   *
   * @param event
   */
  public void onEvent(Event event) {
    onEventInternal(event);
  }

  protected abstract void destroyInternal();

  protected abstract void startInternal();

  protected abstract void stopInternal();

  protected abstract void resumeInternal();

  protected abstract void pauseInternal();

  /**
   * 장치 back key 눌렸을 경우 처리한다.
   * - 이벤트를 처리했다면 true 를 반환한다.
   * - false 를 반환하면 activity 에서 기본값으로 처리된다.
   *
   * @return boolean true = consumed
   */
  public abstract boolean onBackPressed();

  protected abstract void onEventInternal(Event event);

  /***********************************
   * method
   ***********************************/
  protected void onCommand(Command command) {
    this.command = command;
    Log.w("APP# Presenter | onCommand", "| " + this.getClass().getSimpleName() + ", command: " + command.getClass().getSimpleName() + ", " + new Gson().toJson(command));
    command.preExecute(model, view, this);
    command.execute(model, view, this);
    command.postExecute(model, view, this);
  }

  /***********************************
   * listener
   ***********************************/
  // INetworkReceiverListener
  @Override
  public void onChangedConnection(boolean isConnected, int type) {
    Log.i("APP# Presenter | onChangedConnection", "| " + this.getClass().getSimpleName() + ", isConnected:" + isConnected);

    if (false == isConnected) {
      onCommand(new ActivityChangeCommand(ScreenID.ACTIVITY_NETWORK_ERROR, ScreenID.DIRECTION_BACK));
    }
  }

  // IModelResult

  /**
   * Model 에서 전달되는 결과/이벤트 등을 처리한다.
   *
   * @param event
   */
  @Override
  public abstract void onResult(Event event);


  // IActionBarListener
  @Override
  public final void onClickBack(ActionBar actionBar) {
    onBackPressed();
  }
}
