/*
 * Copyright 2016 Hannes Dorfmann.
 *
 * 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.hannesdorfmann.mosby3.mvi;

import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.hannesdorfmann.mosby3.ActivityMviDelegate;
import com.hannesdorfmann.mosby3.FragmentMviDelegate;
import com.hannesdorfmann.mosby3.FragmentMviDelegateImpl;
import com.hannesdorfmann.mosby3.MviDelegateCallback;
import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
import com.hannesdorfmann.mosby3.mvp.MvpView;

/**
 * <p>
 * This abstract class can be used to extend from to implement an Model-View-Intent pattern with
 * this activity as View and a {@link MviPresenter} to coordinate the View and the underlying
 * model (business logic)
 * </p>
 *
 * <p>
 * Per default {@link FragmentMviDelegateImpl} is used with the following lifecycle:
 * The View is attached to the Presenter in {@link Fragment#onViewCreated(View, Bundle)}.
 * So you better instantiate all your UI widgets before that lifecycle callback (typically in
 * {@link
 * Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}. The View is detached from Presenter in
 * {@link Fragment#onDestroyView()}
 * </p>
 *
 * @author Hannes Dorfmann
 * @since 3.0.0
 */
public abstract class MviFragment<V extends MvpView, P extends MviPresenter<V, ?>> extends Fragment
    implements MvpView, MviDelegateCallback<V, P> {

  private boolean isRestoringViewState = false;
  protected FragmentMviDelegate<V, P> mvpDelegate;

  @CallSuper @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getMvpDelegate().onCreate(savedInstanceState);
  }

  @CallSuper @Override public void onDestroy() {
    super.onDestroy();
    getMvpDelegate().onDestroy();
  }

  @CallSuper @Override public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    getMvpDelegate().onSaveInstanceState(outState);
  }

  @CallSuper @Override public void onPause() {
    super.onPause();
    getMvpDelegate().onPause();
  }

  @CallSuper @Override public void onResume() {
    super.onResume();
    getMvpDelegate().onResume();
  }

  @CallSuper @Override public void onStart() {
    super.onStart();
    getMvpDelegate().onStart();
  }

  @CallSuper @Override public void onStop() {
    super.onStop();
    getMvpDelegate().onStop();
  }

  @CallSuper @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    getMvpDelegate().onViewCreated(view, savedInstanceState);
  }

  @CallSuper @Override public void onDestroyView() {
    super.onDestroyView();
    getMvpDelegate().onDestroyView();
  }

  @CallSuper @Override public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    getMvpDelegate().onActivityCreated(savedInstanceState);
  }

  @CallSuper @Override public void onAttach(Activity activity) {
    super.onAttach(activity);
    getMvpDelegate().onAttach(activity);
  }

  @Override public void onAttach(Context context) {
    super.onAttach(context);
    getMvpDelegate().onAttach(context);
  }

  @CallSuper @Override public void onDetach() {
    super.onDetach();
    getMvpDelegate().onDetach();
  }

  @CallSuper @Override public void onAttachFragment(Fragment childFragment) {
    super.onAttachFragment(childFragment);
    getMvpDelegate().onAttachFragment(childFragment);
  }

  @CallSuper @Override public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    getMvpDelegate().onConfigurationChanged(newConfig);
  }

  /**
   * Instantiate a presenter instance
   *
   * @return The {@link MvpPresenter} for this viewState
   */
  @NonNull public abstract P createPresenter();

  /**
   * Get the mvp delegate. This is internally used for creating presenter, attaching and detaching
   * viewState from presenter.
   *
   * <p><b>Please note that only one instance of mvp delegate should be used per Activity
   * instance</b>.
   * </p>
   *
   * <p>
   * Only override this method if you really know what you are doing.
   * </p>
   *
   * @return {@link ActivityMviDelegate}
   */
  @NonNull public FragmentMviDelegate<V, P> getMvpDelegate() {
    if (mvpDelegate == null) {
      mvpDelegate = new FragmentMviDelegateImpl<V, P>(this, this);
    }

    return mvpDelegate;
  }

  @NonNull @Override public V getMvpView() {
    try {
      return (V) this;
    } catch (ClassCastException e) {
      String msg =
          "Couldn't cast the View to the corresponding View interface. Most likely you forgot to add \"Fragment implements YourMvpViewInterface\".\"";
      Log.e(this.toString(), msg);
      throw new RuntimeException(msg, e);
    }
  }

  @Override public void setRestoringViewState(boolean restoringViewState) {
    this.isRestoringViewState = restoringViewState;
  }

  protected boolean isRestoringViewState() {
    return isRestoringViewState;
  }
}

@@ -1486,24 +1486,24 @@
  * this 
-activity
+fragment
  as View
@@ -4880,24 +4880,24 @@
 sed per 
-Activity
+Fragment
 %0A   * in
@@ -5037,24 +5037,24 @@
  %7B@link 
-Activity
+Fragment
 MviDeleg

fix typo (#269)