/*
 * 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.email.AccountTestCase;
import com.android.email.Email;
import com.android.email.NotificationController;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Calendar;
import android.test.MoreAsserts;
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;

public class CalendarSyncEnablerTest extends AccountTestCase {

    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 = Email.EXCHANGE_ACCOUNT_MANAGER_TYPE;

    public CalendarSyncEnablerTest() {
        super();
    }

    @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.enableEasCalendarSyncInternal();

        // 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.enableEasCalendarSyncInternal();

        // 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(Email.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.enableEasCalendarSyncInternal();

        // 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.showNotification("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(NotificationController.NOTIFICATION_ID_EXCHANGE_CALENDAR_ADDED);
    }
}
