internal static void BuildReport(Library library, List <PDFDocument> pdf_documents)
        {
            FeatureTrackingManager.Instance.UseFeature(Features.Library_JSONAnnotationReport);

            AnnotationReportOptions annotation_report_options = new AnnotationReportOptions();

            List <AnnotationWorkGenerator.AnnotationWork> annotation_works = AnnotationWorkGenerator.GenerateAnnotationWorks(library, pdf_documents, annotation_report_options);

            IEnumerable <AnnotationJSON> annotation_jsons = annotation_works.Select(annotation_work =>
                                                                                    new AnnotationJSON
            {
                fingerprint = annotation_work.pdf_document.Fingerprint,
                title       = annotation_work.pdf_document.TitleCombined,
                page        = annotation_work.pdf_annotation.Page,
                left        = annotation_work.pdf_annotation.Left,
                top         = annotation_work.pdf_annotation.Top,
                width       = annotation_work.pdf_annotation.Width,
                height      = annotation_work.pdf_annotation.Height,
                tags        = annotation_work.pdf_annotation.Tags,
                text        = annotation_work.pdf_annotation.Text,
            }
                                                                                    );

            string json     = JsonConvert.SerializeObject(annotation_jsons, Formatting.Indented);
            string filename = Path.GetTempFileName() + ".json.txt";

            File.WriteAllText(filename, json);
            Process.Start(filename);
        }
        private AnnotationReportOptions GetAnnotationReportOptions()
        {
            // TODO: Replace this awful mess with BINDINGS
            AnnotationReportOptions annotation_report_options = new AnnotationReportOptions();

            annotation_report_options.filter_tags      = GetDesiredFilterTags();
            annotation_report_options.IncludeComments  = this.ObjIncludeComments.IsChecked ?? false;
            annotation_report_options.IncludeAbstract  = this.ObjIncludeAbstract.IsChecked ?? false;
            annotation_report_options.IncludeAllPapers = this.ObjIncludeAllPapers.IsChecked ?? false;

            annotation_report_options.ObeySuppressedImages = !(this.ObjIMAGEShow.IsChecked ?? false);
            annotation_report_options.ObeySuppressedText   = !(this.ObjTEXTShow.IsChecked ?? false);
            annotation_report_options.SuppressAllImages    = this.ObjIMAGEHide.IsChecked ?? false;
            annotation_report_options.SuppressAllText      = this.ObjTEXTHide.IsChecked ?? false;

            annotation_report_options.FilterByCreationDate      = this.ObjFilterByCreationDate.IsChecked ?? false;
            annotation_report_options.FilterByCreationDate_From = this.ObjFilterByCreationDate_From.SelectedDate ?? DateTime.MinValue;
            annotation_report_options.FilterByCreationDate_To   = this.ObjFilterByCreationDate_To.SelectedDate ?? DateTime.MaxValue;
            annotation_report_options.FilterByFollowUpDate      = this.ObjFilterByFollowUpDate.IsChecked ?? false;
            annotation_report_options.FilterByFollowUpDate_From = this.ObjFilterByFollowUpDate_From.SelectedDate ?? DateTime.MinValue;
            annotation_report_options.FilterByFollowUpDate_To   = this.ObjFilterByFollowUpDate_To.SelectedDate ?? DateTime.MaxValue;

            annotation_report_options.FilterByCreator      = this.ObjFilterByCreator.IsChecked ?? false;
            annotation_report_options.FilterByCreator_Name = this.ObjFilterByCreatorCombo.Text;

            return(annotation_report_options);
        }
        public static List <AnnotationWork> GenerateAnnotationWorks(Library library, List <PDFDocument> pdf_documents, AnnotationReportOptions annotation_report_options)
        {
            List <AnnotationWork> annotation_works = new List <AnnotationWork>();

            // The caches we will need...
            Dictionary <string, byte[]> library_items_highlights_cache = library.LibraryDB.GetLibraryItemsAsCache(PDFDocumentFileLocations.HIGHLIGHTS);
            Dictionary <string, byte[]> library_items_inks_cache       = library.LibraryDB.GetLibraryItemsAsCache(PDFDocumentFileLocations.INKS);

            for (int j = 0; j < pdf_documents.Count; ++j)
            {
                if (j % 10 == 0)
                {
                    StatusManager.Instance.UpdateStatus("AnnotationReport", "Initialising annotation report", j, pdf_documents.Count);
                }

                PDFDocument pdf_document = pdf_documents[j];

                // Add the comments token if this document has some comments or abstract (and the user wants them)
                if (annotation_report_options.IncludeAllPapers)
                {
                    if (!String.IsNullOrEmpty(pdf_document.Comments) || !String.IsNullOrEmpty(pdf_document.Abstract))
                    {
                        annotation_works.Add(new AnnotationWork {
                            library = library, pdf_document = pdf_document, pdf_annotation = null
                        });
                    }
                }

                List <PDFAnnotation> pdf_annotations = new List <PDFAnnotation>();
                pdf_annotations.AddRange(pdf_document.GetAnnotations());
                if (library_items_highlights_cache.ContainsKey(pdf_document.Fingerprint))
                {
                    pdf_annotations.AddRange(HighlightToAnnotationGenerator.GenerateAnnotations(pdf_document, library_items_highlights_cache));
                }
                if (library_items_inks_cache.ContainsKey(pdf_document.Fingerprint))
                {
                    pdf_annotations.AddRange(InkToAnnotationGenerator.GenerateAnnotations(pdf_document, library_items_inks_cache));
                }

                pdf_annotations.Sort(AnnotationSorter);

                foreach (PDFAnnotation pdf_annotation in pdf_annotations)
                {
                    if (pdf_annotation.Deleted)
                    {
                        continue;
                    }

                    // Filter by annotations
                    if (null != annotation_report_options.filter_tags && annotation_report_options.filter_tags.Count > 0)
                    {
                        HashSet <string> annotation_tags = TagTools.ConvertTagBundleToTags(pdf_annotation.Tags);
                        annotation_tags.IntersectWith(annotation_report_options.filter_tags);
                        if (0 == annotation_tags.Count)
                        {
                            continue;
                        }
                    }

                    // Filter by date ranges and creators
                    {
                        if (annotation_report_options.FilterByCreationDate && pdf_annotation.DateCreated.HasValue)
                        {
                            DateTime date_to = annotation_report_options.FilterByCreationDate_To;
                            if (date_to != DateTime.MaxValue)
                            {
                                date_to = date_to.AddDays(1);
                            }

                            if (pdf_annotation.DateCreated.Value < annotation_report_options.FilterByCreationDate_From)
                            {
                                continue;
                            }
                            if (pdf_annotation.DateCreated.Value >= date_to)
                            {
                                continue;
                            }
                        }

                        if (annotation_report_options.FilterByFollowUpDate)
                        {
                            DateTime date_to = annotation_report_options.FilterByFollowUpDate_To;
                            if (date_to != DateTime.MaxValue)
                            {
                                date_to = date_to.AddDays(1);
                            }

                            if (!pdf_annotation.FollowUpDate.HasValue)
                            {
                                continue;
                            }
                            if (pdf_annotation.FollowUpDate.Value < annotation_report_options.FilterByFollowUpDate_From)
                            {
                                continue;
                            }
                            if (pdf_annotation.FollowUpDate.Value >= date_to)
                            {
                                continue;
                            }
                        }

                        if (annotation_report_options.FilterByCreator)
                        {
                            if (pdf_annotation.Creator != annotation_report_options.FilterByCreator_Name)
                            {
                                continue;
                            }
                        }
                    }

                    annotation_works.Add(new AnnotationWork {
                        library = library, pdf_document = pdf_document, pdf_annotation = pdf_annotation
                    });
                }
            }

            return(annotation_works);
        }
        internal static AnnotationReport BuildReport(Library library, List <PDFDocument> pdf_documents, AnnotationReportOptions annotation_report_options)
        {
            AnnotationReport     annotation_report = new AnnotationReport();
            StandardFlowDocument flow_document     = annotation_report.flow_document;

            // Create a list of all the work we need to do
            List <AnnotationWorkGenerator.AnnotationWork> annotation_works = AnnotationWorkGenerator.GenerateAnnotationWorks(library, pdf_documents, annotation_report_options);

            // Now build the report
            PDFDocument last_pdf_document = null;

            for (int j = 0; j < annotation_works.Count; ++j)
            {
                StatusManager.Instance.UpdateStatus("AnnotationReport", "Building annotation report", j, annotation_works.Count);
                AnnotationWorkGenerator.AnnotationWork annotation_work = annotation_works[j];
                PDFDocument   pdf_document   = annotation_work.pdf_document;
                PDFAnnotation pdf_annotation = annotation_work.pdf_annotation;

                // If this is a new PDFDocument, print out the header
                if (last_pdf_document != pdf_document)
                {
                    last_pdf_document = pdf_document;
                    Logging.Info("Processing {0}", pdf_document.Fingerprint);

                    if (!annotation_report_options.SuppressPDFDocumentHeader)
                    {
                        Span bold_title = new Span();
                        bold_title.FontSize   = 30;
                        bold_title.FontFamily = ThemeTextStyles.FontFamily_Header;
                        bold_title.Inlines.Add(new LineBreak());

                        if (!String.IsNullOrEmpty(pdf_document.TitleCombined))
                        {
                            bold_title.Inlines.Add(pdf_document.TitleCombined);
                            bold_title.Inlines.Add(new LineBreak());
                        }
                        Span bold = new Span();
                        bold.FontSize = 16;
                        if (!String.IsNullOrEmpty(pdf_document.YearCombined))
                        {
                            bold.Inlines.Add(pdf_document.YearCombined);
                            bold.Inlines.Add(" · ");
                        }
                        if (!String.IsNullOrEmpty(pdf_document.AuthorsCombined))
                        {
                            bold.Inlines.Add(pdf_document.AuthorsCombined);
                        }
                        if (!String.IsNullOrEmpty(pdf_document.Publication))
                        {
                            Italic italic = new Italic();
                            italic.Inlines.Add(pdf_document.Publication);
                            bold.Inlines.Add(new LineBreak());
                            bold.Inlines.Add(italic);
                        }
                        if (!String.IsNullOrEmpty(pdf_document.Tags))
                        {
                            bold.Inlines.Add(new LineBreak());

                            Run run = new Run();
                            run.Text = "[" + pdf_document.Tags + "]";
                            bold.Inlines.Add(run);
                        }
                        bold.Inlines.Add(new LineBreak());

                        {
                            bold.Inlines.Add(new LineBreak());

                            Span click_options = new Span();
                            {
                                {
                                    Run run = new Run(" Open ");
                                    run.Background = ThemeColours.Background_Brush_Blue_VeryVeryDark;
                                    run.Foreground = Brushes.White;
                                    run.Cursor     = Cursors.Hand;
                                    run.Tag        = pdf_document;
                                    run.MouseDown += run_Open_MouseDown;
                                    click_options.Inlines.Add(run);
                                }
                                click_options.Inlines.Add(new Run(" "));
                                {
                                    Run run = new Run(" Cite (Author, Date) ");
                                    run.Background = ThemeColours.Background_Brush_Blue_VeryVeryDark;
                                    run.Foreground = Brushes.White;
                                    run.Cursor     = Cursors.Hand;
                                    run.Tag        = pdf_document;
                                    run.MouseDown += run_Cite_MouseDown_Together;
                                    click_options.Inlines.Add(run);
                                }
                                click_options.Inlines.Add(new Run(" "));
                                {
                                    Run run = new Run(" [Cite Author (Date)] ");
                                    run.Background = ThemeColours.Background_Brush_Blue_VeryVeryDark;
                                    run.Foreground = Brushes.White;
                                    run.Cursor     = Cursors.Hand;
                                    run.Tag        = pdf_document;
                                    run.MouseDown += run_Cite_MouseDown_Separate;
                                    click_options.Inlines.Add(run);
                                }
                                click_options.Inlines.Add(new LineBreak());

                                bold.Inlines.Add(click_options);
                                annotation_report.AddClickOption(click_options);
                            }
                        }

                        Paragraph paragraph_header = new Paragraph();
                        paragraph_header.Inlines.Add(bold_title);
                        paragraph_header.Inlines.Add(bold);

                        Section section_header = new Section();
                        section_header.Background = ThemeColours.Background_Brush_Blue_VeryVeryDarkToWhite;
                        if (Colors.Transparent != pdf_document.Color)
                        {
                            section_header.Background = new SolidColorBrush(pdf_document.Color);
                        }
                        section_header.Blocks.Add(paragraph_header);

                        flow_document.Blocks.Add(new Paragraph(new LineBreak()));
                        flow_document.Blocks.Add(section_header);
                        //flow_document.Blocks.Add(new Paragraph(new LineBreak()));

                        bool have_document_details = false;

                        // Add the paper comment if we need to
                        if (annotation_report_options.IncludeComments)
                        {
                            string comment_text = pdf_document.Comments;
                            if (!String.IsNullOrEmpty(comment_text))
                            {
                                have_document_details = true;

                                flow_document.Blocks.Add(new Paragraph(new Run("●")));
                                {
                                    Paragraph paragraph = new Paragraph();
                                    {
                                        Bold header = new Bold();
                                        header.Inlines.Add("Comments: ");
                                        paragraph.Inlines.Add(header);
                                    }
                                    {
                                        Italic italic = new Italic();
                                        italic.Inlines.Add(comment_text);
                                        paragraph.Inlines.Add(italic);
                                    }
                                    flow_document.Blocks.Add(paragraph);
                                }
                            }
                        }
                        if (annotation_report_options.IncludeAbstract)
                        {
                            string abstract_text = pdf_document.Abstract;
                            if (PDFAbstractExtraction.CANT_LOCATE != abstract_text)
                            {
                                have_document_details = true;

                                flow_document.Blocks.Add(new Paragraph(new Run("●")));
                                {
                                    Paragraph paragraph = new Paragraph();
                                    {
                                        Bold header = new Bold();
                                        header.Inlines.Add("Abstract: ");
                                        paragraph.Inlines.Add(header);
                                    }
                                    {
                                        Italic italic = new Italic();
                                        italic.Inlines.Add(abstract_text);
                                        paragraph.Inlines.Add(italic);
                                    }
                                    flow_document.Blocks.Add(paragraph);
                                }
                            }
                        }

                        if (have_document_details)
                        {
                            flow_document.Blocks.Add(new Paragraph(new Run("●")));
                        }
                    }
                }

                // Print out the annotation
                if (null != pdf_annotation)
                {
                    // First the header
                    {
                        //flow_document.Blocks.Add(new Paragraph(new Run(" ● ")));

                        Paragraph paragraph = new Paragraph();
                        paragraph.Inlines.Add(new LineBreak());

                        {
                            Bold coloured_blob = new Bold();
                            coloured_blob.Foreground = new SolidColorBrush(pdf_annotation.Color);
                            coloured_blob.Inlines.Add(" ■ ");
                            paragraph.Inlines.Add(coloured_blob);
                        }

                        {
                            Span italic = new Span();
                            italic.FontSize = 16;
                            string annotation_header = String.Format("Page {0}", pdf_annotation.Page);
                            italic.Inlines.Add(annotation_header);
                            //Underline underline = new Underline(italic);
                            paragraph.Inlines.Add(italic);
                        }

                        {
                            Bold coloured_blob = new Bold();
                            coloured_blob.Foreground = new SolidColorBrush(pdf_annotation.Color);
                            coloured_blob.Inlines.Add(" ■ ");
                            paragraph.Inlines.Add(coloured_blob);
                        }

                        paragraph.Inlines.Add(new LineBreak());

                        // List the tags for this annotation
                        if (!annotation_report_options.SuppressPDFAnnotationTags)
                        {
                            if (!String.IsNullOrEmpty(pdf_annotation.Tags))
                            {
                                paragraph.Inlines.Add(" [" + pdf_annotation.Tags.Replace(";", "; ") + "] ");

                                paragraph.Inlines.Add(new LineBreak());
                            }
                        }

                        bool is_not_synthetic_annotation = (null == pdf_annotation.Tags || (!pdf_annotation.Tags.Contains(HighlightToAnnotationGenerator.HIGHLIGHTS_TAG) && !pdf_annotation.Tags.Contains(InkToAnnotationGenerator.INKS_TAG)));

                        {
                            paragraph.Inlines.Add(new LineBreak());

                            Span click_options = new Span();
                            {
                                Run run = new Run(" Open ");
                                run.Background = ThemeColours.Background_Brush_Blue_VeryDark;
                                run.Foreground = Brushes.White;
                                run.Cursor     = Cursors.Hand;
                                run.Tag        = annotation_work;
                                run.MouseDown += run_AnnotationOpen_MouseDown;
                                click_options.Inlines.Add(run);
                            }

                            if (is_not_synthetic_annotation)
                            {
                                click_options.Inlines.Add(new Run(" "));
                                Run run = new Run(" Edit ");
                                run.Background = ThemeColours.Background_Brush_Blue_VeryDark;
                                run.Foreground = Brushes.White;
                                run.Cursor     = Cursors.Hand;
                                run.Tag        = pdf_annotation;
                                run.MouseDown += run_AnnotationEdit_MouseDown;
                                click_options.Inlines.Add(run);
                            }

                            {
                                click_options.Inlines.Add(new Run(" "));
                                Run run = new Run(" Cite (Author, Date) ");
                                run.Background = ThemeColours.Background_Brush_Blue_VeryDark;
                                run.Foreground = Brushes.White;
                                run.Cursor     = Cursors.Hand;
                                run.Tag        = pdf_document;
                                run.MouseDown += run_Cite_MouseDown_Together;
                                click_options.Inlines.Add(run);
                            }

                            {
                                click_options.Inlines.Add(new Run(" "));
                                Run run = new Run(" Cite Author (Date) ");
                                run.Background = ThemeColours.Background_Brush_Blue_VeryDark;
                                run.Foreground = Brushes.White;
                                run.Cursor     = Cursors.Hand;
                                run.Tag        = pdf_document;
                                run.MouseDown += run_Cite_MouseDown_Separate;
                                click_options.Inlines.Add(run);
                            }

                            click_options.Inlines.Add(new LineBreak());

                            paragraph.Inlines.Add(click_options);
                            annotation_report.AddClickOption(click_options);
                        }

                        {
                            Run run = new Run("Waiting for processing...");
                            run.Foreground = Brushes.Red;
                            paragraph.Inlines.Add(run);
                            annotation_work.processing_error = run;
                        }

                        paragraph.Background = ThemeColours.Background_Brush_Blue_DarkToWhite;
                        flow_document.Blocks.Add(paragraph);
                    }

                    if (!String.IsNullOrEmpty(pdf_annotation.Text))
                    {
                        Paragraph paragraph = new Paragraph();
                        paragraph.Inlines.Add(pdf_annotation.Text);
                        flow_document.Blocks.Add(paragraph);
                    }

                    {
                        // Prepare for some annotation image
                        if ((!annotation_report_options.ObeySuppressedImages || !pdf_annotation.AnnotationReportSuppressImage) && !annotation_report_options.SuppressAllImages)
                        {
                            Image image = new Image();
                            MouseWheelDisabler.DisableMouseWheelForControl(image);
                            image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageWaiting);
                            BlockUIContainer image_container = new BlockUIContainer(image);
                            Figure           floater         = new Figure(image_container);
                            floater.HorizontalAnchor = FigureHorizontalAnchor.PageCenter;
                            floater.WrapDirection    = WrapDirection.None;
                            floater.Width            = new FigureLength(64);

                            floater.Cursor     = Cursors.Hand;
                            floater.Tag        = annotation_work;
                            floater.MouseDown += Floater_MouseDown;

                            Paragraph paragraph = new Paragraph();
                            paragraph.Inlines.Add(floater);

                            annotation_work.report_image   = image;
                            annotation_work.report_floater = floater;

                            flow_document.Blocks.Add(paragraph);
                        }

                        // Prepare for some annotation text
                        if ((!annotation_report_options.ObeySuppressedText || !pdf_annotation.AnnotationReportSuppressText) && !annotation_report_options.SuppressAllText)
                        {
                            Paragraph paragraph = new Paragraph();
                            annotation_work.annotation_paragraph = paragraph;
                            flow_document.Blocks.Add(paragraph);
                        }
                    }
                }

                // Add another paragraph to separate nicely
                {
                    Paragraph paragraph = new Paragraph();
                    flow_document.Blocks.Add(paragraph);
                }
            }

            // Render the images in the background
            BackgroundRenderImages(flow_document, annotation_works, annotation_report_options);

            // Finito!
            StatusManager.Instance.ClearStatus("AnnotationReport");

            return(annotation_report);
        }
        private static void OnShowTagOptionsComplete(Library library, List <PDFDocument> pdf_documents, AnnotationReportOptions annotation_report_options)
        {
            var annotation_report           = BuildReport(library, pdf_documents, annotation_report_options);
            FlowDocumentScrollViewer viewer = new FlowDocumentScrollViewer();

            viewer.Document = annotation_report.flow_document;
            ControlHostingWindow window = new ControlHostingWindow("Annotations", viewer);

            window.Show();
        }
        private static void BackgroundRenderImages_BACKGROUND(FlowDocument flow_document, List <AnnotationWorkGenerator.AnnotationWork> annotation_works, AnnotationReportOptions annotation_report_options)
        {
            Thread.Sleep(annotation_report_options.InitialRenderDelayMilliseconds);

            PDFDocument last_pdf_document = null;

            StatusManager.Instance.ClearCancelled("AnnotationReportBackground");
            for (int j = 0; j < annotation_works.Count; ++j)
            {
                StatusManager.Instance.UpdateStatus("AnnotationReportBackground", "Building annotation report image", j, annotation_works.Count, true);
                if (StatusManager.Instance.IsCancelled("AnnotationReportBackground"))
                {
                    Logging.Warn("User cancelled annotation report generation");
                    break;
                }

                AnnotationWorkGenerator.AnnotationWork annotation_work = annotation_works[j];
                PDFDocument pdf_document = annotation_work.pdf_document;

                // Clear down our previously caches pages
                if (null != last_pdf_document && last_pdf_document != pdf_document)
                {
                    if (last_pdf_document.DocumentExists)
                    {
                        last_pdf_document.PDFRenderer.FlushCachedPageRenderings();
                    }
                }

                // Remember this PDF document so we can flush it if necessary
                last_pdf_document = pdf_document;

                // Now render each image
                PDFAnnotation pdf_annotation = annotation_work.pdf_annotation;
                if (null != pdf_annotation)
                {
                    try
                    {
                        // Clear the waiting for processing text
                        annotation_work.processing_error.Dispatcher.Invoke(new Action(() =>
                        {
                            annotation_work.processing_error.Text = "";
                        }
                                                                                      ), DispatcherPriority.Background);


                        if (pdf_document.DocumentExists)
                        {
                            // Fill in the paragraph text
                            if (null != annotation_work.annotation_paragraph)
                            {
                                annotation_work.processing_error.Dispatcher.Invoke(
                                    new Action(() => BuildAnnotationWork_FillAnnotationText(pdf_document, pdf_annotation, annotation_work)),
                                    DispatcherPriority.Background);
                            }

                            if (null != annotation_work.report_floater)
                            {
                                annotation_work.processing_error.Dispatcher.Invoke(new Action(() =>
                                {
                                    try
                                    {
                                        System.Drawing.Image annotation_image = PDFAnnotationToImageRenderer.RenderAnnotation(pdf_document, pdf_annotation, 80);
                                        BitmapSource cropped_image_page       = BitmapImageTools.FromImage(annotation_image);
                                        annotation_work.report_image.Source   = cropped_image_page;
                                        annotation_work.report_floater.Width  = new FigureLength(cropped_image_page.PixelWidth / 1);
                                    }
                                    catch (Exception ex)
                                    {
                                        Logging.Warn(ex, "There was a problem while rendering an annotation.");
                                        annotation_work.report_image.Source   = Icons.GetAppIcon(Icons.AnnotationReportImageError);
                                        annotation_work.processing_error.Text = "There was a problem while rendering this annotation.";
                                    }
                                }
                                                                                              ), DispatcherPriority.Background);
                            }
                        }
                        else
                        {
                            annotation_work.processing_error.Dispatcher.Invoke(new Action(() =>
                            {
                                if (null != annotation_work.report_image)
                                {
                                    annotation_work.report_image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageError);
                                }

                                annotation_work.processing_error.Text = "Can't show image: The PDF does not exist locally.";
                            }
                                                                                          ), DispatcherPriority.Background);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.Error(ex, "There was an error while rendering page {0} for document {1} for the annotation report", pdf_annotation.Page, pdf_annotation.DocumentFingerprint);

                        annotation_work.processing_error.Dispatcher.Invoke(new Action(() =>
                        {
                            if (null != annotation_work.report_image)
                            {
                                annotation_work.report_image.Source = Icons.GetAppIcon(Icons.AnnotationReportImageError);
                            }

                            annotation_work.processing_error.Text = "Can't show image: There was an error rendering the metadata image.";
                        }
                                                                                      ), DispatcherPriority.Background);
                    }
                }
            }

            // And flush the rendering cache of the last document
            if (null != last_pdf_document)
            {
                if (last_pdf_document.DocumentExists)
                {
                    last_pdf_document.PDFRenderer.FlushCachedPageRenderings();
                }
            }

            StatusManager.Instance.ClearStatus("AnnotationReportBackground");
        }
 private static void BackgroundRenderImages(FlowDocument flow_document, List <AnnotationWorkGenerator.AnnotationWork> annotation_works, AnnotationReportOptions annotation_report_options)
 {
     // Render the images in the background
     SafeThreadPool.QueueUserWorkItem(o => BackgroundRenderImages_BACKGROUND(flow_document, annotation_works, annotation_report_options));
 }
        public static List <AnnotationWork> GenerateAnnotationWorks(WebLibraryDetail web_library_detail, List <PDFDocument> pdf_documents, AnnotationReportOptions annotation_report_options)
        {
            WPFDoEvents.AssertThisCodeIs_NOT_RunningInTheUIThread();

            Stopwatch clk = Stopwatch.StartNew();

            Logging.Info("+GenerateAnnotationWorks: collecting annotations for documents: {0}", Library.GetDocumentsAsFingerprints(pdf_documents));

            List <AnnotationWork> annotation_works = new List <AnnotationWork>();

            // The caches we will need...
            //
            // ## Performance Note:
            //
            // We need to keep in mind the fact that, for a long list of documents, each of their fingerprints will end up in the
            // SQL query to keep the number of sought results to a minimum. Now that would be very fine indeed if the set of documents
            // would be *small* for then the bulk of this function has few documents to cycle through in the loop further below.
            // HOWEVER, imagine a library of 10K+ items and a user kicking this function into work with the entire set passed down through
            // `pdf_documents`: if we weren't applying a bit of extra intelligence here, we would end up with an 'optimized' SQL query
            // containing an 'x OR y OR ...' SELECT filter expression containing 10K+ comparisons: the cost of generating such a huge
            // query would be considerable, let alone the *parsing* of it by SQLite and processing in that DB engine.
            //
            // Hence we're applying a bit of heuristic here: when your *set* includes more than, say, 42 documents (which we all know
            // is the answer to everything and thus also to 'reasonable measure for one page/screen full'  ;-P  ) we simply DO NOT PASS
            // the set on to the query generator-annex-processor call GetLibraryItemsAsCache() but let that one follow its *default*
            // behaviour *instead*, which is to dump the entire table in our lap and good riddance.
            // for more than 42 documents in the set and medium to huge libraries, this is expected to be 'near enough to optimal'.  :-)
            // When you beg to differ, you may. Benchmarks, please! (I know you'll be able to improve on this, surely, but you get my drift:
            // is it worth it yet? Or are there other areas with bigger fish to fry?  ;-)
            //
            ASSERT.Test(pdf_documents != null);                                                         // check these unexpected input combo's
            ASSERT.Test(pdf_documents.Count > 0);                                                       // check these unexpected input combo's
            bool          deliver_reduced_optimal_set = (annotation_report_options.IncludeAllPapers ? false /* we want them *all* anyway! */ : pdf_documents != null ? pdf_documents.Count <= 42 : false /* no fingerprints at all?! */);
            List <string> reduced_optimal_set         = (deliver_reduced_optimal_set ? Library.GetDocumentsAsFingerprints(pdf_documents) : null);
            Dictionary <string, byte[]> library_items_highlights_cache = web_library_detail.Xlibrary.LibraryDB.GetLibraryItemsAsCache(PDFDocumentFileLocations.HIGHLIGHTS, reduced_optimal_set);
            Dictionary <string, byte[]> library_items_inks_cache       = web_library_detail.Xlibrary.LibraryDB.GetLibraryItemsAsCache(PDFDocumentFileLocations.INKS, reduced_optimal_set);

            for (int j = 0; j < pdf_documents.Count; ++j)
            {
                if (j % 10 == 0)
                {
                    StatusManager.Instance.UpdateStatus("AnnotationReport", "Initialising annotation report", j, pdf_documents.Count);
                }

                PDFDocument pdf_document = pdf_documents[j];

                // Add the comments token if this document has some comments or abstract (and the user wants them)
                if (annotation_report_options.IncludeAllPapers && (annotation_report_options.IncludeComments || annotation_report_options.IncludeAbstract))
                {
                    if (!String.IsNullOrEmpty(pdf_document.Comments) || !String.IsNullOrEmpty(pdf_document.Abstract))
                    {
                        annotation_works.Add(new AnnotationWork {
                            web_library_detail = web_library_detail, pdf_document = pdf_document, pdf_annotation = null
                        });
                    }
                }

                List <PDFAnnotation> pdf_annotations = new List <PDFAnnotation>();
                pdf_annotations.AddRange(pdf_document.GetAnnotations());
                if (library_items_highlights_cache.ContainsKey(pdf_document.Fingerprint))
                {
                    pdf_annotations.AddRange(HighlightToAnnotationGenerator.GenerateAnnotations(pdf_document, library_items_highlights_cache));
                }
                if (library_items_inks_cache.ContainsKey(pdf_document.Fingerprint))
                {
                    pdf_annotations.AddRange(InkToAnnotationGenerator.GenerateAnnotations(pdf_document));
                }

                pdf_annotations.Sort(AnnotationSorter);

                foreach (PDFAnnotation pdf_annotation in pdf_annotations)
                {
                    if (pdf_annotation.Deleted)
                    {
                        continue;
                    }

                    // Filter by annotations
                    if (null != annotation_report_options.filter_tags && annotation_report_options.filter_tags.Count > 0)
                    {
                        HashSet <string> annotation_tags = TagTools.ConvertTagBundleToTags(pdf_annotation.Tags);
                        annotation_tags.IntersectWith(annotation_report_options.filter_tags);
                        if (0 == annotation_tags.Count)
                        {
                            continue;
                        }
                    }

                    // Filter by date ranges and creators
                    {
                        if (annotation_report_options.FilterByCreationDate && pdf_annotation.DateCreated.HasValue)
                        {
                            DateTime date_to = annotation_report_options.FilterByCreationDate_To;
                            if (date_to != DateTime.MaxValue)
                            {
                                date_to = date_to.AddDays(1);
                            }

                            if (pdf_annotation.DateCreated.Value < annotation_report_options.FilterByCreationDate_From)
                            {
                                continue;
                            }
                            if (pdf_annotation.DateCreated.Value >= date_to)
                            {
                                continue;
                            }
                        }

                        if (annotation_report_options.FilterByFollowUpDate)
                        {
                            DateTime date_to = annotation_report_options.FilterByFollowUpDate_To;
                            if (date_to != DateTime.MaxValue)
                            {
                                date_to = date_to.AddDays(1);
                            }

                            if (!pdf_annotation.FollowUpDate.HasValue)
                            {
                                continue;
                            }
                            if (pdf_annotation.FollowUpDate.Value < annotation_report_options.FilterByFollowUpDate_From)
                            {
                                continue;
                            }
                            if (pdf_annotation.FollowUpDate.Value >= date_to)
                            {
                                continue;
                            }
                        }

                        if (annotation_report_options.FilterByCreator)
                        {
                            if (pdf_annotation.Creator != annotation_report_options.FilterByCreator_Name)
                            {
                                continue;
                            }
                        }
                    }

                    annotation_works.Add(new AnnotationWork {
                        web_library_detail = web_library_detail, pdf_document = pdf_document, pdf_annotation = pdf_annotation
                    });
                }
            }

            Logging.Info("-GenerateAnnotationWorks: collecting annotations for documents: {1} (time spent: {0} ms)", clk.ElapsedMilliseconds, Library.GetDocumentsAsFingerprints(pdf_documents));

            return(annotation_works);
        }