package com.alapshin.arctor.presenter;

import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.alapshin.arctor.view.MvpView;
import com.alapshin.arctor.viewstate.ViewStateCommand;
import com.alapshin.arctor.viewstate.ViewStateCommandQueue;

import java.lang.ref.WeakReference;

/**
 * Base presenter implementation
 *
 * @author alapshin
 * @since 2015-04-18
 */
public class BasePresenter<V extends MvpView> implements Presenter<V> {
    /**
     * How to store command into the queue after execution
     */
    public enum CommandStoreStrategy {
        /**
         * Add command to the end of the queue
         */
        ADD,
        /**
         * Clear the queue and add command the end of queue
         */
        CLEAR,
        /**
         * Add command to the end of the queue but remove previous commands of the same type from the queue
         */
        REPLACE,
        /**
         * Don't add command to the queue
         */
        SKIP
    }

    private static final String VIEW_STATE_COMMAND_QUEUE_KEY = "view_state_command_queue";
    /**
     * Reference to view. Using weak reference to avoid memory leaks. Before calling any view
     * methods check that view is attached with isViewAttached
     */
    protected WeakReference<V> viewRef;
    protected ViewStateCommandQueue<V> viewStateCommandQueue = new ViewStateCommandQueue<>();

    @Override
    @CallSuper
    @SuppressWarnings("unchecked")
    public void onCreate(@Nullable PresenterBundle savedInstanceState) {
        if (savedInstanceState != null) {
            viewStateCommandQueue = (ViewStateCommandQueue<V>) savedInstanceState.getSerializable(
                    VIEW_STATE_COMMAND_QUEUE_KEY);
        }
    }

    @Override
    @CallSuper
    public void onStart() {
    }

    @Override
    @CallSuper
    public void onResume() {
    }

    @Override
    @CallSuper
    public void onPause() {
    }

    @Override
    @CallSuper
    public void onSaveInstanceState(@NonNull PresenterBundle outState) {
        outState.putSerializable(VIEW_STATE_COMMAND_QUEUE_KEY, viewStateCommandQueue);
    }

    @Override
    @CallSuper
    public void onStop() {
    }

    @Override
    @CallSuper
    public void onDestroy() {
        viewStateCommandQueue.clear();
    }

    @Override
    @CallSuper
    public void attachView(V view) {
        this.viewRef = new WeakReference<V>(view);
        if (viewStateCommandQueue != null) {
            for (ViewStateCommand<V> command: viewStateCommandQueue) {
                command.execute(view);
            }
        }
    }

    @Override
    @CallSuper
    public void detachView() {
        if (viewRef != null) {
            viewRef.clear();
            viewRef = null;
        }
    }

    /**
     * Return currently attached view
     * @return attached view view or null if view is detached
     */
    public V getView() {
        return viewRef == null ? null : viewRef.get();
    }

    public boolean isViewAttached() {
        return viewRef != null && viewRef.get() != null;
    }

    /**
     * Execute command against view and store command into the queue
     * @param command command to execute
     * @param strategy store strategy
     */
    public void executeCommand(ViewStateCommand<V> command, CommandStoreStrategy strategy) {
        command.execute(getView());
        switch (strategy) {
            case ADD:
                viewStateCommandQueue.add(command);
                break;
            case CLEAR:
                viewStateCommandQueue.addWithClear(command);
            case REPLACE:
                viewStateCommandQueue.addWithReplace(command);
                break;
            case SKIP:
                break;
            default:
                break;
        }
    }
}

@@ -517,16 +517,108 @@
 er%3CV%3E %7B%0A
+    private static final String VIEW_STATE_COMMAND_QUEUE_KEY = %22view_state_command_queue%22;%0A%0A
     /**%0A
@@ -1157,85 +1157,90 @@
 ate 
-static final String VIEW_STATE_COMMAND_QUEUE_KEY = %22view_state_command_queue%22
+boolean isViewRecreated = false;%0A    private boolean wasViewOnCreateCalled = false
 ;%0A  
@@ -1270,16 +1270,23 @@
 to view.
+%0A     *
  Using w
@@ -1321,16 +1321,23 @@
 y leaks.
+%0A     *
  Before 
@@ -1352,23 +1352,16 @@
 any view
-%0A     *
  methods
@@ -1681,32 +1681,946 @@
 nstanceState) %7B%0A
+        // Method onCreate could be called in 3 different cases%0A        // 1. After corresponding view is created for the first time%0A        // 2. After corresponding view is recreated after configuration change%0A        // 3. After corresponding view is recreated after process death%0A%0A        // In first case savedInstanceState is null, while in second and third case it is not.%0A        // As a result to distinguish between later two cases checking for savedInstanceState alone is not enough.%0A        // To solve this problem additional flag is introduced that could be checked when savedInstanceState is not null.%0A        // When presenter's onCreate is called after configuration change this flag will be true and false otherwise.%0A        if (wasViewOnCreateCalled) %7B%0A           isViewRecreated = true;%0A        %7D else %7B%0A            isViewRecreated = false;%0A            wasViewOnCreateCalled = true;%0A        %7D%0A%0A
         if (save
@@ -4134,32 +4134,110 @@
 != null;%0A    %7D%0A%0A
+    public boolean isViewRecreated() %7B%0A        return isViewRecreated;%0A    %7D%0A%0A
     /**%0A     * E

Add mechanism to distinguish between orientation change and process restart