/*
 * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

package org.fdroid.fdroid.privileged.install;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.util.Log;
import android.view.ContextThemeWrapper;

import org.fdroid.fdroid.FDroid;
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.installer.PrivilegedInstaller;

import java.io.File;

import eu.chainfire.libsuperuser.Shell;

/**
 * Note: This activity has no view on its own, it displays consecutive dialogs.
 */
public class InstallExtensionDialogActivity extends FragmentActivity {

    private static final String TAG = "InstallIntoSystem";

    public static final String ACTION_INSTALL = "install";

    public static final String ACTION_UNINSTALL = "uninstall";
    public static final String ACTION_POST_INSTALL = "post_install";

    private String apkPath;

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

        // this activity itself has no content view (see manifest)

        if (getIntent().getAction() == null) {
            Log.e(TAG, "Please define an action!");
            finish();
            return;
        }

        Uri dataUri = getIntent().getData();
        if (dataUri != null) {
            File apkFile = new File(dataUri.getPath());
            apkPath = apkFile.getAbsolutePath();
        }

        switch (getIntent().getAction()) {
            case ACTION_UNINSTALL:
                uninstall();
                break;
            case ACTION_INSTALL:
                askBeforeInstall();
                break;
            case ACTION_POST_INSTALL:
                postInstall();
                break;
        }
    }

    private void askBeforeInstall() {
        // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
        ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());

        // not support on Android >= 5.1
        if (android.os.Build.VERSION.SDK_INT >= 22) {
            AlertDialog.Builder alertBuilder = new AlertDialog.Builder(theme);
            alertBuilder.setMessage(R.string.system_install_not_supported);
            alertBuilder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    InstallExtensionDialogActivity.this.setResult(Activity.RESULT_CANCELED);
                    InstallExtensionDialogActivity.this.finish();
                }
            });
            alertBuilder.create().show();
            return;
        }

        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(theme);
        alertBuilder.setTitle(R.string.system_install_question);
        String message = InstallExtension.create(getApplicationContext()).getWarningString();
        alertBuilder.setMessage(Html.fromHtml(message));
        alertBuilder.setPositiveButton(R.string.system_install_button_install, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                checkRootTask.execute();
            }
        });
        alertBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                InstallExtensionDialogActivity.this.setResult(Activity.RESULT_CANCELED);
                InstallExtensionDialogActivity.this.finish();
            }
        });
        alertBuilder.create().show();
    }

    /**
     * 1. Check for root access
     */
    private final AsyncTask<Void, Void, Boolean> checkRootTask = new AsyncTask<Void, Void, Boolean>() {
        ProgressDialog mProgressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
            ContextThemeWrapper theme = new ContextThemeWrapper(InstallExtensionDialogActivity.this,
                    FDroidApp.getCurThemeResId());

            mProgressDialog = new ProgressDialog(theme);
            mProgressDialog.setMessage(getString(R.string.requesting_root_access_body));
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.setCancelable(false);
            mProgressDialog.show();
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            return Shell.SU.available();
        }

        @Override
        protected void onPostExecute(Boolean rootGranted) {
            super.onPostExecute(rootGranted);

            mProgressDialog.dismiss();

            if (rootGranted) {
                // root access granted

                switch (getIntent().getAction()) {
                    case ACTION_UNINSTALL:
                        uninstallTask.execute();
                        break;
                    case ACTION_INSTALL:
                        installTask.execute();
                        break;
                }
            } else {
                // root access denied
                // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
                ContextThemeWrapper theme = new ContextThemeWrapper(InstallExtensionDialogActivity.this,
                        FDroidApp.getCurThemeResId());

                AlertDialog.Builder alertBuilder = new AlertDialog.Builder(theme)
                        .setTitle(R.string.root_access_denied_title)
                        .setMessage(getString(R.string.root_access_denied_body))
                        .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                InstallExtensionDialogActivity.this.setResult(Activity.RESULT_CANCELED);
                                InstallExtensionDialogActivity.this.finish();
                            }
                        });
                alertBuilder.create().show();
            }
        }
    };

    /**
     * 2. Install into system
     */
    private final AsyncTask<Void, Void, Void> installTask = new AsyncTask<Void, Void, Void>() {
        ProgressDialog mProgressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
            ContextThemeWrapper theme = new ContextThemeWrapper(InstallExtensionDialogActivity.this,
                    FDroidApp.getCurThemeResId());

            mProgressDialog = new ProgressDialog(theme);
            mProgressDialog.setMessage(InstallExtension.create(getApplicationContext()).getInstallingString());
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.setCancelable(false);
            mProgressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            InstallExtension.create(getApplicationContext()).runInstall(apkPath);
            return null;
        }
    };

    /**
     * 3. Verify that install worked
     */
    private void postInstall() {
        int isInstalledCorrectly =
                PrivilegedInstaller.isExtensionInstalledCorrectly(this);

        String title;
        String message;
        final int result;
        switch (isInstalledCorrectly) {
            case PrivilegedInstaller.IS_EXTENSION_INSTALLED_YES:
                title = getString(R.string.system_install_post_success);
                message = getString(R.string.system_install_post_success_message);
                result = Activity.RESULT_OK;
                break;
            case PrivilegedInstaller.IS_EXTENSION_INSTALLED_NO:
                title = getString(R.string.system_install_post_fail);
                message = getString(R.string.system_install_post_fail_message);
                result = Activity.RESULT_CANCELED;
                break;
            case PrivilegedInstaller.IS_EXTENSION_INSTALLED_SIGNATURE_PROBLEM:
                title = getString(R.string.system_install_post_fail);
                message = getString(R.string.system_install_post_fail_message) +
                        "\n\n" + getString(R.string.system_install_denied_signature);
                result = Activity.RESULT_CANCELED;
                break;
            default:
                throw new RuntimeException("unhandled return");
        }

        // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
        ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());

        AlertDialog.Builder builder = new AlertDialog.Builder(theme)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        InstallExtensionDialogActivity.this.setResult(result);
                        InstallExtensionDialogActivity.this.finish();
                        startActivity(new Intent(InstallExtensionDialogActivity.this, FDroid.class));
                    }
                })
                .setCancelable(false);
        builder.create().show();
    }

    private void uninstall() {
        // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
        ContextThemeWrapper theme = new ContextThemeWrapper(this, FDroidApp.getCurThemeResId());

        final boolean isInstalled = PrivilegedInstaller.isExtensionInstalled(this);

        if (isInstalled) {
            String message = InstallExtension.create(getApplicationContext()).getWarningString();

            AlertDialog.Builder builder = new AlertDialog.Builder(theme)
                    .setTitle(R.string.system_uninstall)
                    .setMessage(Html.fromHtml(message))
                    .setPositiveButton(R.string.system_uninstall_button, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            checkRootTask.execute();
                        }
                    })
                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            InstallExtensionDialogActivity.this.setResult(Activity.RESULT_CANCELED);
                            InstallExtensionDialogActivity.this.finish();
                        }
                    });
            builder.create().show();
        } else {
            throw new RuntimeException("Uninstall invoked, but extension is not installed!");
        }
    }

    private final AsyncTask<Void, Void, Void> uninstallTask = new AsyncTask<Void, Void, Void>() {
        ProgressDialog mProgressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            // hack to get theme applied (which is not automatically applied due to activity's Theme.NoDisplay
            ContextThemeWrapper theme = new ContextThemeWrapper(InstallExtensionDialogActivity.this,
                    FDroidApp.getCurThemeResId());

            mProgressDialog = new ProgressDialog(theme);
            mProgressDialog.setMessage(getString(R.string.system_install_uninstalling));
            mProgressDialog.setIndeterminate(true);
            mProgressDialog.setCancelable(false);
            mProgressDialog.show();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            InstallExtension.create(getApplicationContext()).runUninstall();
            return null;
        }

        @Override
        protected void onPostExecute(Void unused) {
            super.onPostExecute(unused);

            mProgressDialog.dismiss();

            // app is uninstalled but still display, kill it!
            System.exit(0);
        }
    };

}

