// Copyright 2004-present Facebook. All Rights Reserved.

package com.facebook.react;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;

import com.facebook.react.bridge.MemoryPressure;
import com.facebook.react.bridge.MemoryPressureListener;

import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;

/**
 * Translates and routes memory pressure events to the current catalyst instance.
 */
public class MemoryPressureRouter {
  // Trigger this by sending an intent to your activity with adb shell:
  // am start -a "com.facebook.catalyst.ACTION_TRIM_MEMORY" --activity-single-top -n <activity>
  private static final String ACTION_TRIM_MEMORY ="com.facebook.catalyst.ACTION_TRIM_MEMORY";

  private final Set<MemoryPressureListener> mListeners =
    Collections.synchronizedSet(new LinkedHashSet<MemoryPressureListener>());
  private final ComponentCallbacks2 mCallbacks = new ComponentCallbacks2() {
    @Override
    public void onTrimMemory(int level) {
      trimMemory(level);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
    }

    @Override
    public void onLowMemory() {
    }
  };

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  public static boolean handleDebugIntent(Activity activity, String action) {
    switch (action) {
      case ACTION_TRIM_MEMORY:
        simulateTrimMemory(activity, TRIM_MEMORY_MODERATE);
        break;
      default:
        return false;
    }

    return true;
  }

  MemoryPressureRouter(Context context) {
    context.getApplicationContext().registerComponentCallbacks(mCallbacks);
  }

  /**
   * Add a listener to be notified of memory pressure events.
   */
  public void addMemoryPressureListener(MemoryPressureListener listener) {
    mListeners.add(listener);
  }

  /**
   * Remove a listener previously added with {@link #addMemoryPressureListener}.
   */
  public void removeMemoryPressureListener(MemoryPressureListener listener) {
    mListeners.remove(listener);
  }

  public void destroy(Context context) {
    context.getApplicationContext().unregisterComponentCallbacks(mCallbacks);
  }

  private void trimMemory(int level) {
    if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
      dispatchMemoryPressure(MemoryPressure.CRITICAL);
    } else if (level >= TRIM_MEMORY_BACKGROUND || level == TRIM_MEMORY_RUNNING_CRITICAL) {
      dispatchMemoryPressure(MemoryPressure.MODERATE);
    }
  }

  private void dispatchMemoryPressure(MemoryPressure level) {
    // copy listeners array to avoid ConcurrentModificationException if any of the listeners remove
    // themselves in handleMemoryPressure()
    MemoryPressureListener[] listeners =
      mListeners.toArray(new MemoryPressureListener[mListeners.size()]);
    for (MemoryPressureListener listener : listeners) {
      listener.handleMemoryPressure(level);
    }
  }

  private static void simulateTrimMemory(Activity activity, int level) {
    activity.getApplication().onTrimMemory(level);
    activity.onTrimMemory(level);
  }
}

@@ -222,23 +222,26 @@
 id.app.A
-ctivity
+pplication
 ;%0Aimport
@@ -559,16 +559,88 @@
 GROUND;%0A
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE;%0A
 import s
@@ -994,18 +994,21 @@
  am 
-star
+broadcas
 t -a 
-%22
 com.
@@ -1047,45 +1047,132 @@
 MORY
-%22 --activity-single-top -n %3Cactivity%3E
+_MODERATE%0A  private static final String ACTION_TRIM_MEMORY_MODERATE =%0A    %22com.facebook.rnfeed.ACTION_TRIM_MEMORY_MODERATE%22;
 %0A  p
@@ -1216,18 +1216,32 @@
 M_MEMORY
+_CRITICAL =%0A   
  
-=
 %22com.fac
@@ -1242,32 +1242,30 @@
 om.facebook.
-catalyst
+rnfeed
 .ACTION_TRIM
@@ -1271,16 +1271,25 @@
 M_MEMORY
+_CRITICAL
 %22;%0A%0A  pr
@@ -1817,32 +1817,38 @@
 Intent(A
-ctivity activity
+pplication application
 , String
@@ -1909,16 +1909,25 @@
 M_MEMORY
+_MODERATE
 :%0A      
@@ -1948,23 +1948,26 @@
 Memory(a
-ctivity
+pplication
 , TRIM_M
@@ -1998,16 +1998,119 @@
  break;%0A
+      case ACTION_TRIM_MEMORY_CRITICAL:%0A        simulateTrimMemory(application, TRIM_MEMORY_COMPLETE);%0A
       de
@@ -3596,102 +3596,60 @@
 ry(A
-ctivity activity, int level) %7B%0A    activity.getApplication().onTrimMemory(level);%0A    activity
+pplication application, int level) %7B%0A    application
 .onT

support simulating critical memory pressure, even when activity is destroyed