package com.p3.bewoplaner.page.mvp;

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

import rx.Subscription;
import rx.subscriptions.CompositeSubscription;

import static com.p3.bewoplaner.utils.Preconditions.checkNotNull;
import static com.p3.bewoplaner.utils.Preconditions.checkNull;
import static com.p3.bewoplaner.utils.Preconditions.checkState;

/**
 * Created by imarneanu on 2/9/17.
 */
public abstract class MVPAbstractPresenter<V extends MVPView>
        implements MVPPresenter<V> {

    private static final int METHOD_AFTER_ATTACH = 1;
    private static final int METHOD_BEFORE_DETACH = 2;

    private V mView;
    private int mCalledThroughSuper = 0;
    private CompositeSubscription mCompositeSubscription = new CompositeSubscription();

    protected void addSubscription(Subscription subscription) {
        mCompositeSubscription.add(subscription);
    }

    @Override
    public final void attachView(@NonNull V view) {
        checkNull(mView, "view is already attached");
        mView = view;
        afterAttachView(view);
        checkState((mCalledThroughSuper & METHOD_AFTER_ATTACH) == METHOD_AFTER_ATTACH,
                "super.afterAttachView() not called");
    }

    @Override
    public final void detachView() {
        checkNotNull(mCompositeSubscription, "subscriptionList is NULL");
        mCompositeSubscription.clear();
        checkNotNull(mView, "view is not attached");
        beforeDetachView(mView);
        checkState((mCalledThroughSuper & METHOD_BEFORE_DETACH) == METHOD_BEFORE_DETACH,
                "super.beforeDetachView() not called");
        mView = null;
        mCalledThroughSuper = 0;
    }

    @Override
    public boolean isAttached() {
        return mView != null;
    }

    /**
     * Returns the view of this presenter, once it has been attached
     *
     * @return the view
     */
    @NonNull
    protected V getView() {
        checkNotNull(mView, "view is not attached");
        return mView;
    }

    /**
     * Override this to interact with the view after {@link #attachView(MVPView)} is called.
     * <p>
     * Ensure that you call through super, usually as the last
     * call in your implementation.
     *
     * @param view The view
     */
    @CallSuper
    protected void afterAttachView(@NonNull V view) {
        mCalledThroughSuper |= METHOD_AFTER_ATTACH;
    }

    /**
     * Override this to interact with the view before {@link #detachView()} is called.
     * <p>
     * Ensure that you call through super, usually as the first
     * call in your implementation.
     *
     * @param view The view
     */
    @CallSuper
    protected void beforeDetachView(@NonNull V view) {
        mCalledThroughSuper |= METHOD_BEFORE_DETACH;
    }

}