// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.sync.ui;

import android.accounts.Account;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;

import org.chromium.base.library_loader.ProcessInitException;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
import org.chromium.chrome.browser.sync.ProfileSyncService;
import org.chromium.chrome.browser.sync.SyncController;
import org.chromium.components.signin.ChromeSigninController;

/**
 * This activity is used for requesting a sync passphrase from the user. Typically,
 * this will be the target of an Android notification.
 */
public class PassphraseActivity extends FragmentActivity implements
        PassphraseDialogFragment.Listener,
        FragmentManager.OnBackStackChangedListener {

    public static final String FRAGMENT_PASSPHRASE = "passphrase_fragment";
    public static final String FRAGMENT_SPINNER = "spinner_fragment";
    private static final String TAG = "PassphraseActivity";

    private ProfileSyncService.SyncStateChangedListener mSyncStateChangedListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The Chrome browser process must be started here because this Activity
        // may be started explicitly from Android notifications.
        // During a normal user flow the ChromeTabbedActivity would start the Chrome browser
        // process and this wouldn't be necessary.
        try {
            ChromeBrowserInitializer.getInstance(this).handleSynchronousStartup();
        } catch (ProcessInitException e) {
            Log.e(TAG, "Failed to start browser process.", e);
            ChromeApplication.reportStartupErrorAndExit(e);
            return;
        }
        assert ProfileSyncService.get() != null;
        getFragmentManager().addOnBackStackChangedListener(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Account account = ChromeSigninController.get(this).getSignedInUser();
        if (account == null) {
            finish();
            return;
        }

        if (!isShowingDialog(FRAGMENT_PASSPHRASE)) {
            if (ProfileSyncService.get().isBackendInitialized()) {
                displayPassphraseDialog();
            } else {
                addSyncStateChangedListener();
                displaySpinnerDialog();
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Make sure we don't receive callbacks while in the background.
        // See http://crbug.com/469890.
        removeSyncStateChangedListener();
    }

    private void addSyncStateChangedListener() {
        if (mSyncStateChangedListener != null) {
            return;
        }
        mSyncStateChangedListener = new ProfileSyncService.SyncStateChangedListener() {
            @Override
            public void syncStateChanged() {
                if (ProfileSyncService.get().isBackendInitialized()) {
                    removeSyncStateChangedListener();
                    displayPassphraseDialog();
                }
            }
        };
        ProfileSyncService.get().addSyncStateChangedListener(mSyncStateChangedListener);
    }

    private void removeSyncStateChangedListener() {
        if (mSyncStateChangedListener != null) {
            ProfileSyncService.get().removeSyncStateChangedListener(mSyncStateChangedListener);
            mSyncStateChangedListener = null;
        }
    }

    private boolean isShowingDialog(String tag) {
        return getFragmentManager().findFragmentByTag(tag) != null;
    }

    private void displayPassphraseDialog() {
        assert ProfileSyncService.get().isBackendInitialized();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.addToBackStack(null);
        PassphraseDialogFragment.newInstance(null).show(ft, FRAGMENT_PASSPHRASE);
    }

    private void displaySpinnerDialog() {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.addToBackStack(null);
        SpinnerDialogFragment dialog = new SpinnerDialogFragment();
        dialog.show(ft, FRAGMENT_SPINNER);
    }

    /**
     * Callback for PassphraseDialogFragment.Listener
     */
    @Override
    public boolean onPassphraseEntered(String passphrase) {
        if (!passphrase.isEmpty() && ProfileSyncService.get().setDecryptionPassphrase(passphrase)) {
            // The passphrase was correct - close this activity.
            finish();
            return true;
        }
        return false;
    }

    @Override
    public void onPassphraseCanceled() {
        // Re add the notification.
        SyncController.get(this).getSyncNotificationController().syncStateChanged();
        finish();
    }

    @Override
    public void onBackStackChanged() {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            finish();
        }
    }

    /**
     * Dialog shown while sync is loading.
     */
    public static class SpinnerDialogFragment extends DialogFragment {
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            ProgressDialog dialog = new ProgressDialog(getActivity());
            dialog.setMessage(getResources().getString(R.string.sync_loading));
            return dialog;
        }
    }
}