public static Records <Record> PostProcess(Records <PreRecord> preRecords, PagesPropertiesPanel pagesProperties, Field schema, XDocument data, bool useFilters)
        {
#if PERF_TEST
            var processClock = new Stopwatch();
            processClock.Start();
#endif
            var  filterGrid  = pagesProperties.VariableDataGrid;
            var  selVariable = ((ComboBoxItem)filterGrid.ComboBoxVariable.SelectedItem).Content as string;
            var  pageNames   = preRecords.First().Select((page) => page.Id).ToList();
            bool postFilter  = SystemVariable.MAP.ContainsKey(selVariable) &&
                               SystemVariable.MAP[selVariable].Flag != SystemVariable.EFlag.RECORD_INDEX;

            // Post filter
            if (postFilter && useFilters)
            {
                foreach (var record in preRecords)
                {
                    PostSystemFilter(filterGrid.GridDataset, record, SystemVariable.MAP[selVariable].Flag);
                }
            }

            // Build Next Page chains
            var records = new Records <Record>();
            foreach (var preRecord in preRecords)
            {
                var record = new Record();
                record.RecordIndex = preRecord.RecordIndex;
                foreach (var procPage in preRecord.Where((p) => preRecord.Whitelist.Contains(p.Id)))
                {
                    record.AddRange(GetNextPageChain(preRecord.ToList(), procPage));
                }
                record.TotalPages = record.Count;
                records.Add(record);
            }

            records.MasterPageCounter = records.Sum((record) => record.Count);
            records.GlobalPageCounter = preRecords[0].Count;

            // Populate SystemVariables in the records
            foreach (var record in records)
            {
                foreach (var page in record)
                {
                    foreach (CanvasVariable csd in (page.CanvasControls.Where((control) => { return(control.GetType().IsSubclassOf(typeof(CanvasVariable))); })))
                    {
                        var csdName = csd.GetSchemaElementName();
                        if (SystemVariable.MAP.ContainsKey(csdName))
                        {
                            switch (SystemVariable.MAP[csdName].Flag)
                            {
                            case SystemVariable.EFlag.MASTER_PAGE_COUNTER:
                                csd.Label.Content = records.Count.ToString();
                                break;

                            case SystemVariable.EFlag.TOTAL_PAGES_RECORD:
                                csd.Label.Content = record.TotalPages.ToString();
                                break;
                            }
                        }
                    }
                }
            }

        #if PERF_TEST
            processClock.Stop();
            Console.WriteLine("Process={0}", processClock.Elapsed);
        #endif

            foreach (var record in records)
            {
                foreach (var page in record)
                {
                    page.Canvas.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
                    page.Canvas.Arrange(new System.Windows.Rect(page.Canvas.DesiredSize));
                    page.Canvas.UpdateLayout();
                }
            }
            return(records);
        }
        public static Records <PreRecord> Preprocess(Pages pages, Field schema, XDocument data, bool useFilters)
        {
#if PERF_TEST
            var recordsClock    = new Stopwatch();
            var recordClock     = new Stopwatch();
            var recordItemClock = new Stopwatch();
            var preprocessClock = new Stopwatch();

            preprocessClock.Start();
#endif
            var PagesProperties = pages.LayoutProperties as PagesPropertiesPanel;
            var records         = new Records <PreRecord>();
            records.JobStart          = DateTime.Now;
            records.GlobalPageCounter = pages.Count;
            var  filterGrid  = PagesProperties.VariableDataGrid;
            var  selVariable = ((ComboBoxItem)filterGrid.ComboBoxVariable.SelectedItem).Content as string;
            var  pageNames   = pages.Select((page) => page.Id).ToList();
            bool postFilter  = SystemVariable.MAP.ContainsKey(selVariable) &&
                               SystemVariable.MAP[selVariable].Flag != SystemVariable.EFlag.RECORD_INDEX;
            var elements = data.Root.Elements().ToArray();

            // Generate all available page templates for each record that match preprocess filters
            for (int i = 0; i < elements.Count(); i++)
            {
#if PERF_TEST
                recordClock.Restart();
#endif
                var elem   = elements[i];
                var record = new PreRecord();

                if (SystemVariable.MAP.ContainsKey(selVariable) && SystemVariable.MAP[selVariable].Flag == SystemVariable.EFlag.RECORD_INDEX)
                {
                    record.Whitelist.AddRange(PreSystemFilter(filterGrid.GridDataset, i, SystemVariable.MAP[selVariable].Flag));
                }
                else if (!postFilter && useFilters)
                {
                    record.Whitelist.AddRange(PreDataFilter(filterGrid.GridDataset, elem, selVariable));
                }
                else
                {
                    record.Whitelist.AddRange(pageNames);
                }

                record.RecordIndex = records.Count;

                var             filteredPages   = pages.Where((page) => record.Whitelist.Contains(page.Id));
                List <PageBase> sourceTemplates = null;
                if (pages.LayoutProperties.IsPageOrderVariable)
                {
                    sourceTemplates = new List <PageBase>();
                    foreach (var page in filteredPages.Where((p) => p.QueryNextPage() != PageBase.NextPageCondition.FALSE))
                    {
                        sourceTemplates.AddRange(GetNextPageChain(pages.ToList(), page));
                    }

                    sourceTemplates = sourceTemplates.Distinct().ToList();
                }

                // If there's no next page chains, just add the filtered pages as a source
                if (sourceTemplates == null || sourceTemplates.Count <= 0)
                {
                    sourceTemplates = filteredPages.ToList();
                }

                for (int x = 0; x < sourceTemplates.Count; x++)
                {
#if PERF_TEST
                    recordItemClock.Restart();
#endif
                    var page = sourceTemplates[x];
                    record.Add(CompilePageFromSource(page, record, elem, pages.Count, x, records.JobStart));
#if PERF_TEST
                    recordItemClock.Stop();
                    Console.WriteLine("recordItem={0}", recordItemClock.Elapsed);
#endif
                }
                record.TotalPages = record.Count;
                records.Add(record);
#if PERF_TEST
                recordClock.Stop();
                Console.WriteLine("Record={0}", recordClock.Elapsed);
#endif
            }
#if PERF_TEST
            preprocessClock.Stop();
            Console.WriteLine("Records(totalPreprocess)={0}", preprocessClock.Elapsed);
#endif
            return(records);
        }