<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Signum.Utilities;
using Signum.Utilities.Reflection;
using System.Text.RegularExpressions;
using Signum.Entities.DynamicQuery;
using System.Reflection;
using System.Globalization;

namespace Signum.Entities.Chart
{
    [Serializable]
    public class ChartScriptParameterEmbedded : EmbeddedEntity
    {
        [NotNullable, SqlDbType(Size = 50)]
        [StringLengthValidator(AllowNulls = false, Min = 3, Max = 50)]
        public string Name { get; set; }

        ChartParameterType type;
        public ChartParameterType Type
        {
            get { return type; }
            set
            {
                if (Set(ref type, value))
                {
                    ValueDefinition = null;
                }
            }
        }

        public int? ColumnIndex { get; set; }

        [NotNullable, SqlDbType(Size = 200)]
        string valueDefinition;
        [StringLengthValidator(AllowNulls = true, Max = 200)]
        public string ValueDefinition
        {
            get { return valueDefinition; }
            set
            {
                if (Set(ref valueDefinition, value))
                {
                    enumValues = null;
                    numberInterval = null;
                }
            }
        }


        protected override string PropertyValidation(PropertyInfo pi)
        {
            if (pi.Name == nameof(ValueDefinition) && ValueDefinition != null)
            {
                switch (Type)
                {
                    case ChartParameterType.Enum: return EnumValueList.TryParse(valueDefinition, out enumValues);
                    case ChartParameterType.Number: return NumberInterval.TryParse(valueDefinition, out numberInterval);
                    case ChartParameterType.String: return null;
                    default: throw new InvalidOperationException();
                }
            }

            return base.PropertyValidation(pi);
        }

        public string DefaultValue(QueryToken token)
        {
            switch (Type)
            {
                case ChartParameterType.Enum: return GetEnumValues().DefaultValue(token);
                case ChartParameterType.Number: return GetNumberInterval().DefaultValue.ToString(CultureInfo.InvariantCulture);
                case ChartParameterType.String: return ValueDefinition;
                default: throw new InvalidOperationException();
            }
        }


        public string Valdidate(string parameter, QueryToken token)
        {
            switch (Type)
            {
                case ChartParameterType.Enum: return GetEnumValues().Validate(parameter, token);
                case ChartParameterType.Number: return GetNumberInterval().Validate(parameter);
                case ChartParameterType.String: return null;
                default: throw new InvalidOperationException();
            }
        }

        [Ignore, NonSerialized]
        EnumValueList enumValues;
        public EnumValueList GetEnumValues()
        {
            if (Type != ChartParameterType.Enum)
                throw new InvalidOperationException("Type is not Enum");

            if (enumValues != null)
                return enumValues;

            lock (this)
            {
                if (enumValues != null)
                    return enumValues;

                string error = EnumValueList.TryParse(valueDefinition, out enumValues);
                if (error.HasText())
                    throw new FormatException(error);
            }

            return enumValues;
        }

        [Ignore, NonSerialized]
        NumberInterval numberInterval;
        public NumberInterval GetNumberInterval()
        {
            if (Type != ChartParameterType.Number)
                throw new InvalidOperationException("Type is not Number");

            if (numberInterval != null)
                return numberInterval;

            lock (this)
            {
                if (numberInterval != null)
                    return numberInterval;

                string error = NumberInterval.TryParse(valueDefinition, out numberInterval);
                if (error.HasText())
                    throw new FormatException(error);
            }

            return numberInterval;
        }


        public class NumberInterval
        {
            public decimal DefaultValue;
            public decimal? MinValue;
            public decimal? MaxValue;

            public static string TryParse(string valueDefinition, out NumberInterval interval)
            {
                interval = null;
                var m = Regex.Match(valueDefinition, @"^\s*(?<def>.+)\s*(\[(?<min>.+)?\s*,\s*(?<max>.+)?\s*\])?\s*$");

                if (!m.Success)
                    return "Invalid number interval, [min?, max?]";

                interval = new NumberInterval();

                if (!ReflectionTools.TryParse<decimal>(m.Groups["def"].Value, CultureInfo.InvariantCulture, out interval.DefaultValue))
                    return "Invalid default value";

                if (!ReflectionTools.TryParse<decimal?>(m.Groups["min"].Value, CultureInfo.InvariantCulture, out interval.MinValue))
                    return "Invalid min value";

                if (!ReflectionTools.TryParse<decimal?>(m.Groups["max"].Value, CultureInfo.InvariantCulture, out interval.MaxValue))
                    return "Invalid max value";

                return null;
            }

            public override string ToString()
            {
                return "{0}[{1},{2}]".FormatWith(DefaultValue, MinValue, MaxValue);
            }

            public string Validate(string parameter)
            {
                if (!decimal.TryParse(parameter, out decimal value))
                    return "{0} is not a valid number".FormatWith(parameter);

                if (MinValue.HasValue && value < MinValue)
                    return "{0} is lesser than the minimum {1}".FormatWith(value, MinValue);

                if (MaxValue.HasValue && MaxValue < value)
                    return "{0} is grater than the maximum {1}".FormatWith(value, MinValue);

                return null;
            }
        }
<commit_msg>fix InvariantCulture in ChartScriptParameter<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Signum.Utilities;
using Signum.Utilities.Reflection;
using System.Text.RegularExpressions;
using Signum.Entities.DynamicQuery;
using System.Reflection;
using System.Globalization;

namespace Signum.Entities.Chart
{
    [Serializable]
    public class ChartScriptParameterEmbedded : EmbeddedEntity
    {
        [NotNullable, SqlDbType(Size = 50)]
        [StringLengthValidator(AllowNulls = false, Min = 3, Max = 50)]
        public string Name { get; set; }

        ChartParameterType type;
        public ChartParameterType Type
        {
            get { return type; }
            set
            {
                if (Set(ref type, value))
                {
                    ValueDefinition = null;
                }
            }
        }

        public int? ColumnIndex { get; set; }

        [NotNullable, SqlDbType(Size = 200)]
        string valueDefinition;
        [StringLengthValidator(AllowNulls = true, Max = 200)]
        public string ValueDefinition
        {
            get { return valueDefinition; }
            set
            {
                if (Set(ref valueDefinition, value))
                {
                    enumValues = null;
                    numberInterval = null;
                }
            }
        }


        protected override string PropertyValidation(PropertyInfo pi)
        {
            if (pi.Name == nameof(ValueDefinition) && ValueDefinition != null)
            {
                switch (Type)
                {
                    case ChartParameterType.Enum: return EnumValueList.TryParse(valueDefinition, out enumValues);
                    case ChartParameterType.Number: return NumberInterval.TryParse(valueDefinition, out numberInterval);
                    case ChartParameterType.String: return null;
                    default: throw new InvalidOperationException();
                }
            }

            return base.PropertyValidation(pi);
        }

        public string DefaultValue(QueryToken token)
        {
            switch (Type)
            {
                case ChartParameterType.Enum: return GetEnumValues().DefaultValue(token);
                case ChartParameterType.Number: return GetNumberInterval().DefaultValue.ToString(CultureInfo.InvariantCulture);
                case ChartParameterType.String: return ValueDefinition;
                default: throw new InvalidOperationException();
            }
        }


        public string Valdidate(string parameter, QueryToken token)
        {
            switch (Type)
            {
                case ChartParameterType.Enum: return GetEnumValues().Validate(parameter, token);
                case ChartParameterType.Number: return GetNumberInterval().Validate(parameter);
                case ChartParameterType.String: return null;
                default: throw new InvalidOperationException();
            }
        }

        [Ignore, NonSerialized]
        EnumValueList enumValues;
        public EnumValueList GetEnumValues()
        {
            if (Type != ChartParameterType.Enum)
                throw new InvalidOperationException("Type is not Enum");

            if (enumValues != null)
                return enumValues;

            lock (this)
            {
                if (enumValues != null)
                    return enumValues;

                string error = EnumValueList.TryParse(valueDefinition, out enumValues);
                if (error.HasText())
                    throw new FormatException(error);
            }

            return enumValues;
        }

        [Ignore, NonSerialized]
        NumberInterval numberInterval;
        public NumberInterval GetNumberInterval()
        {
            if (Type != ChartParameterType.Number)
                throw new InvalidOperationException("Type is not Number");

            if (numberInterval != null)
                return numberInterval;

            lock (this)
            {
                if (numberInterval != null)
                    return numberInterval;

                string error = NumberInterval.TryParse(valueDefinition, out numberInterval);
                if (error.HasText())
                    throw new FormatException(error);
            }

            return numberInterval;
        }


        public class NumberInterval
        {
            public decimal DefaultValue;
            public decimal? MinValue;
            public decimal? MaxValue;

            public static string TryParse(string valueDefinition, out NumberInterval interval)
            {
                interval = null;
                var m = Regex.Match(valueDefinition, @"^\s*(?<def>.+)\s*(\[(?<min>.+)?\s*,\s*(?<max>.+)?\s*\])?\s*$");

                if (!m.Success)
                    return "Invalid number interval, [min?, max?]";

                interval = new NumberInterval();

                if (!ReflectionTools.TryParse(m.Groups["def"].Value, CultureInfo.InvariantCulture, out interval.DefaultValue))
                    return "Invalid default value";

                if (!ReflectionTools.TryParse(m.Groups["min"].Value, CultureInfo.InvariantCulture, out interval.MinValue))
                    return "Invalid min value";

                if (!ReflectionTools.TryParse(m.Groups["max"].Value, CultureInfo.InvariantCulture, out interval.MaxValue))
                    return "Invalid max value";

                return null;
            }

            public override string ToString()
            {
                return "{0}[{1},{2}]".FormatWith(DefaultValue, MinValue, MaxValue);
            }

            public string Validate(string parameter)
            {
                if (!decimal.TryParse(parameter, NumberStyles.Float, CultureInfo.InvariantCulture,  out decimal value))
                    return "{0} is not a valid number".FormatWith(parameter);

                if (MinValue.HasValue && value < MinValue)
                    return "{0} is lesser than the minimum {1}".FormatWith(value, MinValue);

                if (MaxValue.HasValue && MaxValue < value)
                    return "{0} is grater than the maximum {1}".FormatWith(value, MinValue);

                return null;
            }
        }

{'fraction_non_alphanumeric': 0.08519365780547448, 'fraction_numerical': 0.002997554626488917, 'mean_word_length': 1.6786393407986477, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 12, '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': '1787909', 'n_tokens_mistral': 3026, 'n_tokens_neox': 2830, 'n_words': 737}