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

package com.facebook.react.modules.netinfo;

import javax.annotation.Nullable;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.net.ConnectivityManagerCompat;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;

import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;

/**
 * Module that monitors and provides information about the connectivity state of the device.
 */
public class ConnectivityModule extends ReactContextBaseJavaModule
    implements LifecycleEventListener {

  private static final String CONNECTION_TYPE_NONE = "NONE";
  private static final String CONNECTION_TYPE_UNKNOWN = "UNKNOWN";

  private final ConnectivityManager mConnectivityManager;
  private final ConnectivityManagerCompat mConnectivityManagerCompat;

  private String mConnectivity;
  private @Nullable ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;

  public ConnectivityModule(ReactApplicationContext reactContext) {
    super(reactContext);
    mConnectivityManager =
        (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    mConnectivityManagerCompat = new ConnectivityManagerCompat();
    mConnectivity = "";
  }

  @Override
  public void onHostResume() {
    maybeRegisterReceiver();
    updateAndSendConnectionType();
  }

  @Override
  public void onHostPause() {
    maybeUnregisterReceiver();
  }

  @Override
  public void onHostDestroy() {
  }

  @Override
  public void initialize() {
    getReactApplicationContext().addLifecycleEventListener(this);
    maybeRegisterReceiver();
    updateAndSendConnectionType();
  }

  @Override
  public void onCatalystInstanceDestroy() {
    maybeUnregisterReceiver();
  }

  @Override
  public String getName() {
    return "NetInfo";
  }

  @ReactMethod
  public void getCurrentConnectivity(Callback successCallback, Callback errorCallback) {
    successCallback.invoke(createConnectivityEventMap());
  }

  @ReactMethod
  public void isConnectionMetered(Callback successCallback) {
    successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
  }

  private void maybeRegisterReceiver() {
    if (mConnectivityBroadcastReceiver != null) {
      return;
    }
    mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver();
    IntentFilter filter = new IntentFilter();
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    getReactApplicationContext().registerReceiver(mConnectivityBroadcastReceiver, filter);
  }

  private void maybeUnregisterReceiver() {
    if (mConnectivityBroadcastReceiver == null) {
      return;
    }
    getReactApplicationContext().unregisterReceiver(mConnectivityBroadcastReceiver);
    mConnectivityBroadcastReceiver = null;
    mConnectivity = "";
  }

  private void updateAndSendConnectionType() {
    String currentConnectivity = getCurrentConnectionType();
    // It is possible to get multiple broadcasts for the same connectivity change, so we only
    // update and send an event when the connectivity has indeed changed.
    if (!currentConnectivity.equalsIgnoreCase(mConnectivity)) {
      mConnectivity = currentConnectivity;
      sendConnectivityChangedEvent();
    }
  }

  private String getCurrentConnectionType() {
    NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
    if (networkInfo == null || !networkInfo.isConnected()) {
      return CONNECTION_TYPE_NONE;
    } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) {
      return networkInfo.getTypeName().toUpperCase();
    } else {
      return CONNECTION_TYPE_UNKNOWN;
    }
  }
  private void sendConnectivityChangedEvent() {
    getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
        .emit("networkStatusDidChange", createConnectivityEventMap());
  }

  private WritableMap createConnectivityEventMap() {
    WritableMap event = new WritableNativeMap();
    event.putString("network_info", mConnectivity);
    return event;
  }

  /**
   * Class that receives intents whenever the connection type changes.
   * NB: It is possible on some devices to receive certain connection type changes multiple times.
   */
  private class ConnectivityBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
      if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
        updateAndSendConnectionType();
      }
    }
  }
}

@@ -100,43 +100,8 @@
 o;%0A%0A
-import javax.annotation.Nullable;%0A%0A
 impo
@@ -411,16 +411,73 @@
 llback;%0A
+import com.facebook.react.bridge.LifecycleEventListener;%0A
 import c
@@ -530,55 +530,8 @@
 xt;%0A
-import com.facebook.react.bridge.ReactContext;%0A
 impo
@@ -637,65 +637,8 @@
 od;%0A
-import com.facebook.react.bridge.LifecycleEventListener;%0A
 impo
@@ -1293,17 +1293,16 @@
 Compat;%0A
-%0A
   privat
@@ -1307,49 +1307,13 @@
 ate 
-String mConnectivity;%0A  private @Nullable
+final
  Con
@@ -1372,16 +1372,54 @@
 eiver;%0A%0A
+  private String mConnectivity = %22%22;%0A%0A
   public
@@ -1696,37 +1696,87 @@
    mConnectivity
- = %22%22
+BroadcastReceiver = new ConnectivityBroadcastReceiver()
 ;%0A  %7D%0A%0A  @Overri
@@ -1809,30 +1809,25 @@
 ume() %7B%0A    
-maybeR
+r
 egisterRecei
@@ -1837,43 +1837,8 @@
 ();%0A
-    updateAndSendConnectionType();%0A
   %7D%0A
@@ -1876,38 +1876,33 @@
 stPause() %7B%0A    
-maybeU
+u
 nregisterReceive
@@ -2071,164 +2071,8 @@
 s);%0A
-    maybeRegisterReceiver();%0A    updateAndSendConnectionType();%0A  %7D%0A%0A  @Override%0A  public void onCatalystInstanceDestroy() %7B%0A    maybeUnregisterReceiver();%0A
   %7D%0A
@@ -2508,14 +2508,9 @@
 oid 
-maybeR
+r
 egis
@@ -2529,152 +2529,8 @@
 ) %7B%0A
-    if (mConnectivityBroadcastReceiver != null) %7B%0A      return;%0A    %7D%0A    mConnectivityBroadcastReceiver = new ConnectivityBroadcastReceiver();%0A
     
@@ -2749,14 +2749,9 @@
 oid 
-maybeU
+u
 nreg
@@ -2772,78 +2772,8 @@
 ) %7B%0A
-    if (mConnectivityBroadcastReceiver == null) %7B%0A      return;%0A    %7D%0A
     
@@ -2857,75 +2857,8 @@
 r);%0A
-    mConnectivityBroadcastReceiver = null;%0A    mConnectivity = %22%22;%0A
   %7D%0A

Refactor NetInfo