package fr.free.nrw.commons.auth;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.os.AsyncTask;
import android.os.Bundle;

import java.io.IOException;

import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.theme.NavigationBaseActivity;
import timber.log.Timber;

public abstract class AuthenticatedActivity extends NavigationBaseActivity {

    String accountType;
    CommonsApplication app;

    private String authCookie;
    
    public AuthenticatedActivity() {
        this.accountType = AccountUtil.accountType();
    }
   
    private class GetAuthCookieTask extends AsyncTask<Void, String, String> {
        private Account account;
        private AccountManager accountManager;
        public GetAuthCookieTask(Account account, AccountManager accountManager) {
            this.account = account;
            this.accountManager = accountManager;
        }
        
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if(result != null) {
                authCookie = result;
                onAuthCookieAcquired(result);
            } else {
                onAuthFailure();
            }
        }

        @Override
        protected String doInBackground(Void... params) {
            try {
                return accountManager.blockingGetAuthToken(account, "", false);
            } catch (OperationCanceledException e) {
                e.printStackTrace();
                return null;
            } catch (AuthenticatorException e) {
                e.printStackTrace();
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    
    private class AddAccountTask extends AsyncTask<Void, String, String> {
        private AccountManager accountManager;
        public AddAccountTask(AccountManager accountManager) {
            this.accountManager = accountManager;
        }
        
        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            if(result != null) {
                Account[] allAccounts =accountManager.getAccountsByType(accountType);
                Account curAccount = allAccounts[0];
                GetAuthCookieTask getCookieTask = new GetAuthCookieTask(curAccount, accountManager);
                getCookieTask.execute();
            } else {
                onAuthFailure();
            }
        }

        @Override
        protected String doInBackground(Void... params) {
            AccountManagerFuture<Bundle> resultFuture = accountManager.addAccount(accountType, null, null, null, AuthenticatedActivity.this, null, null);
            Bundle result;
            try {
                result = resultFuture.getResult();
            } catch (OperationCanceledException e) {
                e.printStackTrace();
                return null;
            } catch (AuthenticatorException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
            if(result.containsKey(AccountManager.KEY_ACCOUNT_NAME)) {
                return result.getString(AccountManager.KEY_ACCOUNT_NAME);
            } else {
                return null;
            }
            
        }
    }

    protected void requestAuthToken() {
        if(authCookie != null) {
            onAuthCookieAcquired(authCookie);
            return;
        }
        AccountManager accountManager = AccountManager.get(this);
        Account curAccount = app.getCurrentAccount();
        if(curAccount == null) {
            AddAccountTask addAccountTask = new AddAccountTask(accountManager);
            // This AsyncTask blocks until the Login Activity returns
            // And since in Android 4.x+ only one background thread runs all AsyncTasks
            // And since LoginActivity can't return until it's own AsyncTask (that does the login)
            // returns, we have a deadlock!
            // Fixed by explicitly asking this to be executed in parallel
            // See: https://groups.google.com/forum/?fromgroups=#!topic/android-developers/8M0RTFfO7-M
            addAccountTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        } else {
            GetAuthCookieTask task = new GetAuthCookieTask(curAccount, accountManager);
            task.execute();
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        app = CommonsApplication.getInstance();
        if(savedInstanceState != null) {
            authCookie = savedInstanceState.getString("authCookie");
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("authCookie", authCookie);
    }

    protected abstract void onAuthCookieAcquired(String authCookie);
    protected abstract void onAuthFailure();
}

@@ -436,16 +436,145 @@
 tivity;%0A
+import io.reactivex.Single;%0Aimport io.reactivex.android.schedulers.AndroidSchedulers;%0Aimport io.reactivex.schedulers.Schedulers;%0A
 import t
@@ -856,19 +856,16 @@
 ;%0A    %7D%0A
-   
 %0A    pri
@@ -873,170 +873,14 @@
 ate 
-class GetAuthCookieTask extends AsyncTask%3CVoid, String, String%3E %7B%0A        private Account account;%0A        private AccountManager accountManager;%0A        public G
+void g
 etAu
@@ -887,20 +887,16 @@
 thCookie
-Task
 (Account
@@ -950,529 +950,33 @@
     
-    this.account = account;%0A            this.accountManager = accountManager;%0A        %7D%0A        %0A        @Override%0A        protected void onPostExecute(String result) %7B%0A            super.onPostExecute(result);%0A            if(result != null) %7B%0A                authCookie = result;%0A                onAuthCookieAcquired(result);%0A            %7D else %7B%0A                onAuthFailure();%0A            %7D%0A        %7D%0A%0A        @Override%0A        protected String doInBackground(Void... params) %7B%0A            try %7B%0A                return
+Single.fromCallable(() -%3E
  acc
@@ -1027,17 +1027,17 @@
 , false)
-;
+)
 %0A       
@@ -1045,357 +1045,285 @@
     
-%7D catch (OperationCanceledException e) %7B%0A                e.printStackTrace();%0A                return null;%0A            %7D catch (AuthenticatorException e) %7B%0A                e.printStackTrace();%0A                return null;%0A            %7D catch (IOException e) %7B%0A                e.printStackTrace();%0A                return null;%0A            %7D%0A        %7D
+    .subscribeOn(Schedulers.io())%0A                .doOnError(Timber::e)%0A                .observeOn(AndroidSchedulers.mainThread())%0A                .subscribe(%0A                        cookie -%3E onAuthCookieAcquired(cookie),%0A                        throwable -%3E onAuthFailure());
 %0A   
@@ -1769,16 +1769,17 @@
 counts =
+ 
 accountM
@@ -1890,47 +1890,9 @@
     
-GetAuthCookieTask getCookieTask = new G
+g
 etAu
@@ -1891,36 +1891,32 @@
    getAuthCookie
-Task
 (curAccount, acc
@@ -1933,49 +1933,8 @@
 r);%0A
-                getCookieTask.execute();%0A
     
@@ -3997,38 +3997,9 @@
     
-GetAuthCookieTask task = new G
+g
 etAu
@@ -4006,20 +4006,16 @@
 thCookie
-Task
 (curAcco
@@ -4040,36 +4040,8 @@
 r);%0A
-            task.execute();%0A
     

Simplify `GetAuthCookie` task