/*
 * Copyright (C) 2010 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.exchange;

import com.android.emailcommon.AccountManagerTypes;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.EmailContent;
import com.android.exchange.utility.ExchangeTestCase;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.Calendar;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.MediumTest;
import android.text.TextUtils;
import android.util.Log;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@MediumTest
public class CalendarSyncEnablerTest extends ExchangeTestCase {

    protected static final String TEST_ACCOUNT_PREFIX = "__test";
    protected static final String TEST_ACCOUNT_SUFFIX = "@android.com";

    private HashMap<Account, Boolean> origCalendarSyncStates = new HashMap<Account, Boolean>();

    // To make the rest of the code shorter thus more readable...
    private static final String EAT = AccountManagerTypes.TYPE_EXCHANGE;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        // Delete any test accounts we might have created earlier
        deleteTemporaryAccountManagerAccounts();

        // Save the original calendar sync states.
        for (Account account : AccountManager.get(getContext()).getAccounts()) {
            origCalendarSyncStates.put(account,
                    ContentResolver.getSyncAutomatically(account, Calendar.AUTHORITY));
        }
    }

    @Override
    public void tearDown() throws Exception {
        super.tearDown();
        // Delete any test accounts we might have created earlier
        deleteTemporaryAccountManagerAccounts();

        // Restore the original calendar sync states.
        // Note we restore only for Exchange accounts.
        // Other accounts should remain intact throughout the tests.  Plus we don't know if the
        // Calendar.AUTHORITY is supported by other types of accounts.
        for (Account account : getExchangeAccounts()) {
            Boolean state = origCalendarSyncStates.get(account);
            if (state == null) continue; // Shouldn't happen, but just in case.

            ContentResolver.setSyncAutomatically(account, Calendar.AUTHORITY, state);
        }
    }

    public void testEnableEasCalendarSync() {
        final Account[] baseAccounts = getExchangeAccounts();

        String a1 = getTestAccountEmailAddress("1");
        String a2 = getTestAccountEmailAddress("2");

        // 1. Test with 1 account

        CalendarSyncEnabler enabler = new CalendarSyncEnabler(getContext());

        // Add exchange accounts
        createAccountManagerAccount(a1);

        String emailAddresses = enabler.enableEasCalendarSyncInternalForTest();

        // Verify
        verifyCalendarSyncState();

        // There seems to be no good way to examine the contents of Notification, so let's verify
        // we at least (tried to) show the correct email addresses.
        checkNotificationEmailAddresses(emailAddresses, baseAccounts, a1);

        // Delete added account.
        deleteTemporaryAccountManagerAccounts();

        // 2. Test with 2 accounts
        enabler = new CalendarSyncEnabler(getContext());

        // Add exchange accounts
        createAccountManagerAccount(a1);
        createAccountManagerAccount(a2);

        emailAddresses = enabler.enableEasCalendarSyncInternalForTest();

        // Verify
        verifyCalendarSyncState();

        // Check
        checkNotificationEmailAddresses(emailAddresses, baseAccounts, a1, a2);
    }

    private static void checkNotificationEmailAddresses(String actual, Account[] baseAccounts,
            String... addedAddresses) {
        // Build and sort actual string array.
        final String[] actualArray = TextUtils.split(actual, " ");
        Arrays.sort(actualArray);

        // Build and sort expected string array.
        ArrayList<String> expected = new ArrayList<String>();
        for (Account account : baseAccounts) {
            expected.add(account.name);
        }
        for (String address : addedAddresses) {
            expected.add(address);
        }
        final String[] expectedArray = new String[expected.size()];
        expected.toArray(expectedArray);
        Arrays.sort(expectedArray);

        // Check!
        MoreAsserts.assertEquals(expectedArray, actualArray);
    }

    /**
     * For all {@link Account}, confirm that:
     * <ol>
     *   <li>Calendar sync is enabled if it's an Exchange account.<br>
     *       Unfortunately setSyncAutomatically() doesn't take effect immediately, so we skip this
     *       check for now.
             TODO Find a stable way to check this.
     *   <li>Otherwise, calendar sync state isn't changed.
     * </ol>
     */
    private void verifyCalendarSyncState() {
        // It's very unfortunate that setSyncAutomatically doesn't take effect immediately.
        for (Account account : AccountManager.get(getContext()).getAccounts()) {
            String message = "account=" + account.name + "(" + account.type + ")";
            boolean enabled = ContentResolver.getSyncAutomatically(account, Calendar.AUTHORITY);
            int syncable = ContentResolver.getIsSyncable(account, Calendar.AUTHORITY);

            if (EAT.equals(account.type)) {
                // Should be enabled.
                // assertEquals(message, Boolean.TRUE, (Boolean) enabled);
                // assertEquals(message, 1, syncable);
            } else {
                // Shouldn't change.
                assertEquals(message, origCalendarSyncStates.get(account), (Boolean) enabled);
            }
        }
    }

    public void testEnableEasCalendarSyncWithNoExchangeAccounts() {
        // This test can only meaningfully run when there's no exchange accounts
        // set up on the device.  Otherwise there'll be no difference from
        // testEnableEasCalendarSync.
        if (AccountManager.get(getContext()).getAccountsByType(EAT).length > 0) {
            Log.w(Logging.LOG_TAG, "testEnableEasCalendarSyncWithNoExchangeAccounts skipped:"
                    + " It only runs when there's no Exchange account on the device.");
            return;
        }
        CalendarSyncEnabler enabler = new CalendarSyncEnabler(getContext());
        String emailAddresses = enabler.enableEasCalendarSyncInternalForTest();

        // Verify (nothing should change)
        verifyCalendarSyncState();

        // No exchange accounts found.
        assertEquals(0, emailAddresses.length());
    }

    public void testShowNotification() {
        CalendarSyncEnabler enabler = new CalendarSyncEnabler(getContext());

        // We can't really check the result, but at least we can make sure it won't crash....
        enabler.showNotificationForTest("a@b.com");

        // Remove the notification.  Comment it out when you want to know how it looks like.
        // TODO If NotificationController supports this notification, we can just mock it out
        // and remove this code.
        ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE))
                .cancel(CalendarSyncEnabler.NOTIFICATION_ID_EXCHANGE_CALENDAR_ADDED);
    }

    protected Account[] getExchangeAccounts() {
        return AccountManager.get(getContext()).getAccountsByType(
                AccountManagerTypes.TYPE_EXCHANGE);
    }

    protected Account makeAccountManagerAccount(String username) {
        return new Account(username, AccountManagerTypes.TYPE_EXCHANGE);
    }

    protected void createAccountManagerAccount(String username) {
        final Account account = makeAccountManagerAccount(username);
        AccountManager.get(getContext()).addAccountExplicitly(account, "password", null);
    }

    protected EmailContent.Account setupProviderAndAccountManagerAccount(String username) {
        // Note that setupAccount creates the email address username@android.com, so that's what
        // we need to use for the account manager
        createAccountManagerAccount(username + TEST_ACCOUNT_SUFFIX);
        return setupTestAccount(username, true);
    }

    protected ArrayList<EmailContent.Account> makeExchangeServiceAccountList() {
        ArrayList<EmailContent.Account> accountList = new ArrayList<EmailContent.Account>();
        Cursor c = mProviderContext.getContentResolver().query(EmailContent.Account.CONTENT_URI,
                EmailContent.Account.CONTENT_PROJECTION, null, null, null);
        try {
            while (c.moveToNext()) {
                EmailContent.Account account = new EmailContent.Account();
                account.restore(c);
                accountList.add(account);
            }
        } finally {
            c.close();
        }
        return accountList;
    }

    protected void deleteAccountManagerAccount(Account account) {
        AccountManagerFuture<Boolean> future =
            AccountManager.get(getContext()).removeAccount(account, null, null);
        try {
            future.getResult();
        } catch (OperationCanceledException e) {
        } catch (AuthenticatorException e) {
        } catch (IOException e) {
        }
    }

    protected void deleteTemporaryAccountManagerAccounts() {
        for (Account accountManagerAccount: getExchangeAccounts()) {
            if (accountManagerAccount.name.startsWith(TEST_ACCOUNT_PREFIX) &&
                    accountManagerAccount.name.endsWith(TEST_ACCOUNT_SUFFIX)) {
                deleteAccountManagerAccount(accountManagerAccount);
            }
        }
    }

    protected String getTestAccountName(String name) {
        return TEST_ACCOUNT_PREFIX + name;
    }

    protected String getTestAccountEmailAddress(String name) {
        return TEST_ACCOUNT_PREFIX + name + TEST_ACCOUNT_SUFFIX;
    }


    /**
     * Helper to retrieve account manager accounts *and* remove any preexisting accounts
     * from the list, to "hide" them from the reconciler.
     */
    protected Account[] getAccountManagerAccounts(Account[] baseline) {
        Account[] rawList = getExchangeAccounts();
        if (baseline.length == 0) {
            return rawList;
        }
        HashSet<Account> set = new HashSet<Account>();
        for (Account addAccount : rawList) {
            set.add(addAccount);
        }
        for (Account removeAccount : baseline) {
            set.remove(removeAccount);
        }
        return set.toArray(new Account[0]);
    }
}
