// Copyright 2016 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.signin;

import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;

import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.preferences.ManagedPreferencesUtils;
import org.chromium.chrome.browser.widget.RadioButtonWithDescription;

import java.util.Arrays;
import java.util.List;

/**
 * A dialog that is displayed when the user switches the account they are syncing to. It gives the
 * option to merge the data of the two accounts or to keep them separate.
 */
public class ConfirmImportSyncDataDialog extends DialogFragment
        implements DialogInterface.OnClickListener {

    /**
     * Callback for completion of the dialog. Only one of {@link Listener#onConfirm} or
     * {@link Listener#onCancel} will be called and it will only be called once.
     */
    public interface Listener {
        /**
         * The user has completed the dialog using the positive button.
         * @param wipeData Whether the user requested that existing data should be wiped.
         */
        public void onConfirm(boolean wipeData);

        /**
         * The user dismisses the dialog through any means other than the positive button.
         */
        public void onCancel();
    }

    /**
     * The situation ConfirmImportSyncDataDialog is created for - whether the user had previously
     * been signed into another account, had signed out then signed into a different one, or
     * if they directly switched accounts. This changes the strings displayed.
     */
    public enum ImportSyncType { SWITCHING_SYNC_ACCOUNTS, PREVIOUS_DATA_FOUND }

    @VisibleForTesting
    public static final String CONFIRM_IMPORT_SYNC_DATA_DIALOG_TAG =
            "sync_account_switch_import_data_tag";

    private static final String KEY_OLD_ACCOUNT_NAME = "lastAccountName";
    private static final String KEY_NEW_ACCOUNT_NAME = "newAccountName";
    private static final String KEY_IMPORT_SYNC_TYPE = "importSyncType";

    private RadioButtonWithDescription mConfirmImportOption;
    private RadioButtonWithDescription mKeepSeparateOption;

    private Listener mListener;
    private boolean mListenerCalled;

    private static ConfirmImportSyncDataDialog newInstance(
            String oldAccountName, String newAccountName, ImportSyncType importSyncType) {

        ConfirmImportSyncDataDialog fragment = new ConfirmImportSyncDataDialog();
        Bundle args = new Bundle();
        args.putString(KEY_OLD_ACCOUNT_NAME, oldAccountName);
        args.putString(KEY_NEW_ACCOUNT_NAME, newAccountName);
        args.putSerializable(KEY_IMPORT_SYNC_TYPE, importSyncType);
        fragment.setArguments(args);
        return fragment;
    }

    /**
     * Creates and shows a new instance of ConfirmImportSyncDataFragment, a dialog that gives the
     * user the option to merge data between the account they are attempting to sign in to and the
     * account they were previously signed into, or to keep the data separate.
     * @param oldAccountName  The previous sync account name.
     * @param newAccountName  The potential next sync account name.
     * @param importSyncType  The situation the dialog is created in - either when directly changing
     *                        the sync account or signing in after being signed out (this changes
     *                        displayed strings).
     * @param fragmentManager FragmentManager to attach the dialog to.
     * @param callback        Callback to be called if the user completes the dialog (as opposed to
     *                        hitting cancel).
     */
    public static void showNewInstance(String oldAccountName, String newAccountName,
            ImportSyncType importSyncType, FragmentManager fragmentManager, Listener callback) {
        ConfirmImportSyncDataDialog confirmSync =
                newInstance(oldAccountName, newAccountName, importSyncType);

        confirmSync.setListener(callback);
        confirmSync.show(fragmentManager, CONFIRM_IMPORT_SYNC_DATA_DIALOG_TAG);
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // If the dialog is being recreated it won't have the listener set and so won't be
        // functional. Therefore we dismiss, and the user will need to open the dialog again.
        if (savedInstanceState != null) {
            dismiss();
        }
        String oldAccountName = getArguments().getString(KEY_OLD_ACCOUNT_NAME);
        String newAccountName = getArguments().getString(KEY_NEW_ACCOUNT_NAME);
        ImportSyncType importSyncType =
                (ImportSyncType) getArguments().getSerializable(KEY_IMPORT_SYNC_TYPE);

        LayoutInflater inflater = getActivity().getLayoutInflater();
        View v = inflater.inflate(R.layout.confirm_import_sync_data, null);

        TextView prompt = (TextView) v.findViewById(R.id.sync_import_data_prompt);

        if (importSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS) {
            prompt.setText(getActivity().getString(
                    R.string.sync_import_data_prompt_switching_accounts,
                    newAccountName, oldAccountName));
        } else {
            prompt.setText(getActivity().getString(
                    R.string.sync_import_data_prompt_existing_data,
                    newAccountName, oldAccountName));
        }

        mConfirmImportOption = (RadioButtonWithDescription)
                v.findViewById(R.id.sync_confirm_import_choice);
        mKeepSeparateOption = (RadioButtonWithDescription)
                v.findViewById(R.id.sync_keep_separate_choice);

        mConfirmImportOption.setDescriptionText(getActivity().getString(
                R.string.sync_import_existing_data_subtext, newAccountName));
        mKeepSeparateOption.setDescriptionText(getActivity().getString(
                (importSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS
                        ? R.string.sync_keep_existing_data_separate_subtext_switching_accounts
                        : R.string.sync_keep_existing_data_separate_subtext_existing_data),
                newAccountName, oldAccountName));

        List<RadioButtonWithDescription> radioGroup =
                Arrays.asList(mConfirmImportOption, mKeepSeparateOption);
        mConfirmImportOption.setRadioButtonGroup(radioGroup);
        mKeepSeparateOption.setRadioButtonGroup(radioGroup);

        // If the account is managed, disallow merging information.
        if (SigninManager.get(getActivity()).getManagementDomain() != null) {
            mKeepSeparateOption.setChecked(true);
            mConfirmImportOption.setOnClickListener(new OnClickListener(){
                @Override
                public void onClick(View v) {
                    ManagedPreferencesUtils.showManagedByAdministratorToast(getActivity());
                }
            });
        } else {
            if (importSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS) {
                mKeepSeparateOption.setChecked(true);
            } else {
                mConfirmImportOption.setChecked(true);
            }
        }

        return new AlertDialog.Builder(getActivity(), R.style.AlertDialogTheme)
                .setTitle(R.string.sync_import_data_title)
                .setPositiveButton(R.string.continue_button, this)
                .setNegativeButton(R.string.cancel, this)
                .setView(v)
                .create();
    }

    private void setListener(Listener listener) {
        assert mListener == null;
        mListener = listener;
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (mListener == null) return;

        if (which == AlertDialog.BUTTON_POSITIVE) {
            assert mConfirmImportOption.isChecked() ^ mKeepSeparateOption.isChecked();

            RecordUserAction.record(mKeepSeparateOption.isChecked()
                    ? "Signin_ImportDataPrompt_DontImport"
                    : "Signin_ImportDataPrompt_ImportData");
            mListener.onConfirm(mKeepSeparateOption.isChecked());
        } else {
            assert which == AlertDialog.BUTTON_NEGATIVE;

            RecordUserAction.record("Signin_ImportDataPrompt_Cancel");
            mListener.onCancel();
        }
        mListenerCalled = true;
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if (mListener != null && !mListenerCalled) {
            mListener.onCancel();
        }
    }
}