/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.facebook.fresco.vito.view.impl;

import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import com.facebook.common.internal.Preconditions;
import com.facebook.drawee.drawable.VisibilityCallback;
import com.facebook.fresco.vito.core.FrescoController2;
import com.facebook.fresco.vito.core.FrescoDrawable2;
import com.facebook.fresco.vito.core.VitoImagePipeline;
import com.facebook.fresco.vito.core.VitoImageRequest;
import com.facebook.fresco.vito.core.VitoUtils;
import com.facebook.fresco.vito.listener.ImageListener;
import com.facebook.fresco.vito.options.ImageOptions;
import com.facebook.fresco.vito.view.VitoView;
import com.facebook.imagepipeline.multiuri.MultiUri;

/** You must initialize this class before use by calling {#code VitoView.init()}. */
@Deprecated /* Experimental */
public class VitoViewImpl2 implements VitoView.Implementation {

  private final View.OnAttachStateChangeListener sOnAttachStateChangeListenerCallback =
      new View.OnAttachStateChangeListener() {
        @Override
        public void onViewAttachedToWindow(View view) {
          FrescoDrawable2 current = getDrawable(view);
          if (current != null) {
            onAttach(current);
          }
        }

        @Override
        public void onViewDetachedFromWindow(View view) {
          FrescoDrawable2 current = getDrawable(view);
          if (current != null) {
            onDetach(current);
          }
        }
      };

  private final FrescoController2 mController;
  private final VitoImagePipeline mVitoImagePipeline;

  public VitoViewImpl2(FrescoController2 controller, VitoImagePipeline vitoImagePipeline) {
    mController = controller;
    mVitoImagePipeline = vitoImagePipeline;
  }

  @Override
  public void show(
      final @Nullable Uri uri,
      final @Nullable MultiUri multiUri,
      final ImageOptions imageOptions,
      final @Nullable Object callerContext,
      final @Nullable ImageListener imageListener,
      final View target) {
    Preconditions.checkArgument(
        !(uri != null && multiUri != null), "Setting both a Uri and MultiUri is not allowed!");

    VitoImageRequest imageRequest =
        mVitoImagePipeline.createImageRequest(
            target.getResources(), uri, multiUri, imageOptions, callerContext);

    final FrescoDrawable2 frescoDrawable = ensureDrawableSet(target);

    // Check if we already fetched the image
    if (frescoDrawable.getDrawableDataSubscriber() != null
        && frescoDrawable.isFetchSubmitted()
        && imageRequest.equals(frescoDrawable.getImageRequest())) {
      frescoDrawable.cancelReleaseNextFrame();
      frescoDrawable.cancelReleaseDelayed();
      return; // already set
    }

    frescoDrawable.setImageRequest(imageRequest);
    frescoDrawable.setCallerContext(callerContext);
    frescoDrawable.setImageId(VitoUtils.generateIdentifier());

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
      // If the view is already attached, we should tell this to controller.
      if (target.isAttachedToWindow()) {
        onAttach(frescoDrawable);
      }
    } else {
      // Before Kitkat we don't have a good way to know.
      // Normally we expect the view to be already attached, thus we always call `onAttach`.
      onAttach(frescoDrawable);
    }

    // `addOnAttachStateChangeListener` is not idempotent
    target.removeOnAttachStateChangeListener(sOnAttachStateChangeListenerCallback);
    target.addOnAttachStateChangeListener(sOnAttachStateChangeListenerCallback);
  }

  private void onAttach(final FrescoDrawable2 drawable) {
    drawable.cancelReleaseNextFrame();
    VitoImageRequest request = drawable.getImageRequest();
    if (request != null) {
      mController.fetch(drawable, request, drawable.getCallerContext(), null, null);
    }
  }

  private void onDetach(FrescoDrawable2 drawable) {
    drawable.scheduleReleaseNextFrame();
  }

  /**
   * Ensure that a {@link FrescoDrawable2} is set for the given View target
   *
   * @param target the target to use
   * @return The drawable to use for the given target
   */
  private FrescoDrawable2 ensureDrawableSet(final View target) {
    if (target instanceof ImageView) {
      ImageView iv = (ImageView) target;
      Drawable current = iv.getDrawable();
      if (current instanceof FrescoDrawable2) {
        return (FrescoDrawable2) current;
      } else {
        FrescoDrawable2 drawable = createDrawable();
        iv.setImageDrawable(drawable);
        return drawable;
      }
    }
    final Drawable background = target.getBackground();
    if (background instanceof FrescoDrawable2) {
      return (FrescoDrawable2) background;
    }
    FrescoDrawable2 drawable = createDrawable();
    ViewCompat.setBackground(target, drawable);
    return drawable;
  }

  @Nullable
  private static FrescoDrawable2 getDrawable(final View view) {
    Drawable d =
        view instanceof ImageView ? ((ImageView) view).getDrawable() : view.getBackground();
    return d instanceof FrescoDrawable2 ? (FrescoDrawable2) d : null;
  }

  private FrescoDrawable2 createDrawable() {
    final FrescoDrawable2 frescoDrawable = mController.createDrawable();

    frescoDrawable.setVisibilityCallback(
        new VisibilityCallback() {
          @Override
          public void onVisibilityChange(boolean visible) {
            if (!visible) {
              onDetach(frescoDrawable);
            } else {
              onAttach(frescoDrawable);
            }
          }

          @Override
          public void onDraw() {
            // NOP
          }
        });
    return frescoDrawable;
  }
}

@@ -1538,35 +1538,62 @@
 onAttach(current
+, current.getImageRequest()
 );%0A
-
           %7D%0A    
@@ -2733,519 +2733,8 @@
 );%0A%0A
-    // Check if we already fetched the image%0A    if (frescoDrawable.getDrawableDataSubscriber() != null%0A        && frescoDrawable.isFetchSubmitted()%0A        && imageRequest.equals(frescoDrawable.getImageRequest())) %7B%0A      frescoDrawable.cancelReleaseNextFrame();%0A      frescoDrawable.cancelReleaseDelayed();%0A      return; // already set%0A    %7D%0A%0A    frescoDrawable.setImageRequest(imageRequest);%0A    frescoDrawable.setCallerContext(callerContext);%0A    frescoDrawable.setImageId(VitoUtils.generateIdentifier());%0A%0A
     
@@ -2933,32 +2933,46 @@
 h(frescoDrawable
+, imageRequest
 );%0A      %7D%0A    %7D
@@ -3154,24 +3154,38 @@
 escoDrawable
+, imageRequest
 );%0A    %7D%0A%0A  
@@ -3468,109 +3468,43 @@
 able
-) %7B%0A    drawable.cancelReleaseNextFrame();%0A    VitoImageRequest request = drawable.getImageRequest();
+, final VitoImageRequest request) %7B
 %0A   
@@ -5224,32 +5224,32 @@
        %7D else %7B%0A
-
               on
@@ -5261,32 +5261,66 @@
 h(frescoDrawable
+, frescoDrawable.getImageRequest()
 );%0A            %7D

Clean up VitoView: Remove unnecessary checks that cause images to not load