using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
namespace FastGithub.Configuration
{
    /// 
    /// 配置值绑定器
    /// 
    static class ValueBinder
    {
        private static readonly Dictionary binders = new();
        /// 
        /// 绑定转换器到指定类型
        /// 
        /// 
        /// 
        /// 
        public static void Bind(Func reader, Func writer)
        {
            binders[typeof(T)] = new Binder(reader, writer);
            var converterType = typeof(TypeConverter<>).MakeGenericType(typeof(T));
            if (TypeDescriptor.GetConverter(typeof(T)).GetType() != converterType)
            {
                TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(converterType));
            }
        }
        private abstract class Binder
        {
            public abstract object? Read(string value);
            public abstract string? Write(object? value);
        }
        private class Binder : Binder
        {
            private readonly Func reader;
            private readonly Func writer;
            public Binder(Func reader, Func writer)
            {
                this.reader = reader;
                this.writer = writer;
            }
            public override object? Read(string value)
            {
                return this.reader(value);
            }
            public override string? Write(object? value)
            {
                return this.writer((T?)value);
            }
        }
        private class TypeConverter : TypeConverter
        {
            public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
            {
                return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
            }
            public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
            {
                if (value is string stringVal)
                {
                    if (stringVal.Equals(string.Empty))
                    {
                        return default(T);
                    }
                    else if (binders.TryGetValue(typeof(T), out var binder))
                    {
                        return binder.Read(stringVal);
                    }
                }
                return base.ConvertFrom(context, culture, value);
            }
            public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
            {
                return destinationType == typeof(T) && binders.TryGetValue(destinationType, out var binder)
                    ? binder.Write(value)
                    : base.ConvertTo(context, culture, value, destinationType);
            }
        }
    }
}