private Dictionary <AnnHistoryItemState, Dictionary <string, string> > ProcessAnnotationsHistory(LEADDocument document)
        {
            // Get the history (which is updated each time SetAnnotations/SaveToCache is called).
            AnnHistory history = document.Annotations.GetHistory();

            if (history == null)
            {
                return(null);
            }

            // Condense the history to get all the changes since the last time the history was cleared in one list.
            history.Condense();
            if (history.Items.Count == 0)
            {
                return(null);
            }

            string documentId = document.DocumentId;

            bool logging = _loggingLEADToIBM;

            if (logging)
            {
                Trace.WriteLine(string.Format("Logging: LEADTOOLS annotations to IBM annotations for document '{0}'", documentId));
                Trace.WriteLine("  Condensed history of changes since last save/set:");
                var items = (List <AnnHistoryItem>)history.Items;
                foreach (AnnHistoryItem item in items)
                {
                    // You also have access to the user information here.
                    Trace.WriteLine(string.Format("    {0} {1} {2}", item.Guid, item.State, item.Timestamp));
                }
            }

            // Get all annotation containers (and the objects within them).
            AnnContainer[] containers = document.Annotations.GetAnnotations(false);

            // Process all the added objects. LEAD tracks both "Added" and "AddedAndModified" (cases
            // where annotations were added and then modified from the default). Here, we combine them
            // for a simple "ADDED" list.
            Dictionary <string, string> addedIBMObjects = new Dictionary <string, string>();

            // Get the guids for the added objects from our history object.
            string[] guids = history.GetGuidForState(AnnHistoryItemState.Added);
            ProcessObjects(addedIBMObjects, documentId, guids, AnnHistoryItemState.Added, containers);
            guids = history.GetGuidForState(AnnHistoryItemState.AddedAndModified);
            ProcessObjects(addedIBMObjects, documentId, guids, AnnHistoryItemState.Added, containers);

            // Process all modified objects
            Dictionary <string, string> modifiedIBMObjects = new Dictionary <string, string>();

            string[] modifiedGuids = history.GetGuidForState(AnnHistoryItemState.Modified);
            ProcessObjects(modifiedIBMObjects, documentId, modifiedGuids, AnnHistoryItemState.Modified, containers);

            // Process all deleted objects (note, we only get the guids for them; no IBM objects will be here)
            Dictionary <string, string> deletedIBMObjects = new Dictionary <string, string>();

            guids = history.GetGuidForState(AnnHistoryItemState.Deleted);
            ProcessObjects(deletedIBMObjects, documentId, guids, AnnHistoryItemState.Deleted, containers);

            // Clear the history since we updated everything.
            history.Clear();
            // Set the history again (so it will be saved in the cache for this document).
            document.Annotations.SetHistory(history);

            // List of converted IBM objects that has been modified
            Dictionary <AnnHistoryItemState, Dictionary <string, string> > ibmObjects = new Dictionary <AnnHistoryItemState, Dictionary <string, string> >();

            ibmObjects.Add(AnnHistoryItemState.Added, addedIBMObjects);
            ibmObjects.Add(AnnHistoryItemState.Modified, modifiedIBMObjects);
            ibmObjects.Add(AnnHistoryItemState.Deleted, deletedIBMObjects);

            return(ibmObjects);
        }
        public SetAnnotationsIBMResponse SetAnnotationsIBM(SetAnnotationsIBMRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // Must have the documentId you'd like to add annotations to.
            // If you only have the document cache URI, DocumentFactory.LoadFromUri needs to be called.
            if (string.IsNullOrEmpty(request.DocumentId))
            {
                throw new ArgumentNullException("documentId");
            }

            // Check that we have annotations.
            if (request.Annotations == null)
            {
                throw new ArgumentNullException("annotations");
            }

            var cache = ServiceHelper.Cache;

            using (var document = DocumentFactory.LoadFromCache(cache, request.DocumentId))
            {
                // Ensure we have the document.
                DocumentHelper.CheckLoadFromCache(document);

                // If the document is read-only then we won't be able to modify its settings. Temporarily change this state.
                bool wasReadOnly = document.IsReadOnly;
                document.IsReadOnly = false;

                // Get the IBM annotations from the request.
                IBMAnnotation[] ibmAnnotationObjects = request.Annotations;

                // Start converting. We need a rendering engine instance to help with measuring font sizes.
                AnnRenderingEngine renderingEngine = ServiceHelper.GetAnnRenderingEngine();

                // We have different options for reading the annotation...
                IBMP8ReadOptions readOptions = new IBMP8ReadOptions();
                readOptions.RenderingEngine = renderingEngine;

                int pagesCount = document.Pages.Count;
                // We have all the IBM objects converted to LEAD; now, add them to their respective page containers.
                Dictionary <int, AnnContainer> modifiedContainers = new Dictionary <int, AnnContainer>();

                for (int i = 0; i < ibmAnnotationObjects.Length; i++)
                {
                    // Our IBM annotation, as an XML string.
                    IBMAnnotation ibmObj = ibmAnnotationObjects[i];
                    if (ibmObj == null || string.IsNullOrEmpty(ibmObj.Annotation))
                    {
                        continue;
                    }

                    try
                    {
                        // Before converting, get the target page number.
                        string ibmPageNumberValue = AnnCodecs.ReadIBMP8PropDescAttr(ibmObj.Annotation, AnnCodecs.IBM_PAGENUMBER);
                        int    pageNumber         = 1;
                        if (!string.IsNullOrEmpty(ibmPageNumberValue))
                        {
                            int.TryParse(ibmPageNumberValue, out pageNumber);
                        }

                        // Make sure the page exists.
                        // If zero, set to page 1; if outside of the document range, disregard it.
                        if (pageNumber == 0)
                        {
                            pageNumber = 1;
                        }
                        else if (pageNumber > pagesCount)
                        {
                            continue;
                        }

                        // Get its container (one per page) and add the object to it.
                        DocumentPage documentPage = document.Pages[pageNumber - 1];

                        AnnContainer container = null;
                        if (modifiedContainers.ContainsKey(pageNumber))
                        {
                            container = modifiedContainers[pageNumber];
                        }
                        else
                        {
                            container = documentPage.GetAnnotations(true);
                            modifiedContainers.Add(pageNumber, container);
                        }

                        readOptions.Mapper = container.Mapper;

                        // Convert to a LEADTOOLS AnnObject.
                        // See "#REF IBM_Annotations_Support" for support info
                        AnnObject leadObj = AnnCodecs.ConvertFromIBMP8(ibmObj.Annotation, readOptions);
                        if (leadObj == null)
                        {
                            Trace.WriteLine("Conversion from IBM Annotation not supported for item at index " + i);
                            continue;
                        }

                        // Add the supplied properties
                        if (!string.IsNullOrEmpty(ibmObj.Password))
                        {
                            leadObj.Lock(ibmObj.Password);
                        }
                        if (!string.IsNullOrEmpty(ibmObj.UserId))
                        {
                            leadObj.UserId = ibmObj.UserId;
                            Dictionary <string, string> metadata = leadObj.Metadata;
                            string key = AnnObject.AuthorMetadataKey;
                            if (metadata.ContainsKey(key))
                            {
                                if (string.IsNullOrEmpty(metadata[key]))
                                {
                                    metadata[key] = ibmObj.UserId;
                                }
                            }
                            else
                            {
                                metadata.Add(key, ibmObj.UserId);
                            }
                        }
                        container.Children.Add(leadObj);
                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine(string.Format("Failed to convert IBM Annotation at index {0}: {1}", i, e.Message));
                    }
                }

                // Set the modified containers in the document.
                AnnContainer[] containers = modifiedContainers.Values.ToArray();
                document.Annotations.SetAnnotations(containers);

                // Reset the read-only value from above before saving into the cache.
                document.IsReadOnly = wasReadOnly;
                // Enable history tracking from this point forward so that calls to retrieve the IBM Annotations will have a history from this set operation.
                document.History.AutoUpdate = true;

                // Clear any old history.
                AnnHistory history = document.Annotations.GetHistory();
                if (history != null)
                {
                    history.Clear();
                    document.Annotations.SetHistory(history);
                }
                document.SaveToCache();

                return(new SetAnnotationsIBMResponse());
            }
        }