package info.knacki.pass.settings.ui;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.SwitchPreference;
import android.provider.Settings;
import android.support.v4.app.ShareCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.ActionBar;
import android.util.SparseArray;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import info.knacki.gitdroid.GitInterface;
import info.knacki.gitdroid.GitInterfaceFactory;
import info.knacki.gitdroid.callback.OnResponseListener;
import info.knacki.gitdroid.entities.GitRef;
import info.knacki.pass.R;
import info.knacki.pass.io.FileInterfaceFactory;
import info.knacki.pass.io.FileMigratoryUtils;
import info.knacki.pass.io.FileUtils;
import info.knacki.pass.io.PathUtils;
import info.knacki.pass.io.pgp.GPGStorageEngine;
import info.knacki.pass.io.pgp.GPGUtil;
import info.knacki.pass.services.AccessibilityService;
import info.knacki.pass.settings.SettingsManager;
import info.knacki.pass.ui.GitPullActivity;
import info.knacki.pass.ui.alertPrompt.AlertPromptGenerator;
import info.knacki.pass.ui.alertPrompt.views.SimpleTextEdit;
import info.knacki.pass.ui.alertPrompt.views.TextView;
import info.knacki.pass.ui.alertPrompt.views.UsernameAndEmail;
import info.knacki.pass.ui.passwordPicker.PasswordPickerFactory;

/**
 * A {@link PreferenceActivity} that presents a set of application settings. On
 * handset devices, settings are presented as a single list. On tablets,
 * settings are split by category, with category headers shown to the left of
 * the list of settings.
 * <p>
 * See <a href="http://developer.android.com/design/patterns/settings.html">
 * Android Design: Settings</a> for design guidelines and the <a
 * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
 * API Guide</a> for more information on developing a Settings UI.
 */
public class SettingsActivity extends AppCompatPreferenceActivity {
    private static final Logger log = Logger.getLogger(SettingsActivity.class.getName());

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

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

    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    private void setupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            // Show the Up button in the action bar.
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            onBackPressed();
            return true;
        }
        return super.onMenuItemSelected(featureId, item);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List<Header> target) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }

    /**
     * This method stops fragment injection in malicious applications.
     * Make sure to deny any unknown fragments here.
     */
    protected boolean isValidFragment(String fragmentName) {
        return PreferenceFragment.class.getName().equals(fragmentName)
                || GeneralPreferenceFragment.class.getName().equals(fragmentName)
                || EncryptionPreferenceFragment.class.getName().equals(fragmentName)
                || VCSPreferenceFragment.class.getName().equals(fragmentName)
                || GPGPreferenceFragment.class.getName().equals(fragmentName)
                || PasswordPreferenceFragment.class.getName().equals(fragmentName);
    }

    public static class GeneralPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);
            setHasOptionsMenu(true);

            findPreference(getResources().getString(R.string.id_softSettings)).setOnPreferenceClickListener(preference -> {
                startActivity(new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS));
                return true;
            });
            findPreference(getResources().getString(R.string.id_accessibility_settings)).setOnPreferenceClickListener(preference -> {
                startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
                return true;
            });
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                findPreference(getResources().getString(R.string.id_draw_over_settings)).setOnPreferenceClickListener(preference -> {
                        startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
                    return true;
                });
            } else {
                getPreferenceScreen().removePreference(findPreference(getResources().getString(R.string.id_draw_over_settings)));
            }
        }

        @Override
        public void onResume() {
            super.onResume();
            findPreference(getResources().getString(R.string.id_softSettings)).setSummary(IsKeyboardEnabled() ? R.string.pref_summary_keyboard_enabled : R.string.pref_summary_enable_keyboard);
            if (IsAccessibilityEnabled()) {
                findPreference(getResources().getString(R.string.id_accessibility_settings)).setSummary(R.string.pref_summary_accessibility_enabled);
                Preference p = findPreference(getResources().getString(R.string.id_draw_over_settings));
                if (p != null)
                    p.setSummary(IsDrawOverEnabled() ? R.string.pref_summary_draw_over_enabled : R.string.pref_summary_draw_over_enable);
            } else {
                findPreference(getResources().getString(R.string.id_accessibility_settings)).setSummary(R.string.pref_summary_accessibility_disabled);
                Preference p = findPreference(getResources().getString(R.string.id_draw_over_settings));
                if (p != null)
                    p.setSummary(R.string.pref_summary_draw_over_unneeded);
            }
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }

        private boolean IsKeyboardEnabled() {
            InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);

            for (InputMethodInfo i: inputManager.getEnabledInputMethodList())
                if (i.getPackageName().equals(getActivity().getApplicationContext().getPackageName()))
                    return true;
            return false;
        }

        private boolean IsAccessibilityEnabled() {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2)
                return false;
            return AccessibilityService.IsEnabled(getActivity());
        }

        private boolean IsDrawOverEnabled() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
                return Settings.canDrawOverlays(getActivity());
            return true;
        }
    }

    public static class EncryptionPreferenceFragment extends PreferenceFragment {
        String[] fEncryptionMethodNames;

        protected int GetEncryptionMethodNames(SettingsManager.EncryptionType selectedType) {
            Collection<Map.Entry<SettingsManager.EncryptionType, String>> encMethods = FileInterfaceFactory.GetEncryptionMethodNames(getResources());
            fEncryptionMethodNames = new String[encMethods.size()];
            int i =0;
            int selectedIndex = -1;
            for (Map.Entry<SettingsManager.EncryptionType, String> method: encMethods) {
                if (selectedIndex == -1 && method.getKey().equals(selectedType))
                    selectedIndex = i;
                fEncryptionMethodNames[i++] = method.getValue();
            }
            return selectedIndex;
        }

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_encryption);
            setHasOptionsMenu(true);

            ListPreference encTypePref = (ListPreference) findPreference(getResources().getString(R.string.id_enc_type));
            final int encTypeIndex = GetEncryptionMethodNames(SettingsManager.GetDefaultEncryptionType(getActivity()));
            encTypePref.setEntries(fEncryptionMethodNames);
            String[] encValues = new String[fEncryptionMethodNames.length];
            for (int i =0; i < fEncryptionMethodNames.length; ++i)
                encValues[i] = "" +i;
            encTypePref.setEntryValues(encValues);
            encTypePref.setSummary(encTypePref.getEntries()[encTypeIndex]);
            encTypePref.setValueIndex(encTypeIndex);
            encTypePref.setOnPreferenceChangeListener((preference, o) -> {
                int value = Integer.parseInt(o.toString());
                preference.setSummary(((ListPreference) preference).getEntries()[value]);
                SettingsManager.SetDefaultEncryptionType(getActivity(), SettingsManager.EncryptionType.FromInt(value));
                return true;
            });

            SwitchPreference fingerPref = (SwitchPreference) findPreference(getString(R.string.id_pref_enc_type_fingerprint));
            fingerPref.setChecked(SettingsManager.IsFingerprintEnabled(getActivity()));
            fingerPref.setOnPreferenceChangeListener((preference, o) -> {
                SettingsManager.SetFingerprintEnabled(getActivity(), (Boolean) o);
                return true;
            });
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }

    public static class VCSPreferenceFragment extends PreferenceFragment {
        private static final int ACTIVITY_REQUEST_CODE_BROWSE_PRIVATE_KEY = 2;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_vcs);
            setHasOptionsMenu(true);

            abstract class PrefListener implements Preference.OnPreferenceChangeListener {
                @Override
                public boolean onPreferenceChange(Preference preference, Object o) {
                    SavePref(o);
                    VCSPreferenceFragment.this.reload();
                    return true;
                }

                abstract void SavePref(Object o);
            }

            findPreference(getResources().getString(R.string.id_vcs_enable)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    Context ctx = getActivity();
                    SettingsManager.SetVCS(ctx, (boolean) o ? new SettingsManager.Git(ctx) : null);
                }
            });
            findPreference(getResources().getString(R.string.id_vcs_list)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    SettingsManager.VCS vcs = SettingsManager.GetVCS(getActivity());
                    SettingsManager.VCS newVcs;

                    switch (Integer.parseInt((String) o)) {
                        case 0:
                            newVcs = new SettingsManager.Git(getActivity());
                            break;
                        default:
                            return;
                    }
                    if (!vcs.GetName().equals(newVcs.GetName())) {
                        SettingsManager.SetVCS(getActivity(), newVcs);
                    }
                }
            });
            findPreference(getResources().getString(R.string.id_vcs_git_url)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
                    git.SetUrl(((String) o).trim());
                    SettingsManager.SetVCS(getActivity(), git);
                }
            });

            findPreference(getResources().getString(R.string.id_vcs_git_user)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
                    git.SetUser(((String) o).trim());
                    SettingsManager.SetVCS(getActivity(), git);
                }
            });
            findPreference(getResources().getString(R.string.id_vcs_git_pass)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
                    git.SetPassword(((String) o).trim());
                    git.SetPrivateKey(false);
                    SettingsManager.SetVCS(getActivity(), git);
                }
            });
            findPreference(getResources().getString(R.string.id_vcs_git_private_key)).setOnPreferenceClickListener(preference -> {
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.setType("*/*");
                i.addCategory(Intent.CATEGORY_OPENABLE);
                VCSPreferenceFragment.this.startActivityForResult(i, ACTIVITY_REQUEST_CODE_BROWSE_PRIVATE_KEY);
                return true;
            });
            findPreference(getResources().getString(R.string.id_vcs_git_ci_username)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
                    git.SetUsername(((String) o).trim());
                    SettingsManager.SetVCS(getActivity(), git);
                }
            });
            findPreference(getResources().getString(R.string.id_vcs_git_ci_user_email)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
                    git.SetUserEmail(((String) o).trim());
                    SettingsManager.SetVCS(getActivity(), git);
                }
            });
            findPreference(getResources().getString(R.string.id_vcs_git_branches)).setOnPreferenceChangeListener(new PrefListener() {
                @Override
                void SavePref(Object o) {
                    String branch = (String) o;
                    if (branch.equals("0000")) {
                        AlertPromptGenerator.StaticMake(getActivity())
                                .setView(new SimpleTextEdit(getActivity())
                                        .setText("master"))
                                .setTitle(R.string.new_branch)
                                .setPositiveButton(R.string.ok, (d, v) -> CreateBranch(((SimpleTextEdit) v).getStr().trim()))
                                .setNegativeButton(R.string.cancel, null)
                                .show();
                    } else {
                        SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
                        git.SetBranch(branch.trim());
                        SettingsManager.SetVCS(getActivity(), git);
                    }
                }
            });

            findPreference(getResources().getString(R.string.id_vcs_git_pull)).setOnPreferenceClickListener(preference -> {
                GitPullActivity.StartSyncActivity(getActivity());
                return true;
            });
        }

        @Override
        public void onResume() {
            super.onResume();
            reload();
        }

        private void CreateBranch(String branchName) {
            if (branchName.equals(""))
                return;
            GitPullActivity.StartCreateBranchActivity(getActivity(), branchName);
        }

        final SparseArray<Preference> hiddenPreferences = new SparseArray<>();

        private void RemovePrefs(int... prefIds) {
            for (int id: prefIds) {
                Preference pref = findPreference(getResources().getString(id));
                if (pref != null) {
                    getPreferenceScreen().removePreference(pref);
                    hiddenPreferences.put(id, pref);
                }
            }
        }

        private Preference FindPreference(int prefId) {
            Preference p = findPreference(getResources().getString(prefId));
            if (p != null)
                return p;
            p = hiddenPreferences.get(prefId);
            hiddenPreferences.remove(prefId);
            if (p != null)
                getPreferenceScreen().addPreference(p);
            return p;
        }

        protected void reload() {
            final SettingsManager.VCS versioning = SettingsManager.GetVCS(getActivity());

            if (versioning != null) {
                ((SwitchPreference) findPreference(getResources().getString(R.string.id_vcs_enable))).setChecked(true);
                ListPreference vcsType = (ListPreference) FindPreference(R.string.id_vcs_list);
                vcsType.setEnabled(true);
                if (versioning instanceof SettingsManager.Git) {
                    vcsType.setValueIndex(0);
                    vcsType.setSummary(vcsType.getEntries()[0]);
                    EditTextPreference gitUrl = (EditTextPreference) FindPreference(R.string.id_vcs_git_url);
                    gitUrl.setSummary(((SettingsManager.Git) versioning).GetUrl());
                    gitUrl.setText(((SettingsManager.Git) versioning).GetUrl());

                    FindPreference(R.string.id_vcs_git_auth_category);
                    EditTextPreference gitUser = (EditTextPreference) FindPreference(R.string.id_vcs_git_user);
                    gitUser.setSummary(((SettingsManager.Git) versioning).GetUser());
                    gitUser.setText(((SettingsManager.Git) versioning).GetUser());

                    EditTextPreference gitPass = (EditTextPreference) FindPreference(R.string.id_vcs_git_pass);
                    gitPass.setSummary(((SettingsManager.Git) versioning).GetPassword().length() == 0 ? "" : "******");
                    gitPass.setText(((SettingsManager.Git) versioning).GetPassword());

                    Preference sshKey = FindPreference(R.string.id_vcs_git_private_key);
                    sshKey.setSummary(((SettingsManager.Git) versioning).HasPrivateKey() ? R.string.pref_vcs_git_private_key_change : R.string.pref_vcs_git_private_key_set);

                    FindPreference(R.string.id_vcs_git_commit_info_category);
                    ListPreference gitBranches = (ListPreference) FindPreference(R.string.id_vcs_git_branches);
                    PopulateBranches(gitBranches, (SettingsManager.Git) versioning);

                    FindPreference(R.string.id_vcs_git_pull);

                    EditTextPreference gitUsername = (EditTextPreference) FindPreference(R.string.id_vcs_git_ci_username);
                    gitUsername.setSummary(((SettingsManager.Git) versioning).GetUsername());
                    gitUsername.setDefaultValue(((SettingsManager.Git) versioning).GetUsername());

                    EditTextPreference gitUserEmail = (EditTextPreference) FindPreference(R.string.id_vcs_git_ci_user_email);
                    gitUserEmail.setSummary(((SettingsManager.Git) versioning).GetUserEmail());
                    gitUserEmail.setDefaultValue(((SettingsManager.Git) versioning).GetUserEmail());
                } else {
                    RemovePrefs(R.string.id_vcs_git_url,
                            R.string.id_vcs_git_user,
                            R.string.id_vcs_git_private_key,
                            R.string.id_vcs_git_pass,
                            R.string.id_vcs_git_branches,
                            R.string.id_vcs_git_pull,
                            R.string.id_vcs_git_ci_username,
                            R.string.id_vcs_git_ci_user_email,
                            R.string.id_vcs_git_commit_info_category,
                            R.string.id_vcs_git_auth_category);
                }
            } else {
                ((SwitchPreference) findPreference(getResources().getString(R.string.id_vcs_enable))).setChecked(false);
                ListPreference vcsType = (ListPreference) findPreference(getResources().getString(R.string.id_vcs_list));
                vcsType.setEnabled(false);
                vcsType.setSummary("");

                RemovePrefs(R.string.id_vcs_git_url,
                    R.string.id_vcs_git_user,
                    R.string.id_vcs_git_pass,
                    R.string.id_vcs_git_private_key,
                    R.string.id_vcs_git_branches,
                    R.string.id_vcs_git_pull,
                    R.string.id_vcs_git_ci_username,
                    R.string.id_vcs_git_ci_user_email,
                    R.string.id_vcs_git_commit_info_category,
                    R.string.id_vcs_git_auth_category);
            }
        }

        protected void ClearBranches(final ListPreference gitBranches) {
            gitBranches.setEntryValues(new CharSequence[]{});
            gitBranches.setEntries(new CharSequence[]{});
            gitBranches.setEnabled(false);
        }

        protected void PopulateBranches(final ListPreference gitBranches, final SettingsManager.Git versioning) {
            gitBranches.setEnabled(false);
            if (versioning != null) {
                GitInterface gitInterface;
                try {
                    gitInterface = GitInterfaceFactory.factory(versioning);
                }
                catch (GitInterfaceFactory.GitInterfaceException e) {
                    Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
                    ClearBranches(gitBranches);
                    return;
                }
                gitInterface.GetRefs(new OnResponseListener<GitRef[]>() {
                    @Override
                    public void OnResponse(final GitRef[] result) {
                        getActivity().runOnUiThread(() -> {
                            if (result == null)
                                ClearBranches(gitBranches);
                            else
                                PopulateBranches(gitBranches, versioning, result);
                        });
                    }

                    @Override
                    public void OnError(final String msg, final Throwable e) {
                        getActivity().runOnUiThread(() -> Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show());
                    }
                });
            } else {
                ClearBranches(gitBranches);
            }
        }

        private void PopulateBranches(ListPreference gitBranches, SettingsManager.Git versioning, GitRef[] result) {
            CharSequence[] refNames = new CharSequence[result.length +1];
            CharSequence[] refs = new CharSequence[result.length +1];
            int selected = -1;

            for (int i = 0; i < result.length; ++i) {
                refNames[i] = result[i].GetBranchName();
                refs[i] = result[i].GetBranch();
                if (result[i].GetBranch().equals(versioning.GetBranch()))
                    selected = i;
            }
            refNames[result.length] = getResources().getString(R.string.new_branch);
            refs[result.length] = "0000";
            gitBranches.setEntries(refNames);
            gitBranches.setEntryValues(refs);
            gitBranches.setEnabled(true);
            if (selected >= 0) {
                gitBranches.setSummary(refNames[selected]);
                gitBranches.setValueIndex(selected);
            }
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }

        private boolean SetPrivateKeyFile(InputStream in) {
            SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
            if (in != null) {
                try {
                    File fOut = new File(PathUtils.GetPrivateRSAKey(getActivity()));
                    if (!fOut.exists() && !fOut.createNewFile()) {
                        throw new FileNotFoundException();
                    }
                    FileUtils.pipe(in, new FileOutputStream(fOut));
                } catch (IOException e) {
                    log.log(Level.SEVERE, "Cannot import private key: " + e.getMessage(), e);
                    return false;
                }
            }
            git.SetPrivateKey(in != null);
            git.SetPassword("");
            SettingsManager.SetVCS(getActivity(), git);
            VCSPreferenceFragment.this.reload();
            return true;
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == ACTIVITY_REQUEST_CODE_BROWSE_PRIVATE_KEY && resultCode == RESULT_OK) {
                try {
                    final Uri intentData = data.getData();
                    boolean importStatus = SetPrivateKeyFile(intentData == null ? null : getActivity().getContentResolver().openInputStream(intentData));
                    Toast.makeText(getActivity(), getResources().getString(importStatus ? R.string.gpg_import_ok : R.string.gpg_import_ko), Toast.LENGTH_LONG).show();
                } catch (FileNotFoundException e) {
                    Toast.makeText(getActivity(), getResources().getString(R.string.file_not_found), Toast.LENGTH_LONG).show();
                    GPGStorageEngine.GetDefaultEngine(getActivity()).RemoveGpgKey();
                }
            }
        }
    }

    public static class GPGPreferenceFragment extends PreferenceFragment {
        public final static int ACTIVITY_REQUEST_CODE_BROWSE_GPG = 1;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_gpg);
            setHasOptionsMenu(true);

            findPreference(getResources().getString(R.string.id_gpg_key_file)).setOnPreferenceClickListener(preference -> {
                Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                i.setType("*/*");
                i.addCategory(Intent.CATEGORY_OPENABLE);
                GPGPreferenceFragment.this.startActivityForResult(i, ACTIVITY_REQUEST_CODE_BROWSE_GPG);
                return true;
            });
            findPreference(getResources().getString(R.string.id_gpg_generate)).setOnPreferenceClickListener(preference -> {
                AlertPromptGenerator.StaticMake(getActivity())
                        .setView(new UsernameAndEmail(getActivity()))
                        .setTitle(R.string.pref_gpg_title_username_mail)
                        .setPositiveButton(R.string.ok, (dialogInterface, v) -> {
                            byte[] keyData = GPGUtil.Generate(((UsernameAndEmail) v).GetUserAndEmail());
                            GPGStorageEngine.GetDefaultEngine(getActivity()).SetGPGKeyContent(new ByteArrayInputStream(keyData));
                            updateGpgFileLabel();
                            GPGSetPassword();
                        })
                        .setNegativeButton(R.string.cancel, null)
                        .show();
                return true;
            });
            findPreference(getResources().getString(R.string.id_gpg_password)).setOnPreferenceClickListener(preference -> {
                GPGSetPassword();
                return true;
            });
            findPreference(getResources().getString(R.string.id_gpg_export)).setOnPreferenceClickListener(preference -> {
                try {
                    if (!GPGUtil.CheckIsPasswordProtected(getActivity())) {
                        AlertPromptGenerator.StaticMake(getActivity())
                                .setCancelable(true)
                                .setPositiveButton(R.string.yes, (DialogInterface dialogInterface, View view) -> DoExportKey())
                                .setNegativeButton(R.string.no, null)
                                .setTitle(R.string.are_you_sure)
                                .setView(new TextView(getActivity()).SetText(R.string.unprotected_key))
                                .show();
                    } else {
                        DoExportKey();
                    }
                    return true;
                } catch (IOException e) {
                    return false;
                }
            });
            updateGpgFileLabel();
        }

        private void GPGSetPassword() {
            try {
                GPGUtil.ChangePassword(getActivity(), PasswordPickerFactory.GetPasswordEditor(getActivity()), new OnResponseListener<Void>() {
                    @Override
                    public void OnResponse(Void result) {
                        updateGpgFileLabel();
                    }

                    @Override
                    public void OnError(String msg, Throwable e) {
                        Toast.makeText(getActivity(), "Error: " + msg, Toast.LENGTH_LONG).show();
                    }
                });
            } catch (IOException e) {
                Toast.makeText(getActivity(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
            }
            updateGpgFileLabel();
        }

        private void DoExportKey() {
            final File outFile = new File(getActivity().getCacheDir().getAbsolutePath() + "/secret_key.gpg");
            try {
                FileUtils.Touch(outFile);
                FileOutputStream fileOut = new FileOutputStream(outFile);
                GPGStorageEngine.GetDefaultEngine(getActivity()).ExportGPGKeyContent(fileOut);
                fileOut.close();
            } catch (IOException e) {
                Toast.makeText(getActivity(), "Cannot prepare key for sharing: " + e.getMessage(), Toast.LENGTH_LONG).show();
                log.log(Level.SEVERE, "Cannot write key to cache", e);
                return;
            }
            final Uri fileUri = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", outFile);
            final Intent shareIntent = ShareCompat.IntentBuilder.from(getActivity())
                    .setStream(fileUri)
                    .setType("application/octet-stream")
                    .getIntent()
                    .setData(fileUri)
                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

            for (ResolveInfo resolveInfo : getActivity().getPackageManager().queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY))
                getActivity().grantUriPermission(resolveInfo.activityInfo.packageName, fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.id_gpg_export)));
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == ACTIVITY_REQUEST_CODE_BROWSE_GPG && resultCode == RESULT_OK) {
                try {
                    final Uri intentData = data.getData();
                    boolean gpgImportStatus;
                    if (intentData != null)
                        gpgImportStatus = GPGStorageEngine.GetDefaultEngine(getActivity()).SetGPGKeyContent(getActivity().getContentResolver().openInputStream(intentData));
                    else
                        gpgImportStatus = false;
                    Toast.makeText(getActivity(), getResources().getString(gpgImportStatus ? R.string.gpg_import_ok : R.string.gpg_import_ko), Toast.LENGTH_LONG).show();
                } catch (FileNotFoundException e) {
                    Toast.makeText(getActivity(), getResources().getString(R.string.file_not_found), Toast.LENGTH_LONG).show();
                    GPGStorageEngine.GetDefaultEngine(getActivity()).RemoveGpgKey();
                }
                updateGpgFileLabel();
            }
        }

        protected void updateGpgFileLabel() {
            if (GPGStorageEngine.GetDefaultEngine(getActivity()).HasGPGKey()) {
                findPreference(getResources().getString(R.string.id_gpg_key_file)).setSummary(GPGUtil.GetGPGKeyName(getActivity()));
                findPreference(getResources().getString(R.string.id_gpg_password)).setEnabled(true);
                findPreference(getResources().getString(R.string.id_gpg_export)).setEnabled(true);
            } else {
                findPreference(getResources().getString(R.string.id_gpg_key_file)).setSummary(R.string.pref_summary_gpg_key_file);
                findPreference(getResources().getString(R.string.id_gpg_password)).setEnabled(false);
                findPreference(getResources().getString(R.string.id_gpg_export)).setEnabled(false);
            }
        }
    }

    public static class PasswordPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_enc_password);
            setHasOptionsMenu(true);

            final Preference pwd = findPreference(getString(R.string.id_pwd_password));
            UpdateSummary();
            pwd.setOnPreferenceClickListener((preference) -> {
                PasswordPickerFactory.GetPasswordEditor(getActivity())
                    .SetStep(FileInterfaceFactory.ChangePasswordGetter.eStep.eNewPassword)
                    .GetPassword(new FileInterfaceFactory.OnPasswordEnteredListener() {
                        @Override
                        public boolean OnResponse(String password) {
                            SettingsManager.SetPassword(getActivity(), password);
                            UpdateSummary();
                            AlertPromptGenerator.StaticMake(getActivity())
                                    .setTitle(R.string.update_password)
                                    .setView(new TextView(getActivity()).SetText(R.string.update_password_confirm))
                                    .setPositiveButton(R.string.yes, (dialogInterface, view) -> FileMigratoryUtils.MigratePasswordToPassword(getActivity(), PasswordPickerFactory.GetPasswordPicker(getActivity())))
                                    .setNegativeButton(R.string.no, null)
                                    .show();
                            return true;
                        }

                        @Override
                        public void OnError(String msg, Throwable e) {

                        }
                    });
                return true;
            });
        }

        private void UpdateSummary() {
            findPreference(getString(R.string.id_pwd_password)).setSummary(SettingsManager.HasPassword(getActivity()) ? R.string.pref_summary_pwd_password : R.string.pref_summary_pwd_new_password);
        }
    }
}
