<commit_before>﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections;
using Signum.Utilities;
using Signum.Utilities.DataStructures;
using Signum.Entities;
using System.Linq;
using System.Xml.Linq;
using Signum.Utilities.Reflection;
using Signum.Utilities.ExpressionTrees;

namespace Signum.Entities.Reflection
{
    public static class GraphExplorer
    {
        public static void PropagateModifications(DirectedGraph<Modifiable> inverseGraph)
        {
            if (inverseGraph == null)
                throw new ArgumentNullException("inverseGraph");

            foreach (Modifiable item in inverseGraph)
                item.Modified = false;

            foreach (Modifiable item in inverseGraph)
                if (item.SelfModified)
                    Propagate(item, inverseGraph); 
        }

        static void Propagate(Modifiable item, DirectedGraph<Modifiable> inverseGraph)
        {
            if (item.Modified.Value)
                return;

            item.Modified = true;
            foreach (var other in inverseGraph.RelatedTo(item))
                Propagate(other, inverseGraph);
        }

  

        public static DirectedGraph<Modifiable> FromRootIdentifiable(Modifiable root)
        {
            return DirectedGraph<Modifiable>.Generate(root, ModifyInspector.IdentifiableExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static DirectedGraph<Modifiable> FromRoot(Modifiable root)
        {
            return DirectedGraph<Modifiable>.Generate(root, ModifyInspector.FullExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static DirectedGraph<Modifiable> FromRoots<T>(IEnumerable<T> roots)
            where T : Modifiable
        {
            return DirectedGraph<Modifiable>.Generate(roots.Cast<Modifiable>(), ModifyInspector.FullExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static DirectedGraph<Modifiable> FromRootsIdentifiable<T>(IEnumerable<T> roots)
            where T : Modifiable
        {
            return DirectedGraph<Modifiable>.Generate(roots.Cast<Modifiable>(), ModifyInspector.IdentifiableExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static Dictionary<ModifiableEntity, string> IntegrityDictionary(DirectedGraph<Modifiable> graph)
        {
            var result = graph.OfType<ModifiableEntity>().Select(m => new { m, Error = m.IntegrityCheck() })
                .Where(p => p.Error.HasText()).ToDictionary(a => a.m, a => a.Error);

            return result;
        }

        public static string IdentifiableIntegrityCheck(DirectedGraph<Modifiable> graph)
        {
            return graph.OfType<ModifiableEntity>().Select(m => m.IntegrityCheck()).Where(e => e.HasText()).ToString("\r\n");
        }

        public static string Integrity(DirectedGraph<Modifiable> graph)
        {
            if (graph.OfType<IdentifiableEntity>().Any())
            {
                var problems = (from m in graph.OfType<IdentifiableEntity>()
                                group m by new { Type = m.GetType(), Id = (m as IdentifiableEntity).TryCS(ident => (long?)ident.IdOrNull) ?? -m.temporalId } into g
                                where g.Count() > 1 && g.Count(m => m.SelfModified) > 0
                                select g).ToList();

                if (problems.Count > 0)
                    return "CLONE ATTACK!\r\n\r\n" + problems.ToString(p => "{0} different instances of the same entity ({1}) have been found:\r\n {2}".Formato(
                        p.Count(),
                        p.Key,
                        p.ToString(m => "  {0}{1}".Formato(m.SelfModified ? "[SelfModified] " : "", m), "\r\n")), "\r\n\r\n");

                return (from ident in graph.OfType<IdentifiableEntity>()
                        let error = ident.IdentifiableIntegrityCheck()
                        where error.HasText()
                        select new { ident, error }).ToString(p => "{0}:\r\n{1}".Formato(p.ident.BaseToString(), p.error.Indent(2)), "\r\n");
            }
            else
            {
                return (from me in graph.OfType<ModifiableEntity>()
                        select me.IntegrityCheck() into error
                        where error.HasText()
                        select error).ToString("\r\n"); 
            }
        }

        public static DirectedGraph<Modifiable> PreSaving(Func<DirectedGraph<Modifiable>> recreate)
        {
            return ModifyGraph(recreate(), (Modifiable m, ref bool graphModified) => m.PreSaving(ref graphModified), recreate);
        }

        public delegate void ModifyEntityEventHandler(Modifiable m, ref bool graphModified);

        public static DirectedGraph<Modifiable> ModifyGraph(DirectedGraph<Modifiable> graph, ModifyEntityEventHandler modifier, Func<DirectedGraph<Modifiable>> recreate)
        {
            bool graphModified = false; 
            foreach (var m in graph)
            {
                modifier(m, ref graphModified);
            }

            if(!graphModified)
                return graph; //common case

            do
            {
                var newGraph = recreate();
                graphModified = false;
                foreach (var m in newGraph.Except(graph))
                {
                    modifier(m, ref graphModified);
                }

                graph = newGraph;
            } while (graphModified);

            return graph; 
        }


        static string[] colors = 
        {
             "aquamarine1",  "aquamarine4", "blue", "blueviolet",
             "brown4", "burlywood", "cadetblue1", "cadetblue",
             "chartreuse", "chocolate", "cornflowerblue",
             "darkgoldenrod", "darkolivegreen3", "darkorchid", "darkseagreen",
             "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "forestgreen"
        };


        public static string SuperGraphviz(this DirectedGraph<Modifiable> modifiables)
        {
            Func<Type, string> color = t => colors[Math.Abs(t.FullName.GetHashCode()) % colors.Length];

            var listNodes = modifiables.Nodes.Select(n => new
            {
                Node = n,

                Fillcolor =  n is Lite? "white": color(n.GetType()),
                Color =
                    n is Lite ? color(Lite.Extract(n.GetType())) :
                    (n.SelfModified ? "red" : n.Modified == true ? "red4" :"black"),

                Shape = n is Lite ? "ellipse" :
                        n is IdentifiableEntity ? "ellipse" :
                        n is EmbeddedEntity ? "box" :
                        Reflector.IsMList(n.GetType()) ? "hexagon" : "plaintext",
                Style = n is Entity ? ", style=\"diagonals,filled,bold\"" : 
                        n is Lite? "style=\"solid,bold\"": "",

                Label = n.ToString().Etc(30, "..").RemoveDiacritics()

            }).ToList();

            string nodes = listNodes.ToString(t => "    {0} [color={1}, fillcolor={2} shape={3}{4}, label=\"{5}\"]".Formato(modifiables.Comparer.GetHashCode(t.Node), t.Color, t.Fillcolor, t.Shape, t.Style, t.Label), "\r\n");

            string arrows = modifiables.Edges.ToString(e => "    {0} -> {1}".Formato(modifiables.Comparer.GetHashCode(e.From), modifiables.Comparer.GetHashCode(e.To)), "\r\n");

            return "digraph \"Grafo\"\r\n{{\r\n    node [ style = \"filled,bold\"]\r\n\r\n{0}\r\n\r\n{1}\r\n}}".Formato(nodes, arrows);
        }

        public static DirectedGraph<IdentifiableEntity> ColapseIdentifiables(DirectedGraph<Modifiable> modifiables)
        {
            DirectedGraph<IdentifiableEntity> result = new DirectedGraph<IdentifiableEntity>();
            foreach (var item in modifiables.OfType<IdentifiableEntity>())
            {
                var toColapse = modifiables.IndirectlyRelatedTo(item, i => !(i is IdentifiableEntity));
                var toColapseFriends = toColapse.SelectMany(i => modifiables.RelatedTo(i).OfType<IdentifiableEntity>());
                result.Add(item, toColapseFriends);
                result.Add(item, modifiables.RelatedTo(item).OfType<IdentifiableEntity>());
            }
            return result;
        }

        public static XDocument EntityDGML(this DirectedGraph<Modifiable> graph)
        {
            return graph.ToDGML(n =>
                n is IdentifiableEntity ? GetAttributes((IdentifiableEntity)n): 
                n is Lite ? GetAttributes((Lite)n):
                n is EmbeddedEntity ? GetAttributes((EmbeddedEntity)n):
                n.GetType().IsMList() ? GetAttributes((IList)n) : 
                new []
                {
                    new XAttribute("Label", n.ToString() ?? "[null]"),
                    new XAttribute("TypeName", n.GetType().TypeName()), 
                    new XAttribute("Background", ColorExtensions.ToHtmlColor(n.GetType().FullName.GetHashCode()))
                });
        }

        private static XAttribute[] GetAttributes(IdentifiableEntity ie)
        {
            return new[]
            {
               new XAttribute("Label", (ie.ToString() ?? "[null]")  + Modified(ie)),
               new XAttribute("TypeName", ie.GetType().TypeName()), 
               new XAttribute("Background", ColorExtensions.ToHtmlColor(ie.GetType().FullName.GetHashCode())),
               new XAttribute("Description", ie.IdOrNull.TryToString() ?? "New")
            };
        }

        private static string Modified(Modifiable ie)
        {
            string str = ",".Combine(ie.SelfModified ? "SelfModified" : null,
                                               ie.Modified == true ? "Modified" :
                                               ie.Modified == false ? "Not-Modified" : null);

            if (str.HasText())
                return "({0})".Formato(str);

            return null;
        }

        private static XAttribute[] GetAttributes(Lite lite)
        {
            return new[]
            {
               new XAttribute("Label", (lite.ToString() ?? "[null]") + Modified(lite)),
               new XAttribute("TypeName", lite.GetType().TypeName()), 
               new XAttribute("Stroke", ColorExtensions.ToHtmlColor(Lite.Extract(lite.GetType()).FullName.GetHashCode())),
               new XAttribute("StrokeThickness", "2"),
               new XAttribute("Background", ColorExtensions.ToHtmlColor(lite.RuntimeType.FullName.GetHashCode()).Replace("#", "#44")),
               new XAttribute("Description", " ".Combine((lite.RuntimeType == Lite.Extract(lite.GetType())? "":  lite.RuntimeType.TypeName() ),   lite.IdOrNull.TryToString() ?? "New"))
            };
        }

        private static XAttribute[] GetAttributes(EmbeddedEntity ee)
        {
            return new[]
            {
               new XAttribute("Label", (ee.ToString() ?? "[null]")+  Modified(ee)),
               new XAttribute("TypeName", ee.GetType().TypeName()), 
               new XAttribute("NodeRadius", 0),
               new XAttribute("Background", ColorExtensions.ToHtmlColor(ee.GetType().FullName.GetHashCode())),
            };
        }

        private static XAttribute[] GetAttributes(IList list)
        {
            return new[]
            {
               new XAttribute("Label", (list.ToString() ?? "[null]") +  Modified((Modifiable)list)),
               new XAttribute("TypeName", list.GetType().TypeName()), 
               new XAttribute("NodeRadius", 2),
               new XAttribute("Background", ColorExtensions.ToHtmlColor(list.GetType().ElementType().FullName.GetHashCode())),
            };
        }
    }
}
<commit_msg>more on chart order windows<commit_after>﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections;
using Signum.Utilities;
using Signum.Utilities.DataStructures;
using Signum.Entities;
using System.Linq;
using System.Xml.Linq;
using Signum.Utilities.Reflection;
using Signum.Utilities.ExpressionTrees;

namespace Signum.Entities.Reflection
{
    public static class GraphExplorer
    {
        public static void PropagateModifications(DirectedGraph<Modifiable> inverseGraph)
        {
            if (inverseGraph == null)
                throw new ArgumentNullException("inverseGraph");

            foreach (Modifiable item in inverseGraph)
                item.Modified = false;

            foreach (Modifiable item in inverseGraph)
                if (item.SelfModified)
                    Propagate(item, inverseGraph); 
        }

        static void Propagate(Modifiable item, DirectedGraph<Modifiable> inverseGraph)
        {
            if (item.Modified.Value)
                return;

            item.Modified = true;
            foreach (var other in inverseGraph.RelatedTo(item))
                Propagate(other, inverseGraph);
        }

  

        public static DirectedGraph<Modifiable> FromRootIdentifiable(Modifiable root)
        {
            return DirectedGraph<Modifiable>.Generate(root, ModifyInspector.IdentifiableExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static DirectedGraph<Modifiable> FromRoot(Modifiable root)
        {
            return DirectedGraph<Modifiable>.Generate(root, ModifyInspector.FullExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static DirectedGraph<Modifiable> FromRoots<T>(IEnumerable<T> roots)
            where T : Modifiable
        {
            return DirectedGraph<Modifiable>.Generate(roots.Cast<Modifiable>(), ModifyInspector.FullExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static DirectedGraph<Modifiable> FromRootsIdentifiable<T>(IEnumerable<T> roots)
            where T : Modifiable
        {
            return DirectedGraph<Modifiable>.Generate(roots.Cast<Modifiable>(), ModifyInspector.IdentifiableExplore, ReferenceEqualityComparer<Modifiable>.Default);
        }

        public static Dictionary<ModifiableEntity, string> IntegrityDictionary(DirectedGraph<Modifiable> graph)
        {
            var result = graph.OfType<ModifiableEntity>().Select(m => new { m, Error = m.IntegrityCheck() })
                .Where(p => p.Error.HasText()).ToDictionary(a => a.m, a => a.Error);

            return result;
        }

        public static string IdentifiableIntegrityCheck(DirectedGraph<Modifiable> graph)
        {
            return graph.OfType<ModifiableEntity>().Select(m => m.IntegrityCheck()).Where(e => e.HasText()).ToString("\r\n");
        }

        public static string Integrity(DirectedGraph<Modifiable> graph)
        {
            if (graph.OfType<IdentifiableEntity>().Any() && !graph.OfType<ModifiableEntity>().Any())
            {
                var problems = (from m in graph.OfType<IdentifiableEntity>()
                                group m by new { Type = m.GetType(), Id = (m as IdentifiableEntity).TryCS(ident => (long?)ident.IdOrNull) ?? -m.temporalId } into g
                                where g.Count() > 1 && g.Count(m => m.SelfModified) > 0
                                select g).ToList();

                if (problems.Count > 0)
                    return "CLONE ATTACK!\r\n\r\n" + problems.ToString(p => "{0} different instances of the same entity ({1}) have been found:\r\n {2}".Formato(
                        p.Count(),
                        p.Key,
                        p.ToString(m => "  {0}{1}".Formato(m.SelfModified ? "[SelfModified] " : "", m), "\r\n")), "\r\n\r\n");

                return (from ident in graph.OfType<IdentifiableEntity>()
                        let error = ident.IdentifiableIntegrityCheck()
                        where error.HasText()
                        select new { ident, error }).ToString(p => "{0}:\r\n{1}".Formato(p.ident.BaseToString(), p.error.Indent(2)), "\r\n");
            }
            else
            {
                return (from me in graph.OfType<ModifiableEntity>()
                        select me.IntegrityCheck() into error
                        where error.HasText()
                        select error).ToString("\r\n"); 
            }
        }

        public static DirectedGraph<Modifiable> PreSaving(Func<DirectedGraph<Modifiable>> recreate)
        {
            return ModifyGraph(recreate(), (Modifiable m, ref bool graphModified) => m.PreSaving(ref graphModified), recreate);
        }

        public delegate void ModifyEntityEventHandler(Modifiable m, ref bool graphModified);

        public static DirectedGraph<Modifiable> ModifyGraph(DirectedGraph<Modifiable> graph, ModifyEntityEventHandler modifier, Func<DirectedGraph<Modifiable>> recreate)
        {
            bool graphModified = false; 
            foreach (var m in graph)
            {
                modifier(m, ref graphModified);
            }

            if(!graphModified)
                return graph; //common case

            do
            {
                var newGraph = recreate();
                graphModified = false;
                foreach (var m in newGraph.Except(graph))
                {
                    modifier(m, ref graphModified);
                }

                graph = newGraph;
            } while (graphModified);

            return graph; 
        }


        static string[] colors = 
        {
             "aquamarine1",  "aquamarine4", "blue", "blueviolet",
             "brown4", "burlywood", "cadetblue1", "cadetblue",
             "chartreuse", "chocolate", "cornflowerblue",
             "darkgoldenrod", "darkolivegreen3", "darkorchid", "darkseagreen",
             "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "forestgreen"
        };


        public static string SuperGraphviz(this DirectedGraph<Modifiable> modifiables)
        {
            Func<Type, string> color = t => colors[Math.Abs(t.FullName.GetHashCode()) % colors.Length];

            var listNodes = modifiables.Nodes.Select(n => new
            {
                Node = n,

                Fillcolor =  n is Lite? "white": color(n.GetType()),
                Color =
                    n is Lite ? color(Lite.Extract(n.GetType())) :
                    (n.SelfModified ? "red" : n.Modified == true ? "red4" :"black"),

                Shape = n is Lite ? "ellipse" :
                        n is IdentifiableEntity ? "ellipse" :
                        n is EmbeddedEntity ? "box" :
                        Reflector.IsMList(n.GetType()) ? "hexagon" : "plaintext",
                Style = n is Entity ? ", style=\"diagonals,filled,bold\"" : 
                        n is Lite? "style=\"solid,bold\"": "",

                Label = n.ToString().Etc(30, "..").RemoveDiacritics()

            }).ToList();

            string nodes = listNodes.ToString(t => "    {0} [color={1}, fillcolor={2} shape={3}{4}, label=\"{5}\"]".Formato(modifiables.Comparer.GetHashCode(t.Node), t.Color, t.Fillcolor, t.Shape, t.Style, t.Label), "\r\n");

            string arrows = modifiables.Edges.ToString(e => "    {0} -> {1}".Formato(modifiables.Comparer.GetHashCode(e.From), modifiables.Comparer.GetHashCode(e.To)), "\r\n");

            return "digraph \"Grafo\"\r\n{{\r\n    node [ style = \"filled,bold\"]\r\n\r\n{0}\r\n\r\n{1}\r\n}}".Formato(nodes, arrows);
        }

        public static DirectedGraph<IdentifiableEntity> ColapseIdentifiables(DirectedGraph<Modifiable> modifiables)
        {
            DirectedGraph<IdentifiableEntity> result = new DirectedGraph<IdentifiableEntity>();
            foreach (var item in modifiables.OfType<IdentifiableEntity>())
            {
                var toColapse = modifiables.IndirectlyRelatedTo(item, i => !(i is IdentifiableEntity));
                var toColapseFriends = toColapse.SelectMany(i => modifiables.RelatedTo(i).OfType<IdentifiableEntity>());
                result.Add(item, toColapseFriends);
                result.Add(item, modifiables.RelatedTo(item).OfType<IdentifiableEntity>());
            }
            return result;
        }

        public static XDocument EntityDGML(this DirectedGraph<Modifiable> graph)
        {
            return graph.ToDGML(n =>
                n is IdentifiableEntity ? GetAttributes((IdentifiableEntity)n): 
                n is Lite ? GetAttributes((Lite)n):
                n is EmbeddedEntity ? GetAttributes((EmbeddedEntity)n):
                n.GetType().IsMList() ? GetAttributes((IList)n) : 
                new []
                {
                    new XAttribute("Label", n.ToString() ?? "[null]"),
                    new XAttribute("TypeName", n.GetType().TypeName()), 
                    new XAttribute("Background", ColorExtensions.ToHtmlColor(n.GetType().FullName.GetHashCode()))
                });
        }

        private static XAttribute[] GetAttributes(IdentifiableEntity ie)
        {
            return new[]
            {
               new XAttribute("Label", (ie.ToString() ?? "[null]")  + Modified(ie)),
               new XAttribute("TypeName", ie.GetType().TypeName()), 
               new XAttribute("Background", ColorExtensions.ToHtmlColor(ie.GetType().FullName.GetHashCode())),
               new XAttribute("Description", ie.IdOrNull.TryToString() ?? "New")
            };
        }

        private static string Modified(Modifiable ie)
        {
            string str = ",".Combine(ie.SelfModified ? "SelfModified" : null,
                                               ie.Modified == true ? "Modified" :
                                               ie.Modified == false ? "Not-Modified" : null);

            if (str.HasText())
                return "({0})".Formato(str);

            return null;
        }

        private static XAttribute[] GetAttributes(Lite lite)
        {
            return new[]
            {
               new XAttribute("Label", (lite.ToString() ?? "[null]") + Modified(lite)),
               new XAttribute("TypeName", lite.GetType().TypeName()), 
               new XAttribute("Stroke", ColorExtensions.ToHtmlColor(Lite.Extract(lite.GetType()).FullName.GetHashCode())),
               new XAttribute("StrokeThickness", "2"),
               new XAttribute("Background", ColorExtensions.ToHtmlColor(lite.RuntimeType.FullName.GetHashCode()).Replace("#", "#44")),
               new XAttribute("Description", " ".Combine((lite.RuntimeType == Lite.Extract(lite.GetType())? "":  lite.RuntimeType.TypeName() ),   lite.IdOrNull.TryToString() ?? "New"))
            };
        }

        private static XAttribute[] GetAttributes(EmbeddedEntity ee)
        {
            return new[]
            {
               new XAttribute("Label", (ee.ToString() ?? "[null]")+  Modified(ee)),
               new XAttribute("TypeName", ee.GetType().TypeName()), 
               new XAttribute("NodeRadius", 0),
               new XAttribute("Background", ColorExtensions.ToHtmlColor(ee.GetType().FullName.GetHashCode())),
            };
        }

        private static XAttribute[] GetAttributes(IList list)
        {
            return new[]
            {
               new XAttribute("Label", (list.ToString() ?? "[null]") +  Modified((Modifiable)list)),
               new XAttribute("TypeName", list.GetType().TypeName()), 
               new XAttribute("NodeRadius", 2),
               new XAttribute("Background", ColorExtensions.ToHtmlColor(list.GetType().ElementType().FullName.GetHashCode())),
            };
        }
    }
}

{'fraction_non_alphanumeric': 0.12148364242550531, 'fraction_numerical': 0.0029172744321733697, 'mean_word_length': 1.8768732765855414, 'pattern_counts': {'":': 6, '<': 98, '<?xml version=': 0, '>': 144, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3943184', 'n_tokens_mistral': 6625, 'n_tokens_neox': 6187, 'n_words': 1217}