/*
 * Copyright (C) 2008-2009 Marc Blank
 * Licensed to 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.adapter;

import android.content.ContentProviderOperation;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
import com.android.emailcommon.provider.Mailbox;
import com.android.emailcommon.service.SyncWindow;
import com.android.emailcommon.utility.AttachmentUtilities;
import com.android.emailcommon.utility.Utility;
import com.android.exchange.CommandStatusException;
import com.android.exchange.CommandStatusException.CommandStatus;
import com.android.exchange.Eas;
import com.android.exchange.ExchangeService;
import com.android.exchange.provider.MailboxUtilities;
import com.google.common.annotations.VisibleForTesting;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * Parse the result of a FolderSync command
 *
 * Handles the addition, deletion, and changes to folders in the user's Exchange account.
 **/

public class FolderSyncParser extends AbstractSyncParser {

    public static final String TAG = "FolderSyncParser";

    // These are defined by the EAS protocol
    public static final int USER_GENERIC_TYPE = 1;
    public static final int INBOX_TYPE = 2;
    public static final int DRAFTS_TYPE = 3;
    public static final int DELETED_TYPE = 4;
    public static final int SENT_TYPE = 5;
    public static final int OUTBOX_TYPE = 6;
    public static final int TASKS_TYPE = 7;
    public static final int CALENDAR_TYPE = 8;
    public static final int CONTACTS_TYPE = 9;
    public static final int NOTES_TYPE = 10;
    public static final int JOURNAL_TYPE = 11;
    public static final int USER_MAILBOX_TYPE = 12;

    // Chunk size for our mailbox commits
    public final static int MAILBOX_COMMIT_SIZE = 20;

    // EAS types that we are willing to consider valid folders for EAS sync
    public static final List<Integer> VALID_EAS_FOLDER_TYPES = Arrays.asList(INBOX_TYPE,
            DRAFTS_TYPE, DELETED_TYPE, SENT_TYPE, OUTBOX_TYPE, USER_MAILBOX_TYPE, CALENDAR_TYPE,
            CONTACTS_TYPE, USER_GENERIC_TYPE);

    public static final String ALL_BUT_ACCOUNT_MAILBOX = MailboxColumns.ACCOUNT_KEY + "=? and " +
        MailboxColumns.TYPE + "!=" + Mailbox.TYPE_EAS_ACCOUNT_MAILBOX;

    private static final String WHERE_SERVER_ID_AND_ACCOUNT = MailboxColumns.SERVER_ID + "=? and " +
        MailboxColumns.ACCOUNT_KEY + "=?";

    private static final String WHERE_DISPLAY_NAME_AND_ACCOUNT = MailboxColumns.DISPLAY_NAME +
        "=? and " + MailboxColumns.ACCOUNT_KEY + "=?";

    private static final String WHERE_PARENT_SERVER_ID_AND_ACCOUNT =
        MailboxColumns.PARENT_SERVER_ID +"=? and " + MailboxColumns.ACCOUNT_KEY + "=?";

    private static final String[] MAILBOX_ID_COLUMNS_PROJECTION =
        new String[] {MailboxColumns.ID, MailboxColumns.SERVER_ID, MailboxColumns.PARENT_SERVER_ID};
    private static final int MAILBOX_ID_COLUMNS_ID = 0;
    private static final int MAILBOX_ID_COLUMNS_SERVER_ID = 1;
    private static final int MAILBOX_ID_COLUMNS_PARENT_SERVER_ID = 2;

    @VisibleForTesting
    long mAccountId;
    @VisibleForTesting
    String mAccountIdAsString;
    @VisibleForTesting
    boolean mInUnitTest = false;

    private String[] mBindArguments = new String[2];
    private ArrayList<ContentProviderOperation> mOperations =
        new ArrayList<ContentProviderOperation>();
    private boolean mInitialSync;
    private ArrayList<String> mParentFixupsNeeded = new ArrayList<String>();
    private boolean mFixupUninitializedNeeded = false;
    // If true, we only care about status (this is true when validating an account) and ignore
    // other data
    private final boolean mStatusOnly;

    private static final ContentValues UNINITIALIZED_PARENT_KEY = new ContentValues();

    {
        UNINITIALIZED_PARENT_KEY.put(MailboxColumns.PARENT_KEY, Mailbox.PARENT_KEY_UNINITIALIZED);
    }

    public FolderSyncParser(InputStream in, AbstractSyncAdapter adapter) throws IOException {
        this(in, adapter, false);
    }

    public FolderSyncParser(InputStream in, AbstractSyncAdapter adapter, boolean statusOnly)
            throws IOException {
        super(in, adapter);
        mAccountId = mAccount.mId;
        mAccountIdAsString = Long.toString(mAccountId);
        mStatusOnly = statusOnly;
    }

    @Override
    public boolean parse() throws IOException, CommandStatusException {
        int status;
        boolean res = false;
        boolean resetFolders = false;
        // Since we're now (potentially) committing mailboxes in chunks, ensure that we start with
        // only the account mailbox
        String key = mAccount.mSyncKey;
        mInitialSync = (key == null) || "0".equals(key);
        if (mInitialSync) {
            mContentResolver.delete(Mailbox.CONTENT_URI, ALL_BUT_ACCOUNT_MAILBOX,
                    new String[] {Long.toString(mAccountId)});
        }
        if (nextTag(START_DOCUMENT) != Tags.FOLDER_FOLDER_SYNC)
            throw new EasParserException();
        while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
            if (tag == Tags.FOLDER_STATUS) {
                status = getValueInt();
                // Do a sanity check on the account here; if we have any duplicated folders, we'll
                // act as though we have a bad folder sync key (wipe/reload mailboxes)
                // Note: The ContentValues isn't used, but no point creating a new one
                int dupes = 0;
                if (mAccountId > 0) {
                    dupes = mContentResolver.update(
                            ContentUris.withAppendedId(EmailContent.ACCOUNT_CHECK_URI, mAccountId),
                            UNINITIALIZED_PARENT_KEY, null, null);
                }
                if (dupes > 0) {
                    String e = "Duplicate mailboxes found for account " + mAccountId + ": " + dupes;
                    // For verbose logging, make sure this is in emaillog.txt
                    userLog(e);
                    // Worthy of logging, regardless
                    Log.w(Logging.LOG_TAG, e);
                    status = Eas.FOLDER_STATUS_INVALID_KEY;
                }
                if (status != Eas.FOLDER_STATUS_OK) {
                    mService.errorLog("FolderSync failed: " + CommandStatus.toString(status));
                    // If the account hasn't been saved, this is a validation attempt, so we don't
                    // try reloading the folder list...
                    if (CommandStatus.isDeniedAccess(status) ||
                            CommandStatus.isNeedsProvisioning(status) ||
                            (mAccount.mId == Account.NOT_SAVED)) {
                        throw new CommandStatusException(status);
                    // Note that we need to catch both old-style (Eas.FOLDER_STATUS_INVALID_KEY)
                    // and EAS 14 style command status
                    } else if (status == Eas.FOLDER_STATUS_INVALID_KEY ||
                            CommandStatus.isBadSyncKey(status)) {
                        mService.errorLog("Bad sync key; RESET and delete all folders");
                        // Delete PIM data
                        ExchangeService.deleteAccountPIMData(mAccountId);
                        // Save away any mailbox sync information that is NOT default
                        saveMailboxSyncOptions();
                        // And only then, delete mailboxes
                        mContentResolver.delete(Mailbox.CONTENT_URI,
                                MailboxColumns.ACCOUNT_KEY + "=?",
                                new String[] {Long.toString(mAccountId)});
                        // Stop existing syncs and reconstruct _main
                        ExchangeService.stopNonAccountMailboxSyncsForAccount(mAccountId);
                        res = true;
                        resetFolders = true;
                        // Reset the sync key and save (this should trigger the AccountObserver
                        // in ExchangeService, which will recreate the account mailbox, which
                        // will then start syncing folders, etc.)
                        mAccount.mSyncKey = "0";
                        ContentValues cv = new ContentValues();
                        cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
                        mContentResolver.update(ContentUris.withAppendedId(Account.CONTENT_URI,
                                mAccount.mId), cv, null, null);
                    } else {
                        // Other errors are at the server, so let's throw an error that will
                        // cause this sync to be retried at a later time
                        mService.errorLog("Throwing IOException; will retry later");
                        throw new EasParserException("Folder status error");
                    }
                }
            } else if (tag == Tags.FOLDER_SYNC_KEY) {
                String newKey = getValue();
                if (!resetFolders) {
                    mAccount.mSyncKey = newKey;
                    userLog("New syncKey: ", newKey);
                } else {
                    userLog("Ignoring new syncKey: ", newKey);
                }
            } else if (tag == Tags.FOLDER_CHANGES) {
                if (mStatusOnly) return res;
                changesParser(mOperations, mInitialSync);
            } else
                skipTag();
        }
        if (mStatusOnly) return res;
        synchronized (mService.getSynchronizer()) {
            if (!mService.isStopped() || resetFolders) {
                commit();
                userLog("Leaving FolderSyncParser with Account syncKey=", mAccount.mSyncKey);
            }
        }
        return res;
    }

    private Cursor getServerIdCursor(String serverId) {
        mBindArguments[0] = serverId;
        mBindArguments[1] = mAccountIdAsString;
        return mContentResolver.query(Mailbox.CONTENT_URI, MAILBOX_ID_COLUMNS_PROJECTION,
                WHERE_SERVER_ID_AND_ACCOUNT, mBindArguments, null);
    }

    public void deleteParser(ArrayList<ContentProviderOperation> ops) throws IOException {
        while (nextTag(Tags.FOLDER_DELETE) != END) {
            switch (tag) {
                case Tags.FOLDER_SERVER_ID:
                    String serverId = getValue();
                    // Find the mailbox in this account with the given serverId
                    Cursor c = getServerIdCursor(serverId);
                    try {
                        if (c.moveToFirst()) {
                            userLog("Deleting ", serverId);
                            ops.add(ContentProviderOperation.newDelete(
                                    ContentUris.withAppendedId(Mailbox.CONTENT_URI,
                                            c.getLong(MAILBOX_ID_COLUMNS_ID))).build());
                            AttachmentUtilities.deleteAllMailboxAttachmentFiles(mContext,
                                    mAccountId, mMailbox.mId);
                            if (!mInitialSync) {
                                String parentId = c.getString(MAILBOX_ID_COLUMNS_PARENT_SERVER_ID);
                                if (!TextUtils.isEmpty(parentId)) {
                                    mParentFixupsNeeded.add(parentId);
                                }
                            }
                        }
                    } finally {
                        c.close();
                    }
                    break;
                default:
                    skipTag();
            }
        }
    }

    private static class SyncOptions {
        private final int mInterval;
        private final int mLookback;

        private SyncOptions(int interval, int lookback) {
            mInterval = interval;
            mLookback = lookback;
        }
    }

    private static final String MAILBOX_STATE_SELECTION =
        MailboxColumns.ACCOUNT_KEY + "=? AND (" + MailboxColumns.SYNC_INTERVAL + "!=" +
            Account.CHECK_INTERVAL_NEVER + " OR " + Mailbox.SYNC_LOOKBACK + "!=" +
            SyncWindow.SYNC_WINDOW_UNKNOWN + ")";

    private static final String[] MAILBOX_STATE_PROJECTION = new String[] {
        MailboxColumns.SERVER_ID, MailboxColumns.SYNC_INTERVAL, MailboxColumns.SYNC_LOOKBACK};
    private static final int MAILBOX_STATE_SERVER_ID = 0;
    private static final int MAILBOX_STATE_INTERVAL = 1;
    private static final int MAILBOX_STATE_LOOKBACK = 2;
    @VisibleForTesting
    final HashMap<String, SyncOptions> mSyncOptionsMap = new HashMap<String, SyncOptions>();

    /**
     * For every mailbox in this account that has a non-default interval or lookback, save those
     * values.
     */
    @VisibleForTesting
    void saveMailboxSyncOptions() {
        // Shouldn't be necessary, but...
        mSyncOptionsMap.clear();
        Cursor c = mContentResolver.query(Mailbox.CONTENT_URI, MAILBOX_STATE_PROJECTION,
                MAILBOX_STATE_SELECTION, new String[] {mAccountIdAsString}, null);
        if (c != null) {
            try {
                while (c.moveToNext()) {
                    mSyncOptionsMap.put(c.getString(MAILBOX_STATE_SERVER_ID),
                            new SyncOptions(c.getInt(MAILBOX_STATE_INTERVAL),
                                    c.getInt(MAILBOX_STATE_LOOKBACK)));
                }
            } finally {
                c.close();
            }
        }
    }

    /**
     * For every set of saved mailbox sync options, try to find and restore those values
     */
    @VisibleForTesting
    void restoreMailboxSyncOptions() {
        try {
            ContentValues cv = new ContentValues();
            mBindArguments[1] = mAccountIdAsString;
            for (String serverId: mSyncOptionsMap.keySet()) {
                SyncOptions options = mSyncOptionsMap.get(serverId);
                cv.put(MailboxColumns.SYNC_INTERVAL, options.mInterval);
                cv.put(MailboxColumns.SYNC_LOOKBACK, options.mLookback);
                mBindArguments[0] = serverId;
                // If we match account and server id, set the sync options
                mContentResolver.update(Mailbox.CONTENT_URI, cv, WHERE_SERVER_ID_AND_ACCOUNT,
                        mBindArguments);
            }
        } finally {
            mSyncOptionsMap.clear();
        }
    }

    public Mailbox addParser() throws IOException {
        String name = null;
        String serverId = null;
        String parentId = null;
        int type = 0;

        while (nextTag(Tags.FOLDER_ADD) != END) {
            switch (tag) {
                case Tags.FOLDER_DISPLAY_NAME: {
                    name = getValue();
                    break;
                }
                case Tags.FOLDER_TYPE: {
                    type = getValueInt();
                    break;
                }
                case Tags.FOLDER_PARENT_ID: {
                    parentId = getValue();
                    break;
                }
                case Tags.FOLDER_SERVER_ID: {
                    serverId = getValue();
                    break;
                }
                default:
                    skipTag();
            }
        }

        if (VALID_EAS_FOLDER_TYPES.contains(type)) {
            Mailbox mailbox = new Mailbox();
            mailbox.mDisplayName = name;
            mailbox.mServerId = serverId;
            mailbox.mAccountKey = mAccountId;
            mailbox.mType = Mailbox.TYPE_MAIL;
            // Note that all mailboxes default to checking "never" (i.e. manual sync only)
            // We set specific intervals for inbox, contacts, and (eventually) calendar
            mailbox.mSyncInterval = Mailbox.CHECK_INTERVAL_NEVER;
            switch (type) {
                case INBOX_TYPE:
                    mailbox.mType = Mailbox.TYPE_INBOX;
                    mailbox.mSyncInterval = mAccount.mSyncInterval;
                    break;
                case CONTACTS_TYPE:
                    mailbox.mType = Mailbox.TYPE_CONTACTS;
                    mailbox.mSyncInterval = mAccount.mSyncInterval;
                    break;
                case OUTBOX_TYPE:
                    // TYPE_OUTBOX mailboxes are known by ExchangeService to sync whenever they
                    // aren't empty.  The value of mSyncFrequency is ignored for this kind of
                    // mailbox.
                    mailbox.mType = Mailbox.TYPE_OUTBOX;
                    break;
                case SENT_TYPE:
                    mailbox.mType = Mailbox.TYPE_SENT;
                    break;
                case DRAFTS_TYPE:
                    mailbox.mType = Mailbox.TYPE_DRAFTS;
                    break;
                case DELETED_TYPE:
                    mailbox.mType = Mailbox.TYPE_TRASH;
                    break;
                case CALENDAR_TYPE:
                    mailbox.mType = Mailbox.TYPE_CALENDAR;
                    mailbox.mSyncInterval = mAccount.mSyncInterval;
                    break;
                case USER_GENERIC_TYPE:
                    mailbox.mType = Mailbox.TYPE_UNKNOWN;
                    break;
            }

            // Make boxes like Contacts and Calendar invisible in the folder list
            mailbox.mFlagVisible = (mailbox.mType < Mailbox.TYPE_NOT_EMAIL);

            if (!parentId.equals("0")) {
                mailbox.mParentServerId = parentId;
                if (!mInitialSync) {
                    mParentFixupsNeeded.add(parentId);
                }
            }
            // At the least, we'll need to set flags
            mFixupUninitializedNeeded = true;

            return mailbox;
        }
        return null;
    }

    /**
     * Determine whether a given mailbox holds mail, rather than other data.  We do this by first
     * checking the type of the mailbox (if it's a known good type, great; if it's a known bad
     * type, return false).  If it's unknown, we check the parent, first by trying to find it in
     * the current set of newly synced items, and then by looking it up in EmailProvider.  If
     * we can find the parent, we use the same rules to determine if it holds mail; if it does,
     * then its children do as well, so that's a go.
     *
     * @param mailbox the mailbox we're checking
     * @param mailboxMap a HashMap relating server id's of mailboxes in the current sync set to
     * the corresponding mailbox structures
     * @return whether or not the mailbox contains email (rather than PIM or unknown data)
     */
    /*package*/ boolean isValidMailFolder(Mailbox mailbox, HashMap<String, Mailbox> mailboxMap) {
        int folderType = mailbox.mType;
        // Automatically accept our email types
        if (folderType < Mailbox.TYPE_NOT_EMAIL) return true;
        // Automatically reject everything else but "unknown"
        if (folderType != Mailbox.TYPE_UNKNOWN) return false;
        // If this is TYPE_UNKNOWN, check the parent
        Mailbox parent = mailboxMap.get(mailbox.mParentServerId);
        // If the parent is in the map, then check it out; if not, it could be an existing saved
        // Mailbox, so we'll have to query the database
        if (parent == null) {
            mBindArguments[0] = Long.toString(mAccount.mId);
            long parentId = -1;
            if (mailbox.mParentServerId != null) {
                mBindArguments[1] = mailbox.mParentServerId;
                parentId = Utility.getFirstRowInt(mContext, Mailbox.CONTENT_URI,
                        EmailContent.ID_PROJECTION,
                        MailboxColumns.ACCOUNT_KEY + "=? AND " + MailboxColumns.SERVER_ID + "=?",
                        mBindArguments, null, EmailContent.ID_PROJECTION_COLUMN, -1);
            }
            if (parentId != -1) {
                // Get the parent from the database
                parent = Mailbox.restoreMailboxWithId(mContext, parentId);
                if (parent == null) return false;
            } else {
                return false;
            }
        }
        return isValidMailFolder(parent, mailboxMap);
    }

    public void updateParser(ArrayList<ContentProviderOperation> ops) throws IOException {
        String serverId = null;
        String displayName = null;
        String parentId = null;
        while (nextTag(Tags.FOLDER_UPDATE) != END) {
            switch (tag) {
                case Tags.FOLDER_SERVER_ID:
                    serverId = getValue();
                    break;
                case Tags.FOLDER_DISPLAY_NAME:
                    displayName = getValue();
                    break;
                case Tags.FOLDER_PARENT_ID:
                    parentId = getValue();
                    break;
                default:
                    skipTag();
                    break;
            }
        }
        // We'll make a change if one of parentId or displayName are specified
        // serverId is required, but let's be careful just the same
        if (serverId != null && (displayName != null || parentId != null)) {
            Cursor c = getServerIdCursor(serverId);
            try {
                // If we find the mailbox (using serverId), make the change
                if (c.moveToFirst()) {
                    userLog("Updating ", serverId);
                    // Fix up old and new parents, as needed
                    if (!TextUtils.isEmpty(parentId)) {
                        mParentFixupsNeeded.add(parentId);
                    }
                    String oldParentId = c.getString(MAILBOX_ID_COLUMNS_PARENT_SERVER_ID);
                    if (!TextUtils.isEmpty(oldParentId)) {
                        mParentFixupsNeeded.add(oldParentId);
                    }
                    // Set display name if we've got one
                    ContentValues cv = new ContentValues();
                    if (displayName != null) {
                        cv.put(Mailbox.DISPLAY_NAME, displayName);
                    }
                    // Save away the server id and uninitialize the parent key
                    cv.put(Mailbox.PARENT_SERVER_ID, parentId);
                    // Clear the parent key; it will be fixed up after the commit
                    cv.put(Mailbox.PARENT_KEY, Mailbox.PARENT_KEY_UNINITIALIZED);
                    ops.add(ContentProviderOperation.newUpdate(
                            ContentUris.withAppendedId(Mailbox.CONTENT_URI,
                                    c.getLong(MAILBOX_ID_COLUMNS_ID))).withValues(cv).build());
                    // Say we need to fixup uninitialized mailboxes
                    mFixupUninitializedNeeded = true;
                }
            } finally {
                c.close();
            }
        }
    }

    private boolean commitMailboxes(ArrayList<Mailbox> validMailboxes,
            ArrayList<Mailbox> userMailboxes, HashMap<String, Mailbox> mailboxMap,
            ArrayList<ContentProviderOperation> ops) {

        // Go through the generic user mailboxes; we'll call them valid if any parent is valid
        for (Mailbox m: userMailboxes) {
            if (isValidMailFolder(m, mailboxMap)) {
                m.mType = Mailbox.TYPE_MAIL;
                validMailboxes.add(m);
            } else {
                userLog("Rejecting unknown type mailbox: " + m.mDisplayName);
            }
        }

        // Add operations for all valid mailboxes
        for (Mailbox m: validMailboxes) {
            userLog("Adding mailbox: ", m.mDisplayName);
            ops.add(ContentProviderOperation
                    .newInsert(Mailbox.CONTENT_URI).withValues(m.toContentValues()).build());
        }

        // Commit the mailboxes
        userLog("Applying ", mOperations.size(), " mailbox operations.");
        // Execute the batch; throw IOExceptions if this fails, hoping the issue isn't repeatable
        // If it IS repeatable, there's no good result, since the folder list will be invalid
        try {
            mContentResolver.applyBatch(EmailContent.AUTHORITY, mOperations);
            return true;
        } catch (RemoteException e) {
            userLog("RemoteException in commitMailboxes");
            return false;
        } catch (OperationApplicationException e) {
            userLog("OperationApplicationException in commitMailboxes");
            return false;
        }
    }

    public void changesParser(final ArrayList<ContentProviderOperation> ops,
            final boolean initialSync) throws IOException {

        // Array of added mailboxes
        final ArrayList<Mailbox> addMailboxes = new ArrayList<Mailbox>();

        // Indicate start of (potential) mailbox changes
        MailboxUtilities.startMailboxChanges(mContext, mAccount.mId);

        while (nextTag(Tags.FOLDER_CHANGES) != END) {
            if (tag == Tags.FOLDER_ADD) {
                Mailbox mailbox = addParser();
                if (mailbox != null) {
                    addMailboxes.add(mailbox);
                }
            } else if (tag == Tags.FOLDER_DELETE) {
                deleteParser(ops);
            } else if (tag == Tags.FOLDER_UPDATE) {
                updateParser(ops);
            } else if (tag == Tags.FOLDER_COUNT) {
                getValueInt();
            } else
                skipTag();
        }

        // Synchronize on the parser to prevent this being run concurrently
        // (an extremely unlikely event, but nonetheless possible)
        synchronized (FolderSyncParser.this) {
            // Mailboxes that we known contain email
            ArrayList<Mailbox> validMailboxes = new ArrayList<Mailbox>();
            // Mailboxes that we're unsure about
            ArrayList<Mailbox> userMailboxes = new ArrayList<Mailbox>();

            // Maps folder serverId to mailbox (used to validate user mailboxes)
            HashMap<String, Mailbox> mailboxMap = new HashMap<String, Mailbox>();
            for (Mailbox mailbox : addMailboxes) {
                mailboxMap.put(mailbox.mServerId, mailbox);
            }

            int mailboxCommitCount = 0;
            for (Mailbox mailbox : addMailboxes) {
                // And add the mailbox to the proper list
                if (mailbox.mType == Mailbox.TYPE_UNKNOWN) {
                    userMailboxes.add(mailbox);
                } else {
                    validMailboxes.add(mailbox);
                }
                // On initial sync, we commit what we have every 20 mailboxes
                if (initialSync && (++mailboxCommitCount == MAILBOX_COMMIT_SIZE)) {
                    if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap,
                            ops)) {
                        mService.stop();
                        return;
                    }
                    // Clear our arrays to prepare for more
                    userMailboxes.clear();
                    validMailboxes.clear();
                    ops.clear();
                    mailboxCommitCount = 0;
                }
            }
            // Commit the sync key and mailboxes
            ContentValues cv = new ContentValues();
            cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
            ops.add(ContentProviderOperation
                    .newUpdate(
                            ContentUris.withAppendedId(Account.CONTENT_URI,
                                    mAccount.mId))
                            .withValues(cv).build());
            if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops)) {
                mService.stop();
                return;
            }
            String accountSelector = Mailbox.ACCOUNT_KEY + "=" + mAccount.mId;
            // For new boxes, setup the parent key and flags
            if (mFixupUninitializedNeeded) {
                MailboxUtilities.fixupUninitializedParentKeys(mContext,
                        accountSelector);
            }
            // For modified parents, reset the flags (and children's parent key)
            for (String parentServerId: mParentFixupsNeeded) {
                Cursor c = mContentResolver.query(Mailbox.CONTENT_URI,
                        Mailbox.CONTENT_PROJECTION, Mailbox.PARENT_SERVER_ID + "=?",
                        new String[] {parentServerId}, null);
                try {
                    if (c.moveToFirst()) {
                        MailboxUtilities.setFlagsAndChildrensParentKey(mContext, c,
                                accountSelector);
                    }
                } finally {
                    c.close();
                }
            }

            MailboxUtilities.setupHierarchicalNames(mContext, mAccount.mId);

            // Signal completion of mailbox changes
            MailboxUtilities.endMailboxChanges(mContext, mAccount.mId);
        }
    }

    /**
     * Not needed for FolderSync parsing; everything is done within changesParser
     */
    @Override
    public void commandsParser() throws IOException {
    }

    /**
     * Clean up after sync
     */
    @Override
    public void commit() throws IOException {
        // Look for sync issues and its children and delete them
        // I'm not aware of any other way to deal with this properly
        mBindArguments[0] = "Sync Issues";
        mBindArguments[1] = mAccountIdAsString;
        Cursor c = mContentResolver.query(Mailbox.CONTENT_URI,
                MAILBOX_ID_COLUMNS_PROJECTION, WHERE_DISPLAY_NAME_AND_ACCOUNT,
                mBindArguments, null);
        String parentServerId = null;
        long id = 0;
        try {
            if (c.moveToFirst()) {
                id = c.getLong(MAILBOX_ID_COLUMNS_ID);
                parentServerId = c.getString(MAILBOX_ID_COLUMNS_SERVER_ID);
            }
        } finally {
            c.close();
        }
        if (parentServerId != null) {
            mContentResolver.delete(ContentUris.withAppendedId(Mailbox.CONTENT_URI, id),
                    null, null);
            mBindArguments[0] = parentServerId;
            mContentResolver.delete(Mailbox.CONTENT_URI, WHERE_PARENT_SERVER_ID_AND_ACCOUNT,
                    mBindArguments);
        }

        // If we have saved options, restore them now
        if (mInitialSync) {
            restoreMailboxSyncOptions();
        }
    }

    @Override
    public void responsesParser() throws IOException {
    }

}
