<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Serenity.Reflection
{
    public class EditorTypeInfo
    {
        public Dictionary<string, EditorOptionInfo> Options { get; set; }
    }

    public class EditorOptionInfo
    {
        public string Name { get; set; }
        public string Type { get; set; }
    }

    public class EditorTypeGenerator
    {
        public EditorTypeGenerator()
        {
            EditorTypes = new Dictionary<string, EditorTypeInfo>();

            UsingNamespaces = new HashSet<string>
            {
                "Serenity",
                "Serenity.ComponentModel",
                "System",
                "System.Collections",
                "System.Collections.Generic",
                "System.ComponentModel"
            };

            RootNamespaces = new HashSet<string>
            {
                "Serenity"
            };
        }

        public Func<string, string> GetTypeName { get; set; }
        public HashSet<string> UsingNamespaces { get; private set; }
        public Dictionary<string, EditorTypeInfo> EditorTypes { get; private set; }
        public HashSet<string> RootNamespaces { get; private set; }

        private string DoGetTypeName(string typeName)
        {
            if (GetTypeName != null)
                return GetTypeName(typeName);

            var parts = typeName.Split(new char[] { '.' });

            return parts[parts.Length - 1] + "Attribute";
        }

        private string DoGetNamespace(string typeName)
        {
            var parts = typeName.Split(new char[] { '.' });
            return String.Join(".", parts.Take(parts.Length - 1).ToArray());
        }

        public string GenerateCode()
        {
            var codeByType = new Dictionary<string, string>();
            var sb = new StringBuilder();
            var cw = new Serenity.Reflection.CodeWriter(sb, 4);

            foreach (var key in EditorTypes.Keys)
            {
                var ns = DoGetNamespace(key);

                var editorKey = key;
                var editorInfo = EditorTypes[key];
                foreach (var rn in RootNamespaces)
                {
                    if (key.StartsWith(rn + "."))
                    {
                        editorKey = editorKey.Substring(rn.Length + 1);
                        break;
                    }
                }

                if (editorKey.EndsWith("Editor"))
                    editorKey = editorKey.Substring(0, editorKey.Length - "Editor".Length);

                sb.Clear();
                cw.Indented("public partial class ");
                var type = DoGetTypeName(key);
                sb.Append(type);
                sb.AppendLine(" : CustomEditorAttribute");
                cw.InBrace(delegate
                {
                    cw.Indented("public ");
                    sb.Append(type);
                    sb.AppendLine("()");
                    cw.Indented("    : base(\"");
                    sb.Append(editorKey);
                    sb.AppendLine("\")");
                    cw.IndentedLine("{");
                    cw.IndentedLine("}");
                    var opt = editorInfo.Options.Keys.ToList();
                    opt.Sort();

                    foreach (var item in opt)
                    {
                        var option = editorInfo.Options[item];
                        var typeName = option.Type;
                        var nullablePrefix = "System.Nullable`1";
                        bool nullable = option.Type.StartsWith(nullablePrefix);
                        if (nullable)
                            typeName = typeName.Substring(nullablePrefix.Length + 1, typeName.Length - nullablePrefix.Length - 2);

                        var systemType = Type.GetType(typeName);
                        if (systemType == null)
                            typeName = "object";
                        else if (typeName.StartsWith("System."))
                            typeName = typeName.Substring(7);

                        sb.AppendLine();
                        cw.Indented("public ");
                        sb.Append(typeName);
                        if (nullable)
                            sb.Append("?");
                        sb.Append(" ");
                        sb.AppendLine(item);
                        cw.InBrace(() =>
                        {
                            string propName = item.Substring(0, 1).ToLowerInvariant() + item.Substring(1);
                            if (item == "ID")
                                propName = "id";
                            cw.Indented("get { return GetOption<");
                            sb.Append(typeName);
                            if (nullable)
                                sb.Append("?");
                            sb.Append(">(\"");
                            sb.Append(propName);
                            sb.AppendLine("\"); }");
                            cw.Indented("set { SetOption(\"");
                            sb.Append(propName);
                            sb.AppendLine("\", value); }");
                        });<commit_msg>Attribute name argument nullable problem fix<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Serenity.Reflection
{
    public class EditorTypeInfo
    {
        public Dictionary<string, EditorOptionInfo> Options { get; set; }
    }

    public class EditorOptionInfo
    {
        public string Name { get; set; }
        public string Type { get; set; }
    }

    public class EditorTypeGenerator
    {
        public EditorTypeGenerator()
        {
            EditorTypes = new Dictionary<string, EditorTypeInfo>();

            UsingNamespaces = new HashSet<string>
            {
                "Serenity",
                "Serenity.ComponentModel",
                "System",
                "System.Collections",
                "System.Collections.Generic",
                "System.ComponentModel"
            };

            RootNamespaces = new HashSet<string>
            {
                "Serenity"
            };
        }

        public Func<string, string> GetTypeName { get; set; }
        public HashSet<string> UsingNamespaces { get; private set; }
        public Dictionary<string, EditorTypeInfo> EditorTypes { get; private set; }
        public HashSet<string> RootNamespaces { get; private set; }

        private string DoGetTypeName(string typeName)
        {
            if (GetTypeName != null)
                return GetTypeName(typeName);

            var parts = typeName.Split(new char[] { '.' });

            return parts[parts.Length - 1] + "Attribute";
        }

        private string DoGetNamespace(string typeName)
        {
            var parts = typeName.Split(new char[] { '.' });
            return String.Join(".", parts.Take(parts.Length - 1).ToArray());
        }

        public string GenerateCode()
        {
            var codeByType = new Dictionary<string, string>();
            var sb = new StringBuilder();
            var cw = new Serenity.Reflection.CodeWriter(sb, 4);

            foreach (var key in EditorTypes.Keys)
            {
                var ns = DoGetNamespace(key);

                var editorKey = key;
                var editorInfo = EditorTypes[key];
                foreach (var rn in RootNamespaces)
                {
                    if (key.StartsWith(rn + "."))
                    {
                        editorKey = editorKey.Substring(rn.Length + 1);
                        break;
                    }
                }

                if (editorKey.EndsWith("Editor"))
                    editorKey = editorKey.Substring(0, editorKey.Length - "Editor".Length);

                sb.Clear();
                cw.Indented("public partial class ");
                var type = DoGetTypeName(key);
                sb.Append(type);
                sb.AppendLine(" : CustomEditorAttribute");
                cw.InBrace(delegate
                {
                    cw.Indented("public ");
                    sb.Append(type);
                    sb.AppendLine("()");
                    cw.Indented("    : base(\"");
                    sb.Append(editorKey);
                    sb.AppendLine("\")");
                    cw.IndentedLine("{");
                    cw.IndentedLine("}");
                    var opt = editorInfo.Options.Keys.ToList();
                    opt.Sort();

                    foreach (var item in opt)
                    {
                        var option = editorInfo.Options[item];
                        var typeName = option.Type;
                        var nullablePrefix = "System.Nullable`1";
                        bool nullable = option.Type.StartsWith(nullablePrefix);
                        if (nullable)
                            typeName = typeName.Substring(nullablePrefix.Length + 1, typeName.Length - nullablePrefix.Length - 2);

                        var systemType = Type.GetType(typeName);
                        if (systemType == null)
                            typeName = "object";
                        else if (typeName.StartsWith("System."))
                            typeName = typeName.Substring(7);

                        sb.AppendLine();
                        cw.Indented("public ");
                        sb.Append(typeName);
                        //if (nullable) //Attribute name argument nullable problem
                        //    sb.Append("?");
                        sb.Append(" ");
                        sb.AppendLine(item);
                        cw.InBrace(() =>
                        {
                            string propName = item.Substring(0, 1).ToLowerInvariant() + item.Substring(1);
                            if (item == "ID")
                                propName = "id";
                            cw.Indented("get { return GetOption<");
                            sb.Append(typeName);
                            //if (nullable) //Attribute name argument nullable problem
                            //    sb.Append("?");
                            sb.Append(">(\"");
                            sb.Append(propName);
                            sb.AppendLine("\"); }");
                            cw.Indented("set { SetOption(\"");
                            sb.Append(propName);
                            sb.AppendLine("\", value); }");
                        });
{'fraction_non_alphanumeric': 0.1036279245997916, 'fraction_numerical': 0.002273373117362887, 'mean_word_length': 1.1415821501014198, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, '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': '4938745', 'n_tokens_mistral': 2558, 'n_tokens_neox': 2419, 'n_words': 519}