package com.pspdfkit.cordova;

import android.os.Bundle;

import androidx.annotation.NonNull;

import com.pspdfkit.cordova.event.EventDispatcher;
import com.pspdfkit.document.PdfDocument;
import com.pspdfkit.listeners.DocumentListener;
import com.pspdfkit.listeners.SimpleDocumentListener;
import com.pspdfkit.ui.PdfActivity;
import com.pspdfkit.ui.PdfFragment;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;

import static com.pspdfkit.cordova.Utilities.checkArgumentNotNull;

public class CordovaPdfActivity extends PdfActivity {

  /**
   * For communication with the JavaScript context, we keep a static reference to the current
   * activity.
   */
  private static CordovaPdfActivity currentActivity;
  private final CompositeDisposable compositeDisposable = new CompositeDisposable();

  @NonNull
  private final DocumentListener listener =
      new SimpleDocumentListener() {
        @Override
        public void onDocumentSaved(@NonNull PdfDocument document) {
          EventDispatcher.getInstance().sendEvent("onDocumentSaved", new JSONObject());
        }

        @Override
        public void onDocumentSaveFailed(
            @NonNull PdfDocument document, @NonNull Throwable exception) {
          try {
            final JSONObject data = new JSONObject();
            data.put("message", exception.getMessage());
            EventDispatcher.getInstance().sendEvent("onDocumentSaveFailed", data);
          } catch (JSONException e) {
            e.printStackTrace();
          }
        }
      };

  public static CordovaPdfActivity getCurrentActivity() {
    return currentActivity;
  }

  private void bindActivity(@NonNull final CordovaPdfActivity activity) {
    checkArgumentNotNull(activity, "activity");

    if (currentActivity != null) {
      releaseActivity();
      currentActivity.disposeSubscriptions();
    }

    currentActivity = activity;
    final PdfFragment pdfFragment = currentActivity.getPdfFragment();
    if (pdfFragment == null) {
      throw new IllegalStateException(
          "EventDispatcher only supports binding to activities that have a fragment instance.");
    }
    pdfFragment.addDocumentListener(listener);
  }

  private void releaseActivity() {
    PdfFragment fragment = currentActivity.getPdfFragment();
    if (fragment != null) {
      fragment.removeDocumentListener(listener);
    }
    currentActivity = null;
  }

  /**
   * Adds given {@link Disposable} to disposable collection which will be automatically disposed as
   * a part of onDestroy during activity finishing process.
   *
   * @param disposable to add to the disposable collection.
   */
  public void addSubscription(Disposable disposable) {
    compositeDisposable.add(disposable);
  }

  private void disposeSubscriptions() {
    compositeDisposable.dispose();
  }

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    bindActivity(this);
  }

  @Override
  protected void onDestroy() {
    if(currentActivity.equals(this)) {
      releaseActivity();

      if (isFinishing()) {
        disposeSubscriptions();
      }
    }

    super.onDestroy();
  }

  @Override
  public void finish() {
    super.finish();
    // Notify JavaScript listeners that the activity was dismissed.
    EventDispatcher.getInstance().notifyActivityDismissed();
  }

  /**
   * Dismisses this PDF activity.
   */
  public void dismiss() {
    finish();
  }

  public boolean saveDocument() throws IOException {
    final PdfDocument document = getDocument();
    if (document != null) {
      return document.saveIfModified();
    } else {
      return false;
    }
  }
}

@@ -46,25 +46,24 @@
 .os.Bundle;%0A
-%0A
 import andro
@@ -68,28 +68,17 @@
 roid
-x.annotation.NonNull
+.util.Log
 ;%0A%0Ai
@@ -433,16 +433,52 @@
 ption;%0A%0A
+import androidx.annotation.NonNull;%0A
 import i
@@ -690,16 +690,78 @@
 vity %7B%0A%0A
+  public static final String LOG_TAG = %22CordovaPdfActivity%22;%0A%0A
   /**%0A  
@@ -1012,16 +1012,127 @@
 ble();%0A%0A
+  /** Singleton document listener for dispatching events from the current activity to JavaScript interface. */%0A
   @NonNu
@@ -1150,16 +1150,23 @@
 e final 
+static 
 Document
@@ -1184,22 +1184,16 @@
 stener =
-%0A     
  new Sim
@@ -1212,28 +1212,24 @@
 istener() %7B%0A
-    
     @Overrid
@@ -1222,36 +1222,32 @@
 %7B%0A    @Override%0A
-    
     public void 
@@ -1297,28 +1297,24 @@
 nt) %7B%0A      
-   
- 
 EventDispatc
@@ -1375,28 +1375,24 @@
 NObject());%0A
-    
     %7D%0A%0A     
@@ -1390,20 +1390,16 @@
  %7D%0A%0A    
-  
-  
 @Overrid
@@ -1400,20 +1400,16 @@
 verride%0A
-    
     publ
@@ -1438,20 +1438,16 @@
 Failed(%0A
-    
         
@@ -1519,22 +1519,14 @@
     
-    
 try %7B%0A
-    
     
@@ -1579,20 +1579,16 @@
         
- 
-   
 data.put
@@ -1624,20 +1624,16 @@
 age());%0A
-    
         
@@ -1709,20 +1709,16 @@
 ;%0A      
- 
-   
 %7D catch 
@@ -1749,37 +1749,98 @@
     
-    e.printStackTrace();%0A    
+Log.e(LOG_TAG, %22Error while creating JSON payload for 'onDocumentSaveFailed' event.%22, e);%0A
     
@@ -1847,26 +1847,18 @@
   %7D%0A    
-    %7D%0A    
+%7D%0A
   %7D;%0A%0A  
@@ -2077,19 +2077,75 @@
     
-if (current
+final CordovaPdfActivity oldActivity = currentActivity;%0A    if (old
 Acti
@@ -2187,31 +2187,27 @@
 ty();%0A      
-current
+old
 Activity.dis
@@ -2604,38 +2604,30 @@
     
-PdfFragment fragment =
+// Release the
  current
 Acti
@@ -2626,117 +2626,332 @@
 rent
-A
+ a
 ctivity
-.getPdfFragment();%0A    if (fragment != null) %7B%0A      fragment.removeDocumentListener(listener);%0A    %7D
+ instance. However, we intentionally don't unregister the%0A    // document listener, so that asynchronous save events from saving the document after the%0A    // activity was destroyed, can still be relayed to the JavaScript interface.%0A    // Since the listener is static, we also don't leak the activity nor fragment.
 %0A   

Fix onDocumentSaved callback after activity onDestroy (#63)