// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.Globalization;

namespace System.ComponentModel.Design.Serialization
{
    public abstract partial class CodeDomDesignerLoader
    {
        private class ModifierConverter : TypeConverter
        {
            /// <summary>
            ///  <para>Gets a value indicating whether this converter can
            ///  convert an object in the given source type to the native type of the converter
            ///  using the context.</para>
            /// </summary>
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
                => GetConverter(context).CanConvertFrom(context, sourceType);

            /// <summary>
            ///  <para>Gets a value indicating whether this converter can
            ///  convert an object to the given destination type using the context.</para>
            /// </summary>
            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
                => GetConverter(context).CanConvertTo(context, destinationType);

            /// <summary>
            ///  <para>Converts the given object to the converter's native type.</para>
            /// </summary>
            public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
                => GetConverter(context).ConvertFrom(context, culture, value);

            /// <summary>
            ///  <para>Converts the given value object to
            ///  the specified destination type using the specified context and arguments.</para>
            /// </summary>
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
                => GetConverter(context).ConvertTo(context, culture, value, destinationType);

            /// <summary>
            /// <para>Re-creates an <see cref='object'/> given a set of property values for the
            ///  object.</para>
            /// </summary>
            public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
                => GetConverter(context).CreateInstance(context, propertyValues);

            /// <summary>
            ///  Returns the type converter for the member attributes enum.  We search the context
            ///  for a code dom provider that can provide us more information.
            /// </summary>
            private TypeConverter GetConverter(ITypeDescriptorContext context)
            {
                TypeConverter modifierConverter = null;

                if (context != null)
                {
                    CodeDomProvider provider = (CodeDomProvider)context.GetService(typeof(CodeDomProvider));

                    if (provider != null)
                    {
                        modifierConverter = provider.GetConverter(typeof(MemberAttributes));
                    }
                }

                if (modifierConverter is null)
                {
                    modifierConverter = TypeDescriptor.GetConverter(typeof(MemberAttributes));
                }

                return modifierConverter;
            }

            /// <summary>
            ///  <para>Gets a value indicating whether changing a value on this object requires a
            ///  call to <see cref='TypeConverter.CreateInstance(IDictionary)'/> to create a new value,
            ///  using the specified context.</para>
            /// </summary>
            public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
                => GetConverter(context).GetCreateInstanceSupported(context);

            /// <summary>
            ///  <para>Gets a collection of properties for
            ///  the type of array specified by the value parameter using the specified context and
            ///  attributes.</para>
            /// </summary>
            public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
                => GetConverter(context).GetProperties(context, value, attributes);

            /// <summary>
            ///  <para>Gets a value indicating
            ///  whether this object supports properties using the
            ///  specified context.</para>
            /// </summary>
            public override bool GetPropertiesSupported(ITypeDescriptorContext context)
                => GetConverter(context).GetPropertiesSupported(context);

            /// <summary>
            ///  <para>Gets a collection of standard values for the data type this type converter is
            ///  designed for.</para>
            /// </summary>
            public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
            {
                // We restrict the set of standard values to those within the access mask.
                StandardValuesCollection values = GetConverter(context).GetStandardValues(context);

                if (values != null && values.Count > 0)
                {
                    bool needMassage = false;

                    foreach (MemberAttributes value in values)
                    {
                        if ((value & MemberAttributes.AccessMask) == 0)
                        {
                            needMassage = true;
                            break;
                        }
                    }

                    if (needMassage)
                    {
                        ArrayList list = new ArrayList(values.Count);

                        foreach (MemberAttributes value in values)
                        {
                            if ((value & MemberAttributes.AccessMask) != 0 && value != MemberAttributes.AccessMask)
                            {
                                list.Add(value);
                            }
                        }

                        values = new StandardValuesCollection(list);
                    }
                }

                return values;
            }

            /// <summary>
            ///  <para>Gets a value indicating whether the collection of standard values returned from
            ///  <see cref='TypeConverter.GetStandardValues()'/> is an exclusive
            ///  list of possible values, using the specified context.</para>
            /// </summary>
            public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
                => GetConverter(context).GetStandardValuesExclusive(context);

            /// <summary>
            ///  <para>Gets a value indicating
            ///  whether this object
            ///  supports a standard set of values that can be picked
            ///  from a list using the specified context.</para>
            /// </summary>
            public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
                => GetConverter(context).GetStandardValuesSupported(context);

            /// <summary>
            ///  <para>Gets
            ///  a value indicating whether the given value object is valid for this type.</para>
            /// </summary>
            public override bool IsValid(ITypeDescriptorContext context, object value)
                => GetConverter(context).IsValid(context, value);
        }
    }
}


