public void Enqueue(object key, ProjectId projectId, DocumentId documentId, IEnumerable <ITaskItem> items)
        {
            lock (_gate)
            {
                var newItems      = CreateVisualStudioTaskItems(items);
                var existingItems = GetExistingVisualStudioTaskItems(key);

                var hasNewItems      = newItems != null;
                var hasExistingItems = existingItems != null || HasPendingVisualStudioTaskItems(key, projectId, documentId);

                // track items from opened files
                if (documentId != null && _workspace.IsDocumentOpen(documentId))
                {
                    _openedFiles.Add(documentId);
                }

                // nothing to do
                if (!hasNewItems && !hasExistingItems)
                {
                    return;
                }

                // handle 3 operations.
                // 1. delete
                if (!hasNewItems && hasExistingItems)
                {
                    RemoveExistingTaskItems_NoLock(key, projectId, documentId, existingItems);
                    ReportPendingTaskItems_NoLock();
                    return;
                }

                // 2. insert
                if (hasNewItems && !hasExistingItems)
                {
                    EnqueuePendingTaskItems_NoLock(key, projectId, documentId, newItems);
                    ReportPendingTaskItems_NoLock();
                    return;
                }

                // 3. update
                Contract.Requires(hasNewItems && hasExistingItems);
                EnqueueUpdate_NoLock(key, projectId, documentId, newItems, existingItems);
            }
        }