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

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.SyncResult;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.text.format.DateUtils;

import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.utility.Utility;
import com.android.exchange.CommandStatusException;
import com.android.exchange.Eas;
import com.android.exchange.EasResponse;
import com.android.exchange.adapter.Serializer;
import com.android.exchange.adapter.Tags;
import com.android.exchange.service.EasServerConnection;
import com.android.mail.utils.LogUtils;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;

import java.io.IOException;
import java.security.cert.CertificateException;
import java.util.ArrayList;

/**
 * Base class for all Exchange operations that use a POST to talk to the server.
 *
 * The core of this class is {@link #performOperation}, which provides the skeleton of making
 * a request, handling common errors, and setting fields on the {@link SyncResult} if there is one.
 * This class abstracts the connection handling from its subclasses and callers.
 *
 * {@link #performOperation} calls various abstract functions to create the request and parse the
 * response. For the most part subclasses can implement just these bits of functionality and rely
 * on {@link #performOperation} to do all the boilerplate etc.
 *
 * There are also a set of functions that a subclass may override if it's substantially
 * different from the "normal" operation (e.g. autodiscover deviates from the standard URI since
 * it's not account-specific so it needs to override {@link #getRequestUri()}), but the default
 * implementations of these functions should suffice for most operations.
 *
 * Some subclasses may need to override {@link #performOperation} to add validation and results
 * processing around a call to super.performOperation. Subclasses should avoid doing too much more
 * than wrapping some handling around the chained call; if you find that's happening, it's likely
 * a sign that the base class needs to be enhanced.
 *
 * One notable reason this wrapping happens is for operations that need to return a result directly
 * to their callers (as opposed to simply writing the results to the provider, as is common with
 * sync operations). This happens for example in
 * {@link com.android.emailcommon.service.IEmailService} message handlers. In such cases, due to
 * how {@link com.android.exchange.service.EasService} uses this class, the subclass needs to
 * store the result as a member variable and then provide an accessor to read the result. Since
 * different operations have different results (or none at all), there is no function in the base
 * class for this.
 *
 * Note that it is not practical to avoid the race between when an operation loads its account data
 * and when it uses it, as that would require some form of locking in the provider. There are three
 * interesting situations where this might happen, and that this class must handle:
 *
 * 1) Deleted from provider: Any subsequent provider access should return an error. Operations
 *    must detect this and terminate with an error.
 * 2) Account sync settings change: Generally only affects Ping. We interrupt the operation and
 *    load the new settings before proceeding.
 * 3) Sync suspended due to hold: A special case of the previous, and affects all operations, but
 *    fortunately doesn't need special handling here. Correct provider functionality must generate
 *    write failures, so the handling for #1 should cover this case as well.
 *
 * This class attempts to defer loading of account data as long as possible -- ideally we load
 * immediately before the network request -- but does not proactively check for changes after that.
 * This approach is a a practical balance between minimizing the race without adding too much
 * complexity beyond what's required.
 */
public abstract class EasOperation {
    public static final String LOG_TAG = Eas.LOG_TAG;

    /** The maximum number of server redirects we allow before returning failure. */
    private static final int MAX_REDIRECTS = 3;

    /** Message MIME type for EAS version 14 and later. */
    private static final String EAS_14_MIME_TYPE = "application/vnd.ms-sync.wbxml";

    /**
     * EasOperation error codes below.  All subclasses should try to create error codes
     * that do not overlap these codes or the codes of other subclasses. The error
     * code values for each subclass should start in a different 100 range (i.e. -100,
     * -200, etc...).
     */

    /** Error code indicating the operation was cancelled via {@link #abort}. */
    public static final int RESULT_ABORT = -1;
    /** Error code indicating the operation was cancelled via {@link #restart}. */
    public static final int RESULT_RESTART = -2;
    /** Error code indicating the Exchange servers redirected too many times. */
    public static final int RESULT_TOO_MANY_REDIRECTS = -3;
    /** Error code indicating the request failed due to a network problem. */
    public static final int RESULT_REQUEST_FAILURE = -4;
    /** Error code indicating a 403 (forbidden) error. */
    public static final int RESULT_FORBIDDEN = -5;
    /** Error code indicating an unresolved provisioning error. */
    public static final int RESULT_PROVISIONING_ERROR = -6;
    /** Error code indicating an authentication problem. */
    public static final int RESULT_AUTHENTICATION_ERROR = -7;
    /** Error code indicating the client is missing a certificate. */
    public static final int RESULT_CLIENT_CERTIFICATE_REQUIRED = -8;
    /** Error code indicating we don't have a protocol version in common with the server. */
    public static final int RESULT_PROTOCOL_VERSION_UNSUPPORTED = -9;
    /** Error code indicating the account could not be loaded from the provider. */
    public static final int RESULT_ACCOUNT_ID_INVALID = -10;
    /** Error code indicating a hard data layer error. */
    public static final int RESULT_HARD_DATA_FAILURE = -11;
    /** Error code indicating some other failure. */
    public static final int RESULT_OTHER_FAILURE = -12;

    protected final Context mContext;

    /** The provider id for the account this operation is on. */
    private final long mAccountId;

    /** The cached {@link Account} state; can be null if it hasn't been loaded yet. */
    protected Account mAccount;

    /** The connection to use for this operation. This is created when {@link #mAccount} is set. */
    private EasServerConnection mConnection;

    /**
     * Constructor which defers loading of account and connection info.
     * @param context
     * @param accountId
     */
    protected EasOperation(final Context context, final long accountId) {
        mContext = context;
        mAccountId = accountId;
    }

    // TODO: Make this private again when EasSyncHandler is converted to be a subclass.
    protected EasOperation(final Context context, final Account account,
            final EasServerConnection connection) {
        this(context, account.mId);
        mAccount = account;
        mConnection = connection;
    }

    protected EasOperation(final Context context, final Account account, final HostAuth hostAuth) {
        this(context, account, new EasServerConnection(context, account, hostAuth));
    }

    protected EasOperation(final Context context, final Account account) {
        this(context, account, account.getOrCreateHostAuthRecv(context));
    }

    /**
     * This constructor is for use by operations that are created by other operations, e.g.
     * {@link EasProvision}. It reuses the account and connection of its parent.
     * @param parentOperation The {@link EasOperation} that is creating us.
     */
    protected EasOperation(final EasOperation parentOperation) {
        mContext = parentOperation.mContext;
        mAccountId = parentOperation.mAccountId;
        mAccount = parentOperation.mAccount;
        mConnection = parentOperation.mConnection;
    }

    /**
     * Some operations happen before the account exists (e.g. account validation).
     * These operations cannot use {@link #loadAccount}, so instead we make a dummy account and
     * supply a temporary {@link HostAuth}.
     * @param hostAuth
     */
    protected final void setDummyAccount(final HostAuth hostAuth) {
        mAccount = new Account();
        mAccount.mEmailAddress = hostAuth.mLogin;
        mConnection = new EasServerConnection(mContext, mAccount, hostAuth);
    }

    /**
     * Loads (or reloads) the {@link Account} for this operation, and sets up our connection to the
     * server.
     * @param allowReload If false, do not perform a load if we already have an {@link Account}
     *                    (i.e. just keep the existing one); otherwise allow replacement of the
     *                    account. Note that this can result in a valid Account being replaced with
     *                    null if the account no longer exists.
     * @return Whether we now have a valid {@link Account} object.
     */
    public final boolean loadAccount(final boolean allowReload) {
        if (mAccount == null || allowReload) {
            mAccount = Account.restoreAccountWithId(mContext, getAccountId());
            if (mAccount != null) {
                mConnection = new EasServerConnection(mContext, mAccount,
                        mAccount.getOrCreateHostAuthRecv(mContext));
            }
        }
        return (mAccount != null);
    }

    public final long getAccountId() {
        return mAccountId;
    }

    /**
     * Request that this operation terminate. Intended for use by the sync service to interrupt
     * running operations, primarily Ping.
     */
    public final void abort() {
        mConnection.stop(EasServerConnection.STOPPED_REASON_ABORT);
    }

    /**
     * Request that this operation restart. Intended for use by the sync service to interrupt
     * running operations, primarily Ping.
     */
    public final void restart() {
        mConnection.stop(EasServerConnection.STOPPED_REASON_RESTART);
    }

    /**
     * The skeleton of performing an operation. This function handles all the common code and
     * error handling, calling into virtual functions that are implemented or overridden by the
     * subclass to do the operation-specific logic.
     *
     * The result codes work as follows:
     * - Negative values indicate common error codes and are defined above (the various RESULT_*
     *   constants).
     * - Non-negative values indicate the result of {@link #handleResponse}. These are obviously
     *   specific to the subclass, and may indicate success or error conditions.
     *
     * The common error codes primarily indicate conditions that occur when performing the POST
     * itself, such as network errors and handling of the HTTP response. However, some errors that
     * can be indicated in the HTTP response code can also be indicated in the payload of the
     * response as well, so {@link #handleResponse} should in those cases return the appropriate
     * negative result code, which will be handled the same as if it had been indicated in the HTTP
     * response code.
     *
     * @return A result code for the outcome of this operation, as described above.
     */
    public int performOperation() {
        // Make sure the account is loaded if it hasn't already been.
        if (!loadAccount(false)) {
            LogUtils.i(LOG_TAG, "Failed to load account %d before sending request for operation %s",
                    getAccountId(), getCommand());
            return RESULT_ACCOUNT_ID_INVALID;
        }

        // We handle server redirects by looping, but we need to protect against too much looping.
        int redirectCount = 0;

        do {
            // Perform the HTTP request and handle exceptions.
            final EasResponse response;
            try {
                response = mConnection.executeHttpUriRequest(makeRequest(), getTimeout());
            } catch (final IOException e) {
                // If we were stopped, return the appropriate result code.
                switch (mConnection.getStoppedReason()) {
                    case EasServerConnection.STOPPED_REASON_ABORT:
                        return RESULT_ABORT;
                    case EasServerConnection.STOPPED_REASON_RESTART:
                        return RESULT_RESTART;
                    default:
                        break;
                }
                // If we're here, then we had a IOException that's not from a stop request.
                String message = e.getMessage();
                if (message == null) {
                    message = "(no message)";
                }
                LogUtils.i(LOG_TAG, "IOException while sending request: %s", message);
                return RESULT_REQUEST_FAILURE;
            } catch (final CertificateException e) {
                LogUtils.i(LOG_TAG, "CertificateException while sending request: %s",
                        e.getMessage());
                return RESULT_CLIENT_CERTIFICATE_REQUIRED;
            } catch (final IllegalStateException e) {
                // Subclasses use ISE to signal a hard error when building the request.
                // TODO: Switch away from ISEs.
                LogUtils.e(LOG_TAG, e, "Exception while sending request");
                return RESULT_HARD_DATA_FAILURE;
            }

            // The POST completed, so process the response.
            try {
                final int result;
                // First off, the success case.
                if (response.isSuccess()) {
                    int responseResult;
                    try {
                        responseResult = handleResponse(response);
                    } catch (final IOException e) {
                        LogUtils.e(LOG_TAG, e, "Exception while handling response");
                        return RESULT_REQUEST_FAILURE;
                    } catch (final CommandStatusException e) {
                        // For some operations (notably Sync & FolderSync), errors are signaled in
                        // the payload of the response. These will have a HTTP 200 response, and the
                        // error condition is only detected during response parsing.
                        // The various parsers handle this by throwing a CommandStatusException.
                        // TODO: Consider having the parsers return the errors instead of throwing.
                        final int status = e.mStatus;
                        LogUtils.e(LOG_TAG, "CommandStatusException: %s, %d", getCommand(), status);
                        if (CommandStatusException.CommandStatus.isNeedsProvisioning(status)) {
                            responseResult = RESULT_PROVISIONING_ERROR;
                        } else if (CommandStatusException.CommandStatus.isDeniedAccess(status)) {
                            responseResult = RESULT_FORBIDDEN;
                        } else {
                            responseResult = RESULT_OTHER_FAILURE;
                        }
                    }
                    result = responseResult;
                } else {
                    result = RESULT_OTHER_FAILURE;
                }

                // Non-negative results indicate success. Return immediately and bypass the error
                // handling.
                if (result >= 0) {
                    return result;
                }

                // If this operation has distinct handling for 403 errors, do that.
                if (result == RESULT_FORBIDDEN || (response.isForbidden() && handleForbidden())) {
                    LogUtils.e(LOG_TAG, "Forbidden response");
                    return RESULT_FORBIDDEN;
                }

                // Handle provisioning errors.
                if (result == RESULT_PROVISIONING_ERROR || response.isProvisionError()) {
                    if (handleProvisionError()) {
                        // The provisioning error has been taken care of, so we should re-do this
                        // request.
                        LogUtils.d(LOG_TAG, "Provisioning error handled during %s, retrying",
                                getCommand());
                        continue;
                    }
                    return RESULT_PROVISIONING_ERROR;
                }

                // Handle authentication errors.
                if (response.isAuthError()) {
                    LogUtils.e(LOG_TAG, "Authentication error");
                    if (response.isMissingCertificate()) {
                        return RESULT_CLIENT_CERTIFICATE_REQUIRED;
                    }
                    return RESULT_AUTHENTICATION_ERROR;
                }

                // Handle redirects.
                if (response.isRedirectError()) {
                    ++redirectCount;
                    mConnection.redirectHostAuth(response.getRedirectAddress());
                    // Note that unlike other errors, we do NOT return here; we just keep looping.
                } else {
                    // All other errors.
                    LogUtils.e(LOG_TAG, "Generic error for operation %s: status %d, result %d",
                            getCommand(), response.getStatus(), result);
                    return RESULT_OTHER_FAILURE;
                }
            } finally {
                response.close();
            }
        } while (redirectCount < MAX_REDIRECTS);

        // Non-redirects return immediately after handling, so the only way to reach here is if we
        // looped too many times.
        LogUtils.e(LOG_TAG, "Too many redirects");
        return RESULT_TOO_MANY_REDIRECTS;
    }

    /**
     * Reset the protocol version to use for this connection. If it's changed, and our account is
     * persisted, also write back the changes to the DB.
     * @param protocolVersion The new protocol version to use, as a string.
     */
    protected final void setProtocolVersion(final String protocolVersion) {
        final long accountId = getAccountId();
        if (mConnection.setProtocolVersion(protocolVersion) && accountId != Account.NOT_SAVED) {
            final Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId);
            final ContentValues cv = new ContentValues(2);
            if (getProtocolVersion() >= 12.0) {
                final int oldFlags = Utility.getFirstRowInt(mContext, uri,
                        Account.ACCOUNT_FLAGS_PROJECTION, null, null, null,
                        Account.ACCOUNT_FLAGS_COLUMN_FLAGS, 0);
                final int newFlags = oldFlags
                        | Account.FLAGS_SUPPORTS_GLOBAL_SEARCH + Account.FLAGS_SUPPORTS_SEARCH;
                if (oldFlags != newFlags) {
                    cv.put(EmailContent.AccountColumns.FLAGS, newFlags);
                }
            }
            cv.put(EmailContent.AccountColumns.PROTOCOL_VERSION, protocolVersion);
            mContext.getContentResolver().update(uri, cv, null, null);
        }
    }

    /**
     * Create the request object for this operation.
     * Most operations use a POST, but some use other request types (e.g. Options).
     * @return An {@link HttpUriRequest}.
     * @throws IOException
     */
    private final HttpUriRequest makeRequest() throws IOException {
        final String requestUri = getRequestUri();
        if (requestUri == null) {
            return mConnection.makeOptions();
        }
        return mConnection.makePost(requestUri, getRequestEntity(),
                getRequestContentType(), addPolicyKeyHeaderToRequest());
    }

    /**
     * The following functions MUST be overridden by subclasses; these are things that are unique
     * to each operation.
     */

    /**
     * Get the name of the operation, used as the "Cmd=XXX" query param in the request URI. Note
     * that if you override {@link #getRequestUri}, then this function may be unused for normal
     * operation, but all subclasses should return something non-null for use with logging.
     * @return The name of the command for this operation as defined by the EAS protocol, or for
     *         commands that don't need it, a suitable descriptive name for logging.
     */
    protected abstract String getCommand();

    /**
     * Build the {@link HttpEntity} which is used to construct the POST. Typically this function
     * will build the Exchange request using a {@link Serializer} and then call {@link #makeEntity}.
     * If the subclass is not using a POST, then it should override this to return null.
     * @return The {@link HttpEntity} to pass to {@link EasServerConnection#makePost}.
     * @throws IOException
     */
    protected abstract HttpEntity getRequestEntity() throws IOException;

    /**
     * Parse the response from the Exchange perform whatever actions are dictated by that.
     * @param response The {@link EasResponse} to our request.
     * @return A result code. Non-negative values are returned directly to the caller; negative
     *         values
     *
     * that is returned to the caller of {@link #performOperation}.
     * @throws IOException
     */
    protected abstract int handleResponse(final EasResponse response)
            throws IOException, CommandStatusException;

    /**
     * The following functions may be overriden by a subclass, but most operations will not need
     * to do so.
     */

    /**
     * Get the URI for the Exchange server and this operation. Most (signed in) operations need
     * not override this; the notable operation that needs to override it is auto-discover.
     * @return
     */
    protected String getRequestUri() {
        return mConnection.makeUriString(getCommand());
    }

    /**
     * @return Whether to set the X-MS-PolicyKey header. Only Ping does not want this header.
     */
    protected boolean addPolicyKeyHeaderToRequest() {
        return true;
    }

    /**
     * @return The content type of this request.
     */
    protected String getRequestContentType() {
        return EAS_14_MIME_TYPE;
    }

    /**
     * @return The timeout to use for the POST.
     */
    protected long getTimeout() {
        return 30 * DateUtils.SECOND_IN_MILLIS;
    }

    /**
     * If 403 responses should be handled in a special way, this function should be overridden to
     * do that.
     * @return Whether we handle 403 responses; if false, then treat 403 as a provisioning error.
     */
    protected boolean handleForbidden() {
        return false;
    }

    /**
     * Handle a provisioning error. Subclasses may override this to do something different, e.g.
     * to validate rather than actually do the provisioning.
     * @return
     */
    protected boolean handleProvisionError() {
        final EasProvision provisionOperation = new EasProvision(this);
        return provisionOperation.provision();
    }

    /**
     * Convenience methods for subclasses to use.
     */

    /**
     * Convenience method to make an {@link HttpEntity} from {@link Serializer}.
     */
    protected final HttpEntity makeEntity(final Serializer s) {
        return new ByteArrayEntity(s.toByteArray());
    }

    /**
     * Check whether we should ask the server what protocol versions it supports and set this
     * account to use that version.
     * @return Whether we need a new protocol version from the server.
     */
    protected final boolean shouldGetProtocolVersion() {
        // TODO: Find conditions under which we should check other than not having one yet.
        return !mConnection.isProtocolVersionSet();
    }

    /**
     * @return The protocol version to use.
     */
    protected final double getProtocolVersion() {
        return mConnection.getProtocolVersion();
    }

    /**
     * @return Our useragent.
     */
    protected final String getUserAgent() {
        return mConnection.getUserAgent();
    }

    /**
     * @return Whether we succeeeded in registering the client cert.
     */
    protected final boolean registerClientCert() {
        return mConnection.registerClientCert();
    }

    /**
     * Add the device information to the current request.
     * @param s The {@link Serializer} for our current request.
     * @param context The {@link Context} for current device.
     * @param userAgent The user agent string that our connection use.
     */
    protected static void expandedAddDeviceInformationToSerializer(final Serializer s,
            final Context context, final String userAgent) throws IOException {
        final String deviceId;
        final String phoneNumber;
        final String operator;
        final TelephonyManager tm = (TelephonyManager)context.getSystemService(
                Context.TELEPHONY_SERVICE);
        if (tm != null) {
            deviceId = tm.getDeviceId();
            phoneNumber = tm.getLine1Number();
            // TODO: This is not perfect and needs to be improved, for at least two reasons:
            // 1) SIM cards can override this name.
            // 2) We don't resend this info to the server when we change networks.
            final String operatorName = tm.getNetworkOperatorName();
            final String operatorNumber = tm.getNetworkOperator();
            if (!TextUtils.isEmpty(operatorName) && !TextUtils.isEmpty(operatorNumber)) {
                operator = operatorName + " (" + operatorNumber + ")";
            } else if (!TextUtils.isEmpty(operatorName)) {
                operator = operatorName;
            } else {
                operator = operatorNumber;
            }
        } else {
            deviceId = null;
            phoneNumber = null;
            operator = null;
        }

        // TODO: Right now, we won't send this information unless the device is provisioned again.
        // Potentially, this means that our phone number could be out of date if the user
        // switches sims. Is there something we can do to force a reprovision?
        s.start(Tags.SETTINGS_DEVICE_INFORMATION).start(Tags.SETTINGS_SET);
        s.data(Tags.SETTINGS_MODEL, Build.MODEL);
        if (deviceId != null) {
            s.data(Tags.SETTINGS_IMEI, tm.getDeviceId());
        }
        // Set the device friendly name, if we have one.
        // TODO: Longer term, this should be done without a provider call.
        final Bundle deviceName = context.getContentResolver().call(
                EmailContent.CONTENT_URI, EmailContent.DEVICE_FRIENDLY_NAME, null, null);
        if (deviceName != null) {
            final String friendlyName = deviceName.getString(EmailContent.DEVICE_FRIENDLY_NAME);
            if (!TextUtils.isEmpty(friendlyName)) {
                s.data(Tags.SETTINGS_FRIENDLY_NAME, friendlyName);
            }
        }
        s.data(Tags.SETTINGS_OS, "Android " + Build.VERSION.RELEASE);
        if (phoneNumber != null) {
            s.data(Tags.SETTINGS_PHONE_NUMBER, phoneNumber);
        }
        // TODO: Consider setting this, but make sure we know what it's used for.
        // If the user changes the device's locale and we don't do a reprovision, the server's
        // idea of the language will be wrong. Since we're not sure what this is used for,
        // right now we're leaving it out.
        //s.data(Tags.SETTINGS_OS_LANGUAGE, Locale.getDefault().getDisplayLanguage());
        s.data(Tags.SETTINGS_USER_AGENT, userAgent);
        if (operator != null) {
            s.data(Tags.SETTINGS_MOBILE_OPERATOR, operator);
        }
        s.end().end();  // SETTINGS_SET, SETTINGS_DEVICE_INFORMATION
    }

    /**
     * Add the device information to the current request.
     * @param s The {@link Serializer} that contains the payload for this request.
     */
    protected final void addDeviceInformationToSerializer(final Serializer s)
            throws IOException {
        final String userAgent = getUserAgent();
        expandedAddDeviceInformationToSerializer(s, mContext, userAgent);
    }

    /**
     * Convenience method for adding a Message to an account's outbox
     * @param account The {@link Account} from which to send the message.
     * @param msg the message to send
     */
    protected final void sendMessage(final Account account, final EmailContent.Message msg) {
        long mailboxId = Mailbox.findMailboxOfType(mContext, account.mId, Mailbox.TYPE_OUTBOX);
        // TODO: Improve system mailbox handling.
        if (mailboxId == Mailbox.NO_MAILBOX) {
            LogUtils.d(LOG_TAG, "No outbox for account %d, creating it", account.mId);
            final Mailbox outbox =
                    Mailbox.newSystemMailbox(mContext, account.mId, Mailbox.TYPE_OUTBOX);
            outbox.save(mContext);
            mailboxId = outbox.mId;
        }
        msg.mMailboxKey = mailboxId;
        msg.mAccountKey = account.mId;
        msg.save(mContext);
        requestSyncForMailbox(new android.accounts.Account(account.mEmailAddress,
                Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), mailboxId);
    }

    /**
     * Issue a {@link android.content.ContentResolver#requestSync} for a specific mailbox.
     * @param amAccount The {@link android.accounts.Account} for the account we're pinging.
     * @param mailboxId The id of the mailbox that needs to sync.
     */
    protected static void requestSyncForMailbox(final android.accounts.Account amAccount,
            final long mailboxId) {
        final Bundle extras = Mailbox.createSyncBundle(mailboxId);
        ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras);
        LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailbox %s, %s",
                amAccount.toString(), extras.toString());
    }

    protected static void requestSyncForMailboxes(final android.accounts.Account amAccount,
            final ArrayList<Long> mailboxIds) {
        final Bundle extras = Mailbox.createSyncBundle(mailboxIds);
        ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras);
        LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailboxes  %s, %s",
                amAccount.toString(), extras.toString());
    }

    /**
     * RequestNoOpSync
     * This requests a sync for a particular authority purely so that that account
     * in settings will recognize that it is trying to sync, and will display the
     * appropriate UI. In fact, all exchange data syncing actually happens through the
     * EmailSyncAdapterService.
     * @param amAccount
     * @param authority
     */
    protected static void requestNoOpSync(final android.accounts.Account amAccount,
            final String authority) {
        final Bundle extras = new Bundle(1);
        extras.putBoolean(Mailbox.SYNC_EXTRA_NOOP, true);
        ContentResolver.requestSync(amAccount, authority, extras);
        LogUtils.d(LOG_TAG, "requestSync EasOperation requestNoOpSync %s, %s",
                amAccount.toString(), extras.toString());
    }

    public static void writeResultToSyncResult(final int result, final SyncResult syncResult) {
        switch (result) {
            case RESULT_TOO_MANY_REDIRECTS:
                syncResult.tooManyRetries = true;
                break;
            case RESULT_REQUEST_FAILURE:
                syncResult.stats.numIoExceptions = 1;
                break;
            case RESULT_FORBIDDEN:
            case RESULT_PROVISIONING_ERROR:
            case RESULT_AUTHENTICATION_ERROR:
            case RESULT_CLIENT_CERTIFICATE_REQUIRED:
                syncResult.stats.numAuthExceptions = 1;
                break;
            case RESULT_PROTOCOL_VERSION_UNSUPPORTED:
                // Only used in validate, so there's never a syncResult to write to here.
                break;
            case RESULT_ACCOUNT_ID_INVALID:
            case RESULT_HARD_DATA_FAILURE:
                syncResult.databaseError = true;
                break;
            case RESULT_OTHER_FAILURE:
                // TODO: Is this correct?
                syncResult.stats.numIoExceptions = 1;
                break;
        }
    }
}
