/*
 * Copyright (C) 2019 Peng fei Pan <[email protected]>
 *
 * 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 me.panpf.sketch.viewfun;

import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import me.panpf.sketch.SketchView;
import me.panpf.sketch.drawable.SketchDrawable;
import me.panpf.sketch.drawable.SketchGifDrawable;
import me.panpf.sketch.drawable.SketchLoadingDrawable;
import me.panpf.sketch.drawable.SketchRefDrawable;
import me.panpf.sketch.request.CancelCause;
import me.panpf.sketch.request.DisplayCache;
import me.panpf.sketch.request.DisplayOptions;
import me.panpf.sketch.request.DisplayRequest;
import me.panpf.sketch.util.SketchUtils;

/**
 * 请求基本功能,更新图片显示引用计数和在onDetachedFromWindow的时候取消请求并清空图片
 */
@SuppressWarnings("WeakerAccess")
public class RequestFunction extends ViewFunction {
    @NonNull
    private SketchView sketchView;

    @NonNull
    private DisplayOptions displayOptions = new DisplayOptions();
    @Nullable
    private DisplayCache displayCache;

    private boolean oldDrawableFromSketch;
    private boolean newDrawableFromSketch;

    public RequestFunction(@NonNull SketchView sketchView) {
        this.sketchView = sketchView;
    }

    /**
     * 修改Drawable显示状态
     *
     * @param callingStation 调用位置
     * @param drawable       Drawable
     * @param isDisplayed    是否已显示
     * @return true:drawable或其子Drawable是SketchDrawable
     */
    private static boolean notifyDrawable(@NonNull String callingStation, @Nullable Drawable drawable, final boolean isDisplayed) {
        if (drawable == null) {
            return false;
        }

        boolean isSketchDrawable = false;

        if (drawable instanceof LayerDrawable) {
            LayerDrawable layerDrawable = (LayerDrawable) drawable;
            for (int i = 0, z = layerDrawable.getNumberOfLayers(); i < z; i++) {
                isSketchDrawable |= notifyDrawable(callingStation, layerDrawable.getDrawable(i), isDisplayed);
            }
        } else {
            if (!isDisplayed && drawable instanceof SketchLoadingDrawable) {
                SketchLoadingDrawable loadingDrawable = (SketchLoadingDrawable) drawable;
                DisplayRequest displayRequest = loadingDrawable.getRequest();
                if (displayRequest != null && !displayRequest.isFinished()) {
                    displayRequest.cancel(CancelCause.BE_REPLACED_ON_SET_DRAWABLE);
                }
            }

            if (drawable instanceof SketchRefDrawable) {
                ((SketchRefDrawable) drawable).setIsDisplayed(callingStation, isDisplayed);
            } else if (drawable instanceof SketchGifDrawable) {
                if (!isDisplayed) {
                    ((SketchGifDrawable) drawable).recycle();
                }
            }

            isSketchDrawable = drawable instanceof SketchDrawable;
        }

        return isSketchDrawable;
    }

    @Override
    public boolean onDetachedFromWindow() {
        // 主动取消请求
        DisplayRequest potentialRequest = SketchUtils.findDisplayRequest(sketchView);
        if (potentialRequest != null && !potentialRequest.isFinished()) {
            potentialRequest.cancel(CancelCause.ON_DETACHED_FROM_WINDOW);
        }
        // todo 尝试不再主动清空图片

        // 如果当前图片是来自Sketch,那么就有可能在这里被主动回收,因此要主动设置ImageView的drawable为null
        final Drawable oldDrawable = sketchView.getDrawable();
        return notifyDrawable("onDetachedFromWindow", oldDrawable, false);
    }

    @Override
    public boolean onDrawableChanged(@NonNull String callPosition, @Nullable Drawable oldDrawable, @Nullable Drawable newDrawable) {
        // 当Drawable改变的时候新Drawable的显示引用计数加1,旧Drawable的显示引用计数减1,一定要先处理newDrawable
        newDrawableFromSketch = notifyDrawable(callPosition + ":newDrawable", newDrawable, true);
        oldDrawableFromSketch = notifyDrawable(callPosition + ":oldDrawable", oldDrawable, false);

        // 如果新Drawable不是来自Sketch,那么就要清空显示参数,防止被RecyclerCompatFunction在onAttachedToWindow的时候错误的恢复成上一张图片
        if (!newDrawableFromSketch) {
            displayCache = null;
        }

        return false;
    }

    @Nullable
    public DisplayCache getDisplayCache() {
        return displayCache;
    }

    public void setDisplayCache(@Nullable DisplayCache displayCache) {
        this.displayCache = displayCache;
    }

    public boolean isOldDrawableFromSketch() {
        return oldDrawableFromSketch;
    }

    public boolean isNewDrawableFromSketch() {
        return newDrawableFromSketch;
    }

    @NonNull
    public DisplayOptions getDisplayOptions() {
        return displayOptions;
    }

    public void clean(){
        if (displayCache != null) {
            displayCache.uri = null;
            displayCache.options.reset();
        }
    }
}