/*
 * Copyright (C) 2013 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, see <http://www.gnu.org/licenses/>.
 */

package org.sufficientlysecure.keychain.service.remote;

import java.util.ArrayList;

import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.view.View;
import android.widget.Toast;

import com.actionbarsherlock.app.SherlockFragmentActivity;

public class RemoteServiceActivity extends SherlockFragmentActivity {

    public static final String ACTION_REGISTER = Constants.INTENT_PREFIX + "API_ACTIVITY_REGISTER";
    public static final String ACTION_CACHE_PASSPHRASE = Constants.INTENT_PREFIX
            + "API_ACTIVITY_CACHE_PASSPHRASE";
    public static final String ACTION_SELECT_PUB_KEYS = Constants.INTENT_PREFIX
            + "API_ACTIVITY_SELECT_PUB_KEYS";
    public static final String ACTION_ERROR_MESSAGE = Constants.INTENT_PREFIX
            + "API_ACTIVITY_ERROR_MESSAGE";

    public static final String EXTRA_MESSENGER = "messenger";

    // passphrase action
    public static final String EXTRA_SECRET_KEY_ID = "secret_key_id";
    // register action
    public static final String EXTRA_PACKAGE_NAME = "package_name";
    public static final String EXTRA_PACKAGE_SIGNATURE = "package_signature";
    // select pub keys action
    public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";
    public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids";
    public static final String EXTRA_DUBLICATE_USER_IDS = "dublicate_user_ids";
    // error message
    public static final String EXTRA_ERROR_MESSAGE = "error_message";

    private Messenger mMessenger;

    // register view
    private AppSettingsFragment mSettingsFragment;
    // select pub keys view
    private SelectPublicKeyFragment mSelectFragment;

    // has the user clicked one of the buttons
    // or do we need to handle the callback in onStop()
    private boolean finishHandled;

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

        handleActions(getIntent(), savedInstanceState);
    }

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

        if (!finishHandled) {
            Message msg = Message.obtain();
            msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL;
            try {
                mMessenger.send(msg);
            } catch (RemoteException e) {
                Log.e(Constants.TAG, "CryptoServiceActivity", e);
            }
        }
    }

    protected void handleActions(Intent intent, Bundle savedInstanceState) {
        finishHandled = false;

        String action = intent.getAction();
        Bundle extras = intent.getExtras();

        if (extras == null) {
            extras = new Bundle();
        }

        mMessenger = extras.getParcelable(EXTRA_MESSENGER);

        /**
         * com.android.crypto actions
         */
        if (ACTION_REGISTER.equals(action)) {
            final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
            final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);

            // Inflate a "Done"/"Cancel" custom action bar view
            ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow,
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // Allow

                            // user needs to select a key!
                            if (mSettingsFragment.getAppSettings().getKeyId() == Id.key.none) {
                                Toast.makeText(RemoteServiceActivity.this,
                                        R.string.api_register_error_select_key, Toast.LENGTH_LONG)
                                        .show();
                            } else {
                                ProviderHelper.insertApiApp(RemoteServiceActivity.this,
                                        mSettingsFragment.getAppSettings());

                                Message msg = Message.obtain();
                                msg.arg1 = RemoteService.RegisterActivityCallback.OKAY;
                                Bundle data = new Bundle();
                                data.putString(RemoteService.RegisterActivityCallback.PACKAGE_NAME,
                                        packageName);
                                msg.setData(data);
                                try {
                                    mMessenger.send(msg);
                                } catch (RemoteException e) {
                                    Log.e(Constants.TAG, "CryptoServiceActivity", e);
                                }

                                finishHandled = true;
                                finish();
                            }
                        }
                    }, R.string.api_register_disallow, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // Disallow

                            Message msg = Message.obtain();
                            msg.arg1 = RemoteService.RegisterActivityCallback.CANCEL;
                            try {
                                mMessenger.send(msg);
                            } catch (RemoteException e) {
                                Log.e(Constants.TAG, "CryptoServiceActivity", e);
                            }

                            finishHandled = true;
                            finish();
                        }
                    });

            setContentView(R.layout.api_app_register_activity);

            mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
                    R.id.api_app_settings_fragment);

            AppSettings settings = new AppSettings(packageName, packageSignature);
            mSettingsFragment.setAppSettings(settings);
        } else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
            long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);

            showPassphraseDialog(secretKeyId);
        } else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
            long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
            ArrayList<String> missingUserIds = intent
                    .getStringArrayListExtra(EXTRA_MISSING_USER_IDS);
            ArrayList<String> dublicateUserIds = intent
                    .getStringArrayListExtra(EXTRA_DUBLICATE_USER_IDS);

            String text = new String();
            text += "<b>" + getString(R.string.api_select_pub_keys_text) + "</b>";
            text += "<br/><br/>";
            if (missingUserIds != null && missingUserIds.size() > 0) {
                text += getString(R.string.api_select_pub_keys_missing_text);
                text += "<br/>";
                text += "<ul>";
                for (String userId : missingUserIds) {
                    text += "<li>" + userId + "</li>";
                }
                text += "</ul>";
                text += "<br/>";
            }
            if (dublicateUserIds != null && dublicateUserIds.size() > 0) {
                text += getString(R.string.api_select_pub_keys_dublicates_text);
                text += "<br/>";
                text += "<ul>";
                for (String userId : dublicateUserIds) {
                    text += "<li>" + userId + "</li>";
                }
                text += "</ul>";
            }

            // Inflate a "Done"/"Cancel" custom action bar view
            ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.btn_okay,
                    new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // ok

                            Message msg = Message.obtain();
                            msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.OKAY;
                            Bundle data = new Bundle();
                            data.putLongArray(
                                    OpenPgpService.SelectPubKeysActivityCallback.PUB_KEY_IDS,
                                    mSelectFragment.getSelectedMasterKeyIds());
                            msg.setData(data);
                            try {
                                mMessenger.send(msg);
                            } catch (RemoteException e) {
                                Log.e(Constants.TAG, "CryptoServiceActivity", e);
                            }

                            finishHandled = true;
                            finish();
                        }
                    }, R.string.btn_do_not_save, new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // cancel

                            Message msg = Message.obtain();
                            msg.arg1 = OpenPgpService.SelectPubKeysActivityCallback.CANCEL;
                            ;
                            try {
                                mMessenger.send(msg);
                            } catch (RemoteException e) {
                                Log.e(Constants.TAG, "CryptoServiceActivity", e);
                            }

                            finishHandled = true;
                            finish();
                        }
                    });

            setContentView(R.layout.api_app_select_pub_keys_activity);

            // set text on view
            HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_select_pub_keys_text);
            textView.setHtmlFromString(text);

            /* Load select pub keys fragment */
            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) {

                // However, if we're being restored from a previous state,
                // then we don't need to do anything and should return or else
                // we could end up with overlapping fragments.
                if (savedInstanceState != null) {
                    return;
                }

                // Create an instance of the fragment
                mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds);

                // Add the fragment to the 'fragment_container' FrameLayout
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit();
            }
        } else if (ACTION_ERROR_MESSAGE.equals(action)) {
            String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE);

            String text = new String();
            text += "<font color=\"red\">" + errorMessage + "</font>";

            // Inflate a "Done" custom action bar view
            ActionBarHelper.setDoneView(getSupportActionBar(), R.string.btn_okay,
                    new View.OnClickListener() {

                        @Override
                        public void onClick(View v) {
                            finish();
                        }
                    });

            setContentView(R.layout.api_app_error_message);

            // set text on view
            HtmlTextView textView = (HtmlTextView) findViewById(R.id.api_app_error_message_text);
            textView.setHtmlFromString(text);
        } else {
            Log.e(Constants.TAG, "Wrong action!");
            finish();
        }
    }

    /**
     * Shows passphrase dialog to cache a new passphrase the user enters for using it later for
     * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
     * for a symmetric passphrase
     */
    private void showPassphraseDialog(long secretKeyId) {
        // Message is received after passphrase is cached
        Handler returnHandler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
                    Message msg = Message.obtain();
                    msg.arg1 = OpenPgpService.PassphraseActivityCallback.OKAY;
                    try {
                        mMessenger.send(msg);
                    } catch (RemoteException e) {
                        Log.e(Constants.TAG, "CryptoServiceActivity", e);
                    }
                } else {
                    Message msg = Message.obtain();
                    msg.arg1 = OpenPgpService.PassphraseActivityCallback.CANCEL;
                    try {
                        mMessenger.send(msg);
                    } catch (RemoteException e) {
                        Log.e(Constants.TAG, "CryptoServiceActivity", e);
                    }
                }

                finishHandled = true;
                finish();
            }
        };

        // Create a new Messenger for the communication back
        Messenger messenger = new Messenger(returnHandler);

        try {
            PassphraseDialogFragment passphraseDialog = PassphraseDialogFragment.newInstance(this,
                    messenger, secretKeyId);

            passphraseDialog.show(getSupportFragmentManager(), "passphraseDialog");
        } catch (PgpGeneralException e) {
            Log.d(Constants.TAG, "No passphrase for this secret key, encrypt directly!");
            // send message to handler to start encryption directly
            returnHandler.sendEmptyMessage(PassphraseDialogFragment.MESSAGE_OKAY);
        }
    }
}
