<commit_before>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using XamlCSS.CssParsing;
using XamlCSS.Dom;
using XamlCSS.Utils;

namespace XamlCSS
{
    public class BaseCss<TDependencyObject, TStyle, TDependencyProperty>
        where TDependencyObject : class
        where TStyle : class
        where TDependencyProperty : class
    {
        public readonly IDependencyPropertyService<TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService;
        public readonly ITreeNodeProvider<TDependencyObject> treeNodeProvider;
        public readonly IStyleResourcesService applicationResourcesService;
        public readonly INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService;

        protected bool executeApplyStylesExecuting;

        private readonly IMarkupExtensionParser markupExpressionParser;
        private Action<Action> uiInvoker;
        private List<RenderInfo<TDependencyObject>> items = new List<RenderInfo<TDependencyObject>>();
        private CssTypeHelper<TDependencyObject, TDependencyProperty, TStyle> cssTypeHelper;
        private int noopCount = 0;

        public BaseCss(IDependencyPropertyService<TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService,
            ITreeNodeProvider<TDependencyObject> treeNodeProvider,
            IStyleResourcesService applicationResourcesService,
            INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService,
            string defaultCssNamespace,
            IMarkupExtensionParser markupExpressionParser,
            Action<Action> uiInvoker,
            ICssFileProvider fileProvider)
        {
            this.dependencyPropertyService = dependencyPropertyService;
            this.treeNodeProvider = treeNodeProvider;
            this.applicationResourcesService = applicationResourcesService;
            this.nativeStyleService = nativeStyleService;
            this.markupExpressionParser = markupExpressionParser;
            this.uiInvoker = uiInvoker;
            this.cssTypeHelper = new CssTypeHelper<TDependencyObject, TDependencyProperty, TStyle>(markupExpressionParser, dependencyPropertyService);

            CssParser.Initialize(defaultCssNamespace, fileProvider);
            StyleSheet.GetParent = parent => treeNodeProvider.GetParent((TDependencyObject)parent, SelectorType.VisualTree);
            StyleSheet.GetStyleSheet = treeNode => dependencyPropertyService.GetStyleSheet((TDependencyObject)treeNode);
        }

        public void ExecuteApplyStyles()
        {
            if (executeApplyStylesExecuting)
            {
                return;
            }

            executeApplyStylesExecuting = true;

            List<RenderInfo<TDependencyObject>> copy;

            //lock (items)
            {
                if (items.Count == 0)
                {
                    noopCount++;
                    executeApplyStylesExecuting = false;
                    return;
                }

                copy = items.Distinct().ToList();
                items.Clear();
            }
            Debug.WriteLine("Noops: " + noopCount);
            noopCount = 0;

            var styleholder = copy.First().StyleSheetHolder;

            "Render".Measure(() =>
            {
                Render(copy, treeNodeProvider, dependencyPropertyService, nativeStyleService, applicationResourcesService, cssTypeHelper);
            });

            Investigate.Print();
            executeApplyStylesExecuting = false;
        }

        private static void RemoveStyleResourcesInternal(
            TDependencyObject styleResourceReferenceHolder,
            StyleSheet styleSheet,
            IStyleResourcesService applicationResourcesService,
            INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService)
        {
            var resourceKeys = applicationResourcesService.GetKeys()
                .OfType<string>()
                .Where(x => x.StartsWith($"{nativeStyleService.BaseStyleResourceKey}_{styleSheet.Id}", StringComparison.Ordinal))
                .ToList();

            foreach (var key in resourceKeys)
            {
                applicationResourcesService.RemoveResource(key);
            }
        }

        public static void Render(
            List<RenderInfo<TDependencyObject>> copy,
            ITreeNodeProvider<TDependencyObject> treeNodeProvider,
            IDependencyPropertyService<TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService,
            INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService,
            IStyleResourcesService applicationResourcesService,
            CssTypeHelper<TDependencyObject, TDependencyProperty, TStyle> cssTypeHelper)
        {
            try
            {
                "BeginUpdate".Measure(() => applicationResourcesService.BeginUpdate());

                "RemoveOldStyleObjects".Measure(() =>
                {
                    RemoveOldStyleObjects(copy, nativeStyleService, applicationResourcesService);
                });
                "SetAttachedToToNull".Measure(() =>
                {
                    SetAttachedToToNull(copy, dependencyPropertyService, treeNodeProvider, nativeStyleService);
                });
                "SetAttachedToToNewStyleSheet".Measure(() =>
                {
                    SetAttachedToToNewStyleSheet(copy, dependencyPropertyService, treeNodeProvider, nativeStyleService);
                });

                var styleUpdateInfos = new Dictionary<TDependencyObject, StyleUpdateInfo>();

                var newOrUpdatedStyleSheets = copy
                   .Where(x =>
                   x.RenderTargetKind == RenderTargetKind.Stylesheet)
                   .Select(x => x.StyleSheet)
                   .Distinct()
                   .ToList();

                var newOrUpdatedStyleHolders = copy
                    .Where(x =>
                        x.ChangeKind == ChangeKind.New ||
                        x.ChangeKind == ChangeKind.Update ||
                        x.ChangeKind == ChangeKind.Remove)
                    .Select(x => new { x.ChangeKind, x.StartFrom, x.StyleSheet, x.StyleSheetHolder })
                    .Distinct()
                    .ToList();

                "SetupStyleInfo LOGICAL".Measure(() =>
                {
                    foreach (var item in newOrUpdatedStyleHolders)
                    {
                        var start = item.StartFrom ?? item.StyleSheetHolder;
                        if (!treeNodeProvider.IsInTree(start, SelectorType.LogicalTree))
                        {
                            continue;
                        }
                        var domElement = treeNodeProvider.GetDomElement(start);

                        "EnsureParents".Measure(() =>
                        {
                            EnsureParents(domElement, treeNodeProvider, dependencyPropertyService, nativeStyleService, styleUpdateInfos, SelectorType.LogicalTree);
                        });

                        SetupStyleInfo(domElement, item.StyleSheet, styleUpdateInfos, treeNodeProvider, dependencyPropertyService, nativeStyleService, false, item.ChangeKind == ChangeKind.Remove, SelectorType.LogicalTree);
                    }
                });

                "SetupStyleInfo VisualTree".Measure(() =>
                {
                    foreach (var item in newOrUpdatedStyleHolders)
                    {
                        var start = item.StartFrom ?? item.StyleSheetHolder;
                        if (!treeNodeProvider.IsInTree(start, SelectorType.VisualTree))
                        {
                            continue;
                        }

                        var domElement = treeNodeProvider.GetDomElement(start);

                        "EnsureParents".Measure(() =>
                        {
                            EnsureParents(domElement, treeNodeProvider, dependencyPropertyService, nativeStyleService, styleUpdateInfos, SelectorType.VisualTree);
                        });

                        var discardOldMatchingStyles = newOrUpdatedStyleSheets.Contains(item.StyleSheet);
                        SetupStyleInfo(domElement, item.StyleSheet, styleUpdateInfos, treeNodeProvider, dependencyPropertyService, nativeStyleService, discardOldMatchingStyles, item.ChangeKind == ChangeKind.Remove, SelectorType.VisualTree);
                    }
                });

                var tasks = new List<Task<IList<IDomElement<TDependencyObject>>>>();
                var distinctCopy = copy.Select(x => new { x.StartFrom, x.StyleSheetHolder, x.StyleSheet }).Distinct().ToList();
                $"distinctCopy {distinctCopy.Count} items".Measure(() => { });
                foreach (var item in distinctCopy)
                {<commit_msg>Fix update-old-matching-styles still set if stylesheet is updated<commit_after>﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using XamlCSS.CssParsing;
using XamlCSS.Dom;
using XamlCSS.Utils;

namespace XamlCSS
{
    public class BaseCss<TDependencyObject, TStyle, TDependencyProperty>
        where TDependencyObject : class
        where TStyle : class
        where TDependencyProperty : class
    {
        public readonly IDependencyPropertyService<TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService;
        public readonly ITreeNodeProvider<TDependencyObject> treeNodeProvider;
        public readonly IStyleResourcesService applicationResourcesService;
        public readonly INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService;

        protected bool executeApplyStylesExecuting;

        private readonly IMarkupExtensionParser markupExpressionParser;
        private Action<Action> uiInvoker;
        private List<RenderInfo<TDependencyObject>> items = new List<RenderInfo<TDependencyObject>>();
        private CssTypeHelper<TDependencyObject, TDependencyProperty, TStyle> cssTypeHelper;
        private int noopCount = 0;

        public BaseCss(IDependencyPropertyService<TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService,
            ITreeNodeProvider<TDependencyObject> treeNodeProvider,
            IStyleResourcesService applicationResourcesService,
            INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService,
            string defaultCssNamespace,
            IMarkupExtensionParser markupExpressionParser,
            Action<Action> uiInvoker,
            ICssFileProvider fileProvider)
        {
            this.dependencyPropertyService = dependencyPropertyService;
            this.treeNodeProvider = treeNodeProvider;
            this.applicationResourcesService = applicationResourcesService;
            this.nativeStyleService = nativeStyleService;
            this.markupExpressionParser = markupExpressionParser;
            this.uiInvoker = uiInvoker;
            this.cssTypeHelper = new CssTypeHelper<TDependencyObject, TDependencyProperty, TStyle>(markupExpressionParser, dependencyPropertyService);

            CssParser.Initialize(defaultCssNamespace, fileProvider);
            StyleSheet.GetParent = parent => treeNodeProvider.GetParent((TDependencyObject)parent, SelectorType.VisualTree);
            StyleSheet.GetStyleSheet = treeNode => dependencyPropertyService.GetStyleSheet((TDependencyObject)treeNode);
        }

        public void ExecuteApplyStyles()
        {
            if (executeApplyStylesExecuting)
            {
                return;
            }

            executeApplyStylesExecuting = true;

            List<RenderInfo<TDependencyObject>> copy;

            //lock (items)
            {
                if (items.Count == 0)
                {
                    noopCount++;
                    executeApplyStylesExecuting = false;
                    return;
                }

                copy = items.Distinct().ToList();
                items.Clear();
            }
            Debug.WriteLine("Noops: " + noopCount);
            noopCount = 0;

            var styleholder = copy.First().StyleSheetHolder;

            "Render".Measure(() =>
            {
                Render(copy, treeNodeProvider, dependencyPropertyService, nativeStyleService, applicationResourcesService, cssTypeHelper);
            });

            Investigate.Print();
            executeApplyStylesExecuting = false;
        }

        private static void RemoveStyleResourcesInternal(
            TDependencyObject styleResourceReferenceHolder,
            StyleSheet styleSheet,
            IStyleResourcesService applicationResourcesService,
            INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService)
        {
            var resourceKeys = applicationResourcesService.GetKeys()
                .OfType<string>()
                .Where(x => x.StartsWith($"{nativeStyleService.BaseStyleResourceKey}_{styleSheet.Id}", StringComparison.Ordinal))
                .ToList();

            foreach (var key in resourceKeys)
            {
                applicationResourcesService.RemoveResource(key);
            }
        }

        public static void Render(
            List<RenderInfo<TDependencyObject>> copy,
            ITreeNodeProvider<TDependencyObject> treeNodeProvider,
            IDependencyPropertyService<TDependencyObject, TStyle, TDependencyProperty> dependencyPropertyService,
            INativeStyleService<TStyle, TDependencyObject, TDependencyProperty> nativeStyleService,
            IStyleResourcesService applicationResourcesService,
            CssTypeHelper<TDependencyObject, TDependencyProperty, TStyle> cssTypeHelper)
        {
            try
            {
                "BeginUpdate".Measure(() => applicationResourcesService.BeginUpdate());

                "RemoveOldStyleObjects".Measure(() =>
                {
                    RemoveOldStyleObjects(copy, nativeStyleService, applicationResourcesService);
                });
                "SetAttachedToToNull".Measure(() =>
                {
                    SetAttachedToToNull(copy, dependencyPropertyService, treeNodeProvider, nativeStyleService);
                });
                "SetAttachedToToNewStyleSheet".Measure(() =>
                {
                    SetAttachedToToNewStyleSheet(copy, dependencyPropertyService, treeNodeProvider, nativeStyleService);
                });

                var styleUpdateInfos = new Dictionary<TDependencyObject, StyleUpdateInfo>();

                var newOrUpdatedStyleSheets = copy
                   .Where(x =>
                   x.RenderTargetKind == RenderTargetKind.Stylesheet)
                   .Select(x => x.StyleSheet)
                   .Distinct()
                   .ToList();

                var newOrUpdatedStyleHolders = copy
                    .Where(x =>
                        x.ChangeKind == ChangeKind.New ||
                        x.ChangeKind == ChangeKind.Update ||
                        x.ChangeKind == ChangeKind.Remove)
                    .Select(x => new { x.ChangeKind, x.StartFrom, x.StyleSheet, x.StyleSheetHolder })
                    .Distinct()
                    .ToList();

                "SetupStyleInfo LOGICAL".Measure(() =>
                {
                    foreach (var item in newOrUpdatedStyleHolders)
                    {
                        var start = item.StartFrom ?? item.StyleSheetHolder;
                        if (!treeNodeProvider.IsInTree(start, SelectorType.LogicalTree))
                        {
                            continue;
                        }
                        var domElement = treeNodeProvider.GetDomElement(start);

                        "EnsureParents".Measure(() =>
                        {
                            EnsureParents(domElement, treeNodeProvider, dependencyPropertyService, nativeStyleService, styleUpdateInfos, SelectorType.LogicalTree);
                        });

                        var discardOldMatchingStyles = newOrUpdatedStyleSheets.Contains(item.StyleSheet);
                        SetupStyleInfo(domElement, item.StyleSheet, styleUpdateInfos, treeNodeProvider, dependencyPropertyService, nativeStyleService, discardOldMatchingStyles, item.ChangeKind == ChangeKind.Remove, SelectorType.LogicalTree);
                    }
                });

                "SetupStyleInfo VisualTree".Measure(() =>
                {
                    foreach (var item in newOrUpdatedStyleHolders)
                    {
                        var start = item.StartFrom ?? item.StyleSheetHolder;
                        if (!treeNodeProvider.IsInTree(start, SelectorType.VisualTree))
                        {
                            continue;
                        }

                        var domElement = treeNodeProvider.GetDomElement(start);

                        "EnsureParents".Measure(() =>
                        {
                            EnsureParents(domElement, treeNodeProvider, dependencyPropertyService, nativeStyleService, styleUpdateInfos, SelectorType.VisualTree);
                        });

                        var discardOldMatchingStyles = newOrUpdatedStyleSheets.Contains(item.StyleSheet);
                        SetupStyleInfo(domElement, item.StyleSheet, styleUpdateInfos, treeNodeProvider, dependencyPropertyService, nativeStyleService, discardOldMatchingStyles, item.ChangeKind == ChangeKind.Remove, SelectorType.VisualTree);
                    }
                });

                var tasks = new List<Task<IList<IDomElement<TDependencyObject>>>>();
                var distinctCopy = copy.Select(x => new { x.StartFrom, x.StyleSheetHolder, x.StyleSheet }).Distinct().ToList();
                $"distinctCopy {distinctCopy.Count} items".Measure(() => { });
                foreach (var item in distinctCopy)
                {
{'fraction_non_alphanumeric': 0.07338589623421735, 'fraction_numerical': 0.0003308154601091691, 'mean_word_length': 2.0044724200761967, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3902822', 'n_tokens_mistral': 4128, 'n_tokens_neox': 3995, 'n_words': 722}