/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.email.activity.setup;

import com.android.email.R;
import com.android.email.provider.EmailContent;
import com.android.email.provider.ProviderTestUtils;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.HostAuth;

import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.MediumTest;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;

import java.net.URI;
import java.net.URISyntaxException;

/**
 * Tests of the basic UI logic in the Account Setup Incoming (IMAP / POP3) screen.
 */
@MediumTest
public class AccountSetupExchangeTests extends
        ActivityInstrumentationTestCase2<AccountSetupExchange> {
    //EXCHANGE-REMOVE-SECTION-START
    private AccountSetupExchange mActivity;
    private EditText mServerView;
    private EditText mPasswordView;
    private Button mNextButton;
    private CheckBox mSslRequiredCheckbox;
    private CheckBox mTrustAllCertificatesCheckbox;
    //EXCHANGE-REMOVE-SECTION-END

    public AccountSetupExchangeTests() {
        super(AccountSetupExchange.class);
    }

    //EXCHANGE-REMOVE-SECTION-START
    /**
     * Common setup code for all tests.  Sets up a default launch intent, which some tests
     * will use (others will override).
     */
    @Override
    protected void setUp() throws Exception {
        super.setUp();

        // This sets up a default URI which can be used by any of the test methods below.
        // Individual test methods can replace this with a custom URI if they wish
        // (except those that run on the UI thread - for them, it's too late to change it.)
        Intent i = getTestIntent("eas://user:password@server.com");
        setActivityIntent(i);
    }

    /**
     * Test processing with a complete, good URI -> good fields
     */
    public void testGoodUri() {
        Intent i = getTestIntent("eas://user:password@server.com");
        setActivityIntent(i);
        getActivityAndFields();
        assertTrue(mNextButton.isEnabled());
    }

    // TODO Add tests for valid usernames in eas
    // They would be <name> or <name>\<domain> or <name>/<domain> or a valid email address

    /**
     * No user is not OK - not enabled
     */
    public void testBadUriNoUser() {
        Intent i = getTestIntent("eas://:password@server.com");
        setActivityIntent(i);
        getActivityAndFields();
        assertFalse(mNextButton.isEnabled());
    }

    /**
     * No password is not OK - not enabled
     */
    public void testBadUriNoPassword() {
        Intent i = getTestIntent("eas://user@server.com");
        setActivityIntent(i);
        getActivityAndFields();
        assertFalse(mNextButton.isEnabled());
    }

    /**
     * Test for non-standard but OK server names
     */
    @UiThreadTest
    public void testGoodServerVariants() {
        getActivityAndFields();
        assertTrue(mNextButton.isEnabled());

        mServerView.setText("  server.com  ");
        assertTrue(mNextButton.isEnabled());
    }

    /**
     * Test for non-empty but non-OK server names
     */
    @UiThreadTest
    public void testBadServerVariants() {
        getActivityAndFields();
        assertTrue(mNextButton.isEnabled());

        mServerView.setText("  ");
        assertFalse(mNextButton.isEnabled());

        mServerView.setText("serv$er.com");
        assertFalse(mNextButton.isEnabled());
    }

    /**
     * Test aspects of loadFields()
     *
     * TODO: More cases
     */
    @UiThreadTest
    public void testLoadFields() {
        // The default URI has no SSL and no "trust"
        getActivityAndFields();
        assertFalse(mSslRequiredCheckbox.isChecked());
        assertFalse(mTrustAllCertificatesCheckbox.isChecked());
        assertFalse(mTrustAllCertificatesCheckbox.getVisibility() == View.VISIBLE);

        // Setup host auth with variants of SSL enabled and check.  This also enables the
        // "trust certificates" checkbox (not checked, but visible now).
        Account account =
            ProviderTestUtils.setupAccount("account", false, mActivity.getBaseContext());
        account.mHostAuthRecv = ProviderTestUtils.setupHostAuth(
                "eas", "hostauth", 1, false, mActivity.getBaseContext());
        account.mHostAuthRecv.mFlags |= HostAuth.FLAG_SSL;
        account.mHostAuthRecv.mFlags &= ~HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
        mActivity.loadFields(account);
        assertTrue(mSslRequiredCheckbox.isChecked());
        assertFalse(mTrustAllCertificatesCheckbox.isChecked());
        assertTrue(mTrustAllCertificatesCheckbox.getVisibility() == View.VISIBLE);

        // Setup host auth with variants of SSL enabled and check.  This also enables the
        // "trust certificates" checkbox (not checked, but visible now).
        account.mHostAuthRecv.mFlags |= HostAuth.FLAG_TRUST_ALL_CERTIFICATES;
        mActivity.loadFields(account);
        assertTrue(mSslRequiredCheckbox.isChecked());
        assertTrue(mTrustAllCertificatesCheckbox.isChecked());
        assertTrue(mTrustAllCertificatesCheckbox.getVisibility() == View.VISIBLE);
    }

    /**
     * Test to confirm that passwords with leading or trailing spaces are accepted verbatim.
     */
    @UiThreadTest
    public void testPasswordNoTrim() throws URISyntaxException {
        getActivityAndFields();

        // Clear the password - should disable
        checkPassword(null, false);

        // Various combinations of spaces should be OK
        checkPassword(" leading", true);
        checkPassword("trailing ", true);
        checkPassword("em bedded", true);
        checkPassword(" ", true);
    }

    /**
     * Check password field for a given password.  Should be called in UI thread.  Confirms that
     * the password has not been trimmed.
     *
     * @param password the password to test with
     * @param expectNext true if expected that this password will enable the "next" button
     */
    private void checkPassword(String password, boolean expectNext) throws URISyntaxException {
        mPasswordView.setText(password);
        if (expectNext) {
            assertTrue(mNextButton.isEnabled());
            URI uri = mActivity.getUri();
            String actualUserInfo = uri.getUserInfo();
            String actualPassword = actualUserInfo.split(":", 2)[1];
            assertEquals(password, actualPassword);
        } else {
            assertFalse(mNextButton.isEnabled());
        }
    }

    /**
     * TODO: Directly test validateFields() checking boolean result
     */

    /**
     * Get the activity (which causes it to be started, using our intent) and get the UI fields
     */
    private void getActivityAndFields() {
        mActivity = getActivity();
        mServerView = (EditText) mActivity.findViewById(R.id.account_server);
        mPasswordView = (EditText) mActivity.findViewById(R.id.account_password);
        mNextButton = (Button) mActivity.findViewById(R.id.next);
        mSslRequiredCheckbox = (CheckBox) mActivity.findViewById(R.id.account_ssl);
        mTrustAllCertificatesCheckbox =
            (CheckBox) mActivity.findViewById(R.id.account_trust_certificates);
    }

    /**
     * Create an intent with the Account in it
     */
    private Intent getTestIntent(String storeUriString) {
        EmailContent.Account account = new EmailContent.Account();
        account.setStoreUri(getInstrumentation().getTargetContext(), storeUriString);
        Intent i = new Intent(Intent.ACTION_MAIN);
        i.putExtra(AccountSetupExchange.EXTRA_ACCOUNT, account);
        i.putExtra(AccountSetupExchange.EXTRA_DISABLE_AUTO_DISCOVER, true);
        return i;
    }
    //EXCHANGE-REMOVE-SECTION-END
}
