/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.drawee.controller;

import android.graphics.drawable.Animatable;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;

/**
 * Listener that forwards controller events to multiple listeners.
 */
@ThreadSafe
public class ForwardingControllerListener<INFO> implements ControllerListener<INFO> {
  // lint only allows 23 characters in a tag
  private static final String TAG = "FdingControllerListener";

  private final List<ControllerListener<? super INFO>> mListeners = new ArrayList<>(2);

  public ForwardingControllerListener() {
  }

  public static <INFO> ForwardingControllerListener<INFO> create() {
    return new ForwardingControllerListener<INFO>();
  }

  public static <INFO> ForwardingControllerListener<INFO> of(
      ControllerListener<? super INFO> listener) {
    ForwardingControllerListener<INFO> forwarder = create();
    forwarder.addListener(listener);
    return forwarder;
  }

  public static <INFO> ForwardingControllerListener<INFO> of(
      ControllerListener<? super INFO> listener1,
      ControllerListener<? super INFO> listener2) {
    ForwardingControllerListener<INFO> forwarder = create();
    forwarder.addListener(listener1);
    forwarder.addListener(listener2);
    return forwarder;
  }

  public synchronized void addListener(ControllerListener<? super INFO> listener) {
    mListeners.add(listener);
  }

  public synchronized void removeListener(ControllerListener<? super INFO> listener) {
    mListeners.remove(listener);
  }

  public synchronized void clearListeners() {
    mListeners.clear();
  }

  private synchronized void onException(String message, Throwable t) {
    Log.e(TAG, message, t);
  }

  @Override
  public synchronized void onSubmit(String id, Object callerContext) {
    final int numberOfListeners = mListeners.size();
    for (int i = 0; i < numberOfListeners; ++i) {
      try {
        ControllerListener<? super INFO> listener = mListeners.get(i);
        listener.onSubmit(id, callerContext);
      } catch (Exception exception) {
        // Don't punish the other listeners if we're given a bad one.
        onException("InternalListener exception in onSubmit", exception);
      }
    }
  }

  @Override
  public synchronized void onFinalImageSet(
      String id,
      @Nullable INFO imageInfo,
      @Nullable Animatable animatable) {
    final int numberOfListeners = mListeners.size();
    for (int i = 0; i < numberOfListeners; ++i) {
      try {
        ControllerListener<? super INFO> listener = mListeners.get(i);
        listener.onFinalImageSet(id, imageInfo, animatable);
      } catch (Exception exception) {
        // Don't punish the other listeners if we're given a bad one.
        onException("InternalListener exception in onFinalImageSet", exception);
      }
    }
  }

  @Override
  public void onIntermediateImageSet(String id, @Nullable INFO imageInfo) {
    final int numberOfListeners = mListeners.size();
    for (int i = 0; i < numberOfListeners; ++i) {
      try {
        ControllerListener<? super INFO> listener = mListeners.get(i);
        listener.onIntermediateImageSet(id, imageInfo);
      } catch (Exception exception) {
        // Don't punish the other listeners if we're given a bad one.
        onException("InternalListener exception in onIntermediateImageSet", exception);
      }
    }
  }

  @Override
  public void onIntermediateImageFailed(String id, Throwable throwable) {
    final int numberOfListeners = mListeners.size();
    for (int i = 0; i < numberOfListeners; ++i) {
      try {
        ControllerListener<? super INFO> listener = mListeners.get(i);
        listener.onIntermediateImageFailed(id, throwable);
      } catch (Exception exception) {
        // Don't punish the other listeners if we're given a bad one.
        onException("InternalListener exception in onIntermediateImageFailed", exception);
      }
    }
  }

  @Override
  public synchronized void onFailure(String id, Throwable throwable) {
    final int numberOfListeners = mListeners.size();
    for (int i = 0; i < numberOfListeners; ++i) {
      try {
        ControllerListener<? super INFO> listener = mListeners.get(i);
        listener.onFailure(id, throwable);
      } catch (Exception exception) {
        // Don't punish the other listeners if we're given a bad one.
        onException("InternalListener exception in onFailure", exception);
      }
    }
  }

  @Override
  public synchronized void onRelease(String id) {
    final int numberOfListeners = mListeners.size();
    for (int i = 0; i < numberOfListeners; ++i) {
      try {
        ControllerListener<? super INFO> listener = mListeners.get(i);
        listener.onRelease(id);
      } catch (Exception exception) {
        // Don't punish the other listeners if we're given a bad one.
        onException("InternalListener exception in onRelease", exception);
      }
    }
  }
}

@@ -1871,36 +1871,113 @@
     
-mListeners.remove(listener);
+int index = mListeners.indexOf(listener);%0A    if (index != -1) %7B%0A      mListeners.set(index, null);%0A    %7D
 %0A  %7D
@@ -2418,32 +2418,66 @@
 steners.get(i);%0A
+        if (listener != null) %7B%0A  
         listener
@@ -2506,16 +2506,26 @@
 ntext);%0A
+        %7D%0A
       %7D 
@@ -3041,32 +3041,66 @@
 steners.get(i);%0A
+        if (listener != null) %7B%0A  
         listener
@@ -3140,24 +3140,34 @@
 nimatable);%0A
+        %7D%0A
       %7D catc
@@ -3628,32 +3628,66 @@
 steners.get(i);%0A
+        if (listener != null) %7B%0A  
         listener
@@ -3726,16 +3726,26 @@
 eInfo);%0A
+        %7D%0A
       %7D 
@@ -4215,32 +4215,66 @@
 steners.get(i);%0A
+        if (listener != null) %7B%0A  
         listener
@@ -4308,32 +4308,42 @@
 id, throwable);%0A
+        %7D%0A
       %7D catch (E
@@ -4805,32 +4805,66 @@
 steners.get(i);%0A
+        if (listener != null) %7B%0A  
         listener
@@ -4886,24 +4886,34 @@
 throwable);%0A
+        %7D%0A
       %7D catc
@@ -5342,32 +5342,66 @@
 steners.get(i);%0A
+        if (listener != null) %7B%0A  
         listener
@@ -5416,16 +5416,26 @@
 se(id);%0A
+        %7D%0A
       %7D 

Fix IndexOOBExceptionin ForwardingControllerListener