// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;

namespace System.Windows.Forms.Design;

internal class DataGridViewAddColumnDialog : Form
{
    private RadioButton _dataBoundColumnRadioButton;
    private Label _columnInDataSourceLabel;

    private ListBox _dataColumns;

    private RadioButton _unboundColumnRadioButton;
    private TextBox _nameTextBox;

    private ComboBox _columnTypesCombo;

    private TextBox _headerTextBox;
    private Label _nameLabel;

    private Label _typeLabel;

    private Label _headerTextLabel;
    private CheckBox _visibleCheckBox;

    private CheckBox _readOnlyCheckBox;

    private CheckBox _frozenCheckBox;
    private Button _addButton;

    private Button _cancelButton;

    private readonly DataGridViewColumnCollection _dataGridViewColumns;
    private readonly DataGridView _liveDataGridView;
    private int _insertAtPosition = -1;
    private int _initialDataGridViewColumnsCount = -1;
    private bool _persistChangesToDesigner;

    private TableLayoutPanel _okCancelTableLayoutPanel;
    private TableLayoutPanel _checkBoxesTableLayoutPanel;
    private TableLayoutPanel _overarchingTableLayoutPanel;

    public DataGridViewAddColumnDialog(DataGridViewColumnCollection dataGridViewColumns, DataGridView liveDataGridView)
    {
        _dataGridViewColumns = dataGridViewColumns;
        _liveDataGridView = liveDataGridView;

        // PERF: set the Dialog Font before InitializeComponent.
        Font uiFont = DefaultFont;
        if (_liveDataGridView.Site.TryGetService(out IUIService? uiService))
        {
            uiFont = (Font)uiService.Styles["DialogFont"]!;
        }

        Font = uiFont;

        //
        // Required for Windows Form Designer support
        //
        InitializeComponent();

        // put this code in the constructor because we want to keep the dataBoundColumnRadioButton.Checked state
        // when the user closes and reopens the add column dialog
        EnableDataBoundSection();
    }

    /// <summary>
    ///  consolidate all the information from the dialog into a data grid view column
    ///  and insert it in the data grid view column collection
    /// </summary>
    private void AddColumn()
    {
        ComboBoxItem? comboBoxItem = (ComboBoxItem)_columnTypesCombo.SelectedItem!;
        Type columnType = comboBoxItem.ColumnType;

        DataGridViewColumn column = (DataGridViewColumn)Activator.CreateInstance(columnType)!;

        // if we want to insert a column before a frozen column then make sure that we insert a frozen column
        bool forceColumnFrozen = _dataGridViewColumns.Count > _insertAtPosition && _dataGridViewColumns[_insertAtPosition].Frozen;

        column.Frozen = forceColumnFrozen;

        // if we don't persist changes to the designer then we want to add the columns before
        // setting the Frozen bit
        if (!_persistChangesToDesigner)
        {
            // set the header text because the DataGridViewColumnCollection needs it to compute
            // its listbox'x HorizontalOffset
            column.HeaderText = _headerTextBox.Text;
            column.Name = _nameTextBox.Text;
            column.DisplayIndex = -1;
            _dataGridViewColumns.Insert(_insertAtPosition, column);
            _insertAtPosition++;
        }

        // if we persist changes directly to the designer then:
        // 1. set the column property values
        // 2. Add the new column
        // 3. site the column

        // 1. set the property values in the column
        column.HeaderText = _headerTextBox.Text;
        column.Name = _nameTextBox.Text;
        column.Visible = _visibleCheckBox.Checked;
        column.Frozen = _frozenCheckBox.Checked || forceColumnFrozen;
        column.ReadOnly = _readOnlyCheckBox.Checked;

        if (_dataBoundColumnRadioButton.Checked && _dataColumns.SelectedIndex > -1)
        {
            column.DataPropertyName = ((ListBoxItem)_dataColumns.SelectedItem!).PropertyName;
        }

        if (_persistChangesToDesigner)
        {
            try
            {
                // insert the column before siting the column.
                // if DataGridView throws an exception then the designer does not end up w/ a column that is not in any data grid view.
                column.DisplayIndex = -1;
                _dataGridViewColumns.Insert(_insertAtPosition, column);
                _insertAtPosition++;
                // site the column
                _liveDataGridView.Site?.Container?.Add(column, column.Name);
            }
            catch (InvalidOperationException ex)
            {
                IUIService? uiService = _liveDataGridView.Site?.GetService<IUIService>();
                DataGridViewDesigner.ShowErrorDialog(uiService, ex, _liveDataGridView);
                return;
            }
        }

        // Set the UserAddedColumn property to true.
        PropertyDescriptorCollection props = TypeDescriptor.GetProperties(column);
        PropertyDescriptor? pd = props["UserAddedColumn"];
        pd?.SetValue(column, true);

        // pick a new Column name
        _nameTextBox.Text = _headerTextBox.Text = AssignName();
        _nameTextBox.Focus();
    }

    private string AssignName()
    {
        int colId = 1;
        // string columnName = (SR.DataGridView_ColumnName, colId.ToString());
        string columnName;

        IDesignerHost? host = _liveDataGridView.Site?.GetService<IDesignerHost>();
        IContainer? container = host?.Container;

        do
        {
            columnName = $"Column{colId++}";
        }
        while (!ValidName(columnName,
                            _dataGridViewColumns,
                            container,
                            nameCreationService: null,
                            _liveDataGridView.Columns,
                            !_persistChangesToDesigner));

        return columnName;
    }

    /// <summary>
    ///  Clean up any resources being used.
    /// </summary>
    protected override void Dispose(bool disposing) => base.Dispose(disposing);

    private void EnableDataBoundSection()
    {
        bool dataGridViewIsDataBound = _dataColumns.Items.Count > 0;
        if (dataGridViewIsDataBound)
        {
            _dataBoundColumnRadioButton.Enabled = true;
            _dataBoundColumnRadioButton.Checked = true;
            _dataBoundColumnRadioButton.Focus();
        }
        else
        {
            _dataBoundColumnRadioButton.Enabled = false;
            _unboundColumnRadioButton.Checked = true;
            _nameTextBox.Focus();
        }

        _headerTextBox.Text = _nameTextBox.Text = AssignName();
    }

    /// <summary>
    ///  public because the EditColumns dialog wants to use it as well.
    /// </summary>
    /// <param name="typeResolutionService"></param>
    /// <param name="type"></param>
    /// <returns></returns>
    public static ComponentDesigner? GetComponentDesignerForType(ITypeResolutionService? typeResolutionService, Type type)
    {
        ComponentDesigner? compDesigner = null;
        DesignerAttribute? designerAttribute = null;
        AttributeCollection? attributes = TypeDescriptor.GetAttributes(type);
        for (int i = 0; i < attributes.Count; i++)
        {
            if (attributes[i] is DesignerAttribute attribute)
            {
                Type? daType = Type.GetType(attribute.DesignerBaseTypeName);
                if (daType == typeof(IDesigner))
                {
                    designerAttribute = attribute;
                    break;
                }
            }
        }

        if (designerAttribute is not null)
        {
            Type? designerType = typeResolutionService is not null
                ? typeResolutionService.GetType(designerAttribute.DesignerTypeName)
                : Type.GetType(designerAttribute.DesignerTypeName);

            if (designerType is not null && typeof(ComponentDesigner).IsAssignableFrom(designerType))
            {
                compDesigner = Activator.CreateInstance(designerType) as ComponentDesigner;
            }
        }

        return compDesigner;
    }

    #region Windows Form Designer generated code
    /// <summary>
    ///  Required method for Designer support - do not modify
    ///  the contents of this method with the code editor.
    /// </summary>
    [MemberNotNull(nameof(_dataBoundColumnRadioButton))]
    [MemberNotNull(nameof(_overarchingTableLayoutPanel))]
    [MemberNotNull(nameof(_checkBoxesTableLayoutPanel))]
    [MemberNotNull(nameof(_frozenCheckBox))]
    [MemberNotNull(nameof(_visibleCheckBox))]
    [MemberNotNull(nameof(_readOnlyCheckBox))]
    [MemberNotNull(nameof(_okCancelTableLayoutPanel))]
    [MemberNotNull(nameof(_addButton))]
    [MemberNotNull(nameof(_cancelButton))]
    [MemberNotNull(nameof(_columnInDataSourceLabel))]
    [MemberNotNull(nameof(_dataColumns))]
    [MemberNotNull(nameof(_unboundColumnRadioButton))]
    [MemberNotNull(nameof(_nameLabel))]
    [MemberNotNull(nameof(_nameTextBox))]
    [MemberNotNull(nameof(_typeLabel))]
    [MemberNotNull(nameof(_columnTypesCombo))]
    [MemberNotNull(nameof(_headerTextLabel))]
    [MemberNotNull(nameof(_headerTextBox))]
    private void InitializeComponent()
    {
        ComponentResourceManager resources = new(typeof(DataGridViewAddColumnDialog));
        _dataBoundColumnRadioButton = new RadioButton();
        _overarchingTableLayoutPanel = new TableLayoutPanel();
        _checkBoxesTableLayoutPanel = new TableLayoutPanel();
        _frozenCheckBox = new CheckBox();
        _visibleCheckBox = new CheckBox();
        _readOnlyCheckBox = new CheckBox();
        _okCancelTableLayoutPanel = new TableLayoutPanel();
        _addButton = new Button();
        _cancelButton = new Button();
        _columnInDataSourceLabel = new Label();
        _dataColumns = new ListBox();
        _unboundColumnRadioButton = new RadioButton();
        _nameLabel = new Label();
        _nameTextBox = new TextBox();
        _typeLabel = new Label();
        _columnTypesCombo = new ComboBox();
        _headerTextLabel = new Label();
        _headerTextBox = new TextBox();
        _overarchingTableLayoutPanel.SuspendLayout();
        _checkBoxesTableLayoutPanel.SuspendLayout();
        _okCancelTableLayoutPanel.SuspendLayout();
        SuspendLayout();
        //
        // dataBoundColumnRadioButton
        //
        resources.ApplyResources(_dataBoundColumnRadioButton, "dataBoundColumnRadioButton");
        _dataBoundColumnRadioButton.Checked = true;
        _overarchingTableLayoutPanel.SetColumnSpan(_dataBoundColumnRadioButton, 3);
        _dataBoundColumnRadioButton.Margin = new Padding(0);
        _dataBoundColumnRadioButton.Name = "dataBoundColumnRadioButton";
        _dataBoundColumnRadioButton.CheckedChanged += dataBoundColumnRadioButton_CheckedChanged;
        //
        // overarchingTableLayoutPanel
        //
        resources.ApplyResources(_overarchingTableLayoutPanel, "overarchingTableLayoutPanel");
        _overarchingTableLayoutPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
        _overarchingTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 14F));
        _overarchingTableLayoutPanel.ColumnStyles.Add(new ColumnStyle());
        _overarchingTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 250F));
        _overarchingTableLayoutPanel.Controls.Add(_checkBoxesTableLayoutPanel, 0, 10);
        _overarchingTableLayoutPanel.Controls.Add(_okCancelTableLayoutPanel, 2, 11);
        _overarchingTableLayoutPanel.Controls.Add(_dataBoundColumnRadioButton, 0, 0);
        _overarchingTableLayoutPanel.Controls.Add(_columnInDataSourceLabel, 1, 1);
        _overarchingTableLayoutPanel.Controls.Add(_dataColumns, 1, 2);
        _overarchingTableLayoutPanel.Controls.Add(_unboundColumnRadioButton, 0, 4);
        _overarchingTableLayoutPanel.Controls.Add(_nameLabel, 1, 5);
        _overarchingTableLayoutPanel.Controls.Add(_nameTextBox, 2, 5);
        _overarchingTableLayoutPanel.Controls.Add(_typeLabel, 1, 7);
        _overarchingTableLayoutPanel.Controls.Add(_columnTypesCombo, 2, 7);
        _overarchingTableLayoutPanel.Controls.Add(_headerTextLabel, 1, 9);
        _overarchingTableLayoutPanel.Controls.Add(_headerTextBox, 2, 9);
        _overarchingTableLayoutPanel.Margin = new Padding(12, 12, 12, 13);
        _overarchingTableLayoutPanel.Name = "overarchingTableLayoutPanel";
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 22F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 16F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 91F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 12F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 22F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle());
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 4F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle());
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 4F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle());
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 27F));
        _overarchingTableLayoutPanel.RowStyles.Add(new RowStyle());
        //
        // checkBoxesTableLayoutPanel
        //
        resources.ApplyResources(_checkBoxesTableLayoutPanel, "checkBoxesTableLayoutPanel");
        _checkBoxesTableLayoutPanel.ColumnStyles.Add(new ColumnStyle());
        _checkBoxesTableLayoutPanel.ColumnStyles.Add(new ColumnStyle());
        _checkBoxesTableLayoutPanel.ColumnStyles.Add(new ColumnStyle());
        _checkBoxesTableLayoutPanel.Controls.Add(_frozenCheckBox, 2, 0);
        _checkBoxesTableLayoutPanel.Controls.Add(_visibleCheckBox, 0, 0);
        _checkBoxesTableLayoutPanel.Controls.Add(_readOnlyCheckBox, 1, 0);
        _checkBoxesTableLayoutPanel.Margin = new Padding(0);
        _overarchingTableLayoutPanel.SetColumnSpan(_checkBoxesTableLayoutPanel, 3);
        _checkBoxesTableLayoutPanel.Name = "checkBoxesTableLayoutPanel";
        _checkBoxesTableLayoutPanel.RowStyles.Add(new RowStyle());
        //
        // frozenCheckBox
        //
        resources.ApplyResources(_frozenCheckBox, "frozenCheckBox");
        _frozenCheckBox.Margin = new Padding(0);
        _frozenCheckBox.Name = "frozenCheckBox";
        //
        // visibleCheckBox
        //
        resources.ApplyResources(_visibleCheckBox, "visibleCheckBox");
        _visibleCheckBox.Checked = true;
        _visibleCheckBox.CheckState = CheckState.Checked;
        _visibleCheckBox.Margin = new Padding(0);
        _visibleCheckBox.Name = "visibleCheckBox";
        //
        // readOnlyCheckBox
        //
        resources.ApplyResources(_readOnlyCheckBox, "readOnlyCheckBox");
        _readOnlyCheckBox.Margin = new Padding(0);
        _readOnlyCheckBox.Name = "readOnlyCheckBox";
        //
        // okCancelTableLayoutPanel
        //
        resources.ApplyResources(_okCancelTableLayoutPanel, "okCancelTableLayoutPanel");
        _okCancelTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
        _okCancelTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
        _okCancelTableLayoutPanel.Controls.Add(_addButton, 0, 0);
        _okCancelTableLayoutPanel.Controls.Add(_cancelButton, 1, 0);
        _okCancelTableLayoutPanel.Margin = new Padding(0, 6, 0, 0);
        _okCancelTableLayoutPanel.Name = "okCancelTableLayoutPanel";
        _okCancelTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50F));
        //
        // addButton
        //
        resources.ApplyResources(_addButton, "addButton");
        _addButton.Margin = new Padding(0, 0, 3, 0);
        _addButton.Name = "addButton";
        _addButton.Click += addButton_Click;
        //
        // cancelButton
        //
        resources.ApplyResources(_cancelButton, "cancelButton");
        _cancelButton.Margin = new Padding(3, 0, 0, 0);
        _cancelButton.Name = "cancelButton";
        _cancelButton.Click += cancelButton_Click;
        //
        // columnInDataSourceLabel
        //
        resources.ApplyResources(_columnInDataSourceLabel, "columnInDataSourceLabel");
        _overarchingTableLayoutPanel.SetColumnSpan(_columnInDataSourceLabel, 2);
        _columnInDataSourceLabel.Margin = new Padding(0);
        _columnInDataSourceLabel.Name = "columnInDataSourceLabel";
        //
        // dataColumns
        //
        resources.ApplyResources(_dataColumns, "dataColumns");
        _overarchingTableLayoutPanel.SetColumnSpan(_dataColumns, 2);
        _dataColumns.FormattingEnabled = true;
        _dataColumns.Margin = new Padding(0);
        _dataColumns.Name = "dataColumns";

        _dataColumns.SelectedIndexChanged += dataColumns_SelectedIndexChanged;
        //
        // unboundColumnRadioButton
        //
        resources.ApplyResources(_unboundColumnRadioButton, "unboundColumnRadioButton");
        _overarchingTableLayoutPanel.SetColumnSpan(_unboundColumnRadioButton, 3);
        _unboundColumnRadioButton.Margin = new Padding(0);
        _unboundColumnRadioButton.Name = "unboundColumnRadioButton";
        _unboundColumnRadioButton.CheckedChanged += unboundColumnRadioButton_CheckedChanged;
        //
        // nameLabel
        //
        resources.ApplyResources(_nameLabel, "nameLabel");
        _nameLabel.Margin = new Padding(0);
        _nameLabel.Name = "nameLabel";
        //
        // nameTextBox
        //
        resources.ApplyResources(_nameTextBox, "nameTextBox");
        _nameTextBox.Margin = new Padding(0);
        _nameTextBox.Name = "nameTextBox";
        _nameTextBox.Validating += nameTextBox_Validating;
        //
        // typeLabel
        //
        resources.ApplyResources(_typeLabel, "typeLabel");
        _typeLabel.Margin = new Padding(0);
        _typeLabel.Name = "typeLabel";
        //
        // columnTypesCombo
        //
        resources.ApplyResources(_columnTypesCombo, "columnTypesCombo");
        _columnTypesCombo.DropDownStyle = ComboBoxStyle.DropDownList;
        _columnTypesCombo.FormattingEnabled = true;
        _columnTypesCombo.Margin = new Padding(0);
        _columnTypesCombo.Name = "columnTypesCombo";
        _columnTypesCombo.Sorted = true;
        //
        // headerTextLabel
        //
        resources.ApplyResources(_headerTextLabel, "headerTextLabel");
        _headerTextLabel.Margin = new Padding(0);
        _headerTextLabel.Name = "headerTextLabel";
        //
        // headerTextBox
        //
        resources.ApplyResources(_headerTextBox, "headerTextBox");
        _headerTextBox.Margin = new Padding(0);
        _headerTextBox.Name = "headerTextBox";
        //
        // DataGridViewAddColumnDialog
        //
        resources.ApplyResources(this, "$this");
        AutoScaleMode = AutoScaleMode.Font;
        CancelButton = _cancelButton;
        AutoSizeMode = AutoSizeMode.GrowAndShrink;
        Controls.Add(_overarchingTableLayoutPanel);
        FormBorderStyle = FormBorderStyle.FixedDialog;
        HelpButton = true;
        MaximizeBox = false;
        MinimizeBox = false;
        Name = "DataGridViewAddColumnDialog";
        ShowIcon = false;
        ShowInTaskbar = false;
        HelpButtonClicked += DataGridViewAddColumnDialog_HelpButtonClicked;
        FormClosed += DataGridViewAddColumnDialog_Closed;
        VisibleChanged += DataGridViewAddColumnDialog_VisibleChanged;
        Load += DataGridViewAddColumnDialog_Load;
        HelpRequested += DataGridViewAddColumnDialog_HelpRequested;
        _overarchingTableLayoutPanel.ResumeLayout(false);
        _overarchingTableLayoutPanel.PerformLayout();
        _checkBoxesTableLayoutPanel.ResumeLayout(false);
        _checkBoxesTableLayoutPanel.PerformLayout();
        _okCancelTableLayoutPanel.ResumeLayout(false);
        _okCancelTableLayoutPanel.PerformLayout();
        ResumeLayout(false);
        PerformLayout();
    }
    #endregion

    private void dataBoundColumnRadioButton_CheckedChanged(object? sender, EventArgs e)
    {
        _columnInDataSourceLabel.Enabled = _dataBoundColumnRadioButton.Checked;
        _dataColumns.Enabled = _dataBoundColumnRadioButton.Checked;

        // push the property name into the headerTextBox and into the nameTextBox
        dataColumns_SelectedIndexChanged(null, EventArgs.Empty);
    }

    private void dataColumns_SelectedIndexChanged(object? sender, EventArgs e)
    {
        if (_dataColumns.SelectedItem is null)
        {
            return;
        }

        _headerTextBox.Text = _nameTextBox.Text = ((ListBoxItem)_dataColumns.SelectedItem).PropertyName;

        // pick a default data grid view column type
        // NOTE: this will pick one of our data grid view column types
        SetDefaultDataGridViewColumnType(((ListBoxItem)_dataColumns.SelectedItem).PropertyType);
    }

    private void unboundColumnRadioButton_CheckedChanged(object? sender, EventArgs e)
    {
        if (_unboundColumnRadioButton.Checked)
        {
            _nameTextBox.Text = _headerTextBox.Text = AssignName();
            _nameTextBox.Focus();
        }
    }

    private void DataGridViewAddColumnDialog_Closed(object? sender, EventArgs e)
    {
        if (_persistChangesToDesigner)
        {
            try
            {
                Debug.Assert(_initialDataGridViewColumnsCount != -1, "did you forget to set the initialDataGridViewColumnsCount when you started the dialog?");
                if (!_liveDataGridView.Site.TryGetService(out IComponentChangeService? changeService))
                {
                    return;
                }

                // to get good Undo/Redo we need to bring the data grid view column collection
                // back to its initial state before firing the componentChanging event
                DataGridViewColumn[] cols = new DataGridViewColumn[_liveDataGridView.Columns.Count - _initialDataGridViewColumnsCount];
                for (int i = _initialDataGridViewColumnsCount; i < _liveDataGridView.Columns.Count; i++)
                {
                    cols[i - _initialDataGridViewColumnsCount] = _liveDataGridView.Columns[i];
                }

                for (int i = _initialDataGridViewColumnsCount; i < _liveDataGridView.Columns.Count;)
                {
                    _liveDataGridView.Columns.RemoveAt(_initialDataGridViewColumnsCount);
                }

                // the data grid view column collection is back to its initial state
                // fire the component changing event
                PropertyDescriptor? prop = TypeDescriptor.GetProperties(_liveDataGridView)["Columns"];
                changeService.OnComponentChanging(_liveDataGridView, prop);

                // add back the data grid view columns the user added using the Add Columns dialog
                // But first wipe out the existing display index.
                for (int i = 0; i < cols.Length; i++)
                {
                    cols[i].DisplayIndex = -1;
                }

                _liveDataGridView.Columns.AddRange(cols);

                // fire component changed event
                changeService.OnComponentChanged(_liveDataGridView, prop, null, null);
            }
            catch (InvalidOperationException)
            {
            }
        }
#if DEBUG
        else
        {
            Debug.Assert(_initialDataGridViewColumnsCount == -1, "did you forget to reset the _initialDataGridViewColumnsCount when you started the dialog?");
        }
#endif // DEBUG

        // The DialogResult is OK.
        DialogResult = DialogResult.OK;
    }

    private void DataGridViewAddColumnDialog_HelpButtonClicked(object? sender, CancelEventArgs e)
    {
        DataGridViewAddColumnDialog_HelpRequestHandled();
        e.Cancel = true;
    }

    private void DataGridViewAddColumnDialog_HelpRequested(object? sender, HelpEventArgs e)
    {
        DataGridViewAddColumnDialog_HelpRequestHandled();
        e.Handled = true;
    }

    private void DataGridViewAddColumnDialog_HelpRequestHandled()
    {
        IHelpService? helpService = _liveDataGridView.Site?.GetService<IHelpService>();
        helpService?.ShowHelpFromKeyword("vs.DataGridViewAddColumnDialog");
    }

    private void DataGridViewAddColumnDialog_Load(object? sender, EventArgs e)
    {
        // setup Visible/ReadOnly/Frozen checkboxes
        // localization will change the check boxes text length
        if (_dataBoundColumnRadioButton.Checked)
        {
            _headerTextBox.Text = _nameTextBox.Text = AssignName();
        }
        else
        {
            Debug.Assert(_unboundColumnRadioButton.Checked, "we only have 2 radio buttons");
            string columnName = AssignName();
            _headerTextBox.Text = _nameTextBox.Text = columnName;
        }

        PopulateColumnTypesCombo();

        PopulateDataColumns();

        EnableDataBoundSection();

        _cancelButton.Text = SR.DataGridView_Cancel;
    }

    private void DataGridViewAddColumnDialog_VisibleChanged(object? sender, EventArgs e)
    {
        if (Visible && IsHandleCreated)
        {
            // we loaded the form
            if (_dataBoundColumnRadioButton.Checked)
            {
                Debug.Assert(_dataColumns.Enabled, "dataColumns list box and dataBoundColumnRadioButton should be enabled / disabled in sync");
                _dataColumns.Select();
            }
            else
            {
                Debug.Assert(_unboundColumnRadioButton.Checked, "We only have 2 radio buttons");
                _nameTextBox.Select();
            }
        }
    }

    private void nameTextBox_Validating(object? sender, CancelEventArgs e)
    {
        INameCreationService? nameCreationService = null;
        IContainer? container = null;

        if (_liveDataGridView.Site.TryGetService(out IDesignerHost? host))
        {
            container = host.Container;
            nameCreationService = _liveDataGridView.Site.GetService<INameCreationService>();
        }

        if (!ValidName(
            _nameTextBox.Text,
            _dataGridViewColumns,
            container,
            nameCreationService,
            _liveDataGridView.Columns,
            !_persistChangesToDesigner,
            out string errorString))
        {
            IUIService? uiService = _liveDataGridView.Site?.GetService<IUIService>();
            DataGridViewDesigner.ShowErrorDialog(uiService, errorString, _liveDataGridView);
            e.Cancel = true;
        }
    }

    private void PopulateColumnTypesCombo()
    {
        _columnTypesCombo.Items.Clear();

        if (!_liveDataGridView.Site.TryGetService(out IDesignerHost? host))
        {
            return;
        }

        ITypeDiscoveryService? discoveryService = host.GetService<ITypeDiscoveryService>();

        if (discoveryService is null)
        {
            return;
        }

        ICollection columnTypes = DesignerUtils.FilterGenericTypes(discoveryService.GetTypes(typeof(DataGridViewColumn), excludeGlobalTypes: false));

        foreach (Type type in columnTypes)
        {
            if (type == typeof(DataGridViewColumn))
            {
                continue;
            }

            if (type.IsAbstract)
            {
                continue;
            }

            if (!type.IsPublic && !type.IsNestedPublic)
            {
                continue;
            }

            if (TypeDescriptorHelper.TryGetAttribute(type, out DataGridViewColumnDesignTimeVisibleAttribute? attribute) && !attribute.Visible)
            {
                continue;
            }

            _columnTypesCombo.Items.Add(new ComboBoxItem(type));
        }

        // make the textBoxColumn type the selected type
        _columnTypesCombo.SelectedIndex = TypeToSelectedIndex(typeof(DataGridViewTextBoxColumn));
    }

    private void PopulateDataColumns()
    {
        int selectedIndex = _dataColumns.SelectedIndex;

        _dataColumns.SelectedIndex = -1;
        _dataColumns.Items.Clear();

        if (_liveDataGridView.DataSource is not null)
        {
            CurrencyManager? currencyManager = null;
            try
            {
                currencyManager = BindingContext?[_liveDataGridView.DataSource, _liveDataGridView.DataMember] as CurrencyManager;
            }
            catch (ArgumentException)
            {
            }

            PropertyDescriptorCollection? propertyDescriptorCollection = currencyManager?.GetItemProperties();

            if (propertyDescriptorCollection is not null)
            {
                for (int i = 0; i < propertyDescriptorCollection.Count; i++)
                {
                    PropertyDescriptor propertyDescriptor = propertyDescriptorCollection[i];
                    if (typeof(IList<object>).IsAssignableFrom(propertyDescriptor.PropertyType))
                    {
                        // we have an IList. It could be a byte[] in which case we want to generate an Image column
                        TypeConverter imageTypeConverter = TypeDescriptor.GetConverter(typeof(Image));
                        if (!imageTypeConverter.CanConvertFrom(propertyDescriptor.PropertyType))
                        {
                            continue;
                        }
                    }

                    _dataColumns.Items.Add(new ListBoxItem(propertyDescriptor.PropertyType, propertyDescriptor.Name));
                }
            }
        }

        _dataColumns.SelectedIndex = selectedIndex != -1 && selectedIndex < _dataColumns.Items.Count
            ? selectedIndex
            : _dataColumns.Items.Count > 0 ? 0 : -1;
    }

    private void addButton_Click(object? sender, EventArgs e)
    {
        _cancelButton.Text = (SR.DataGridView_Close);

        // AddColumn takes all the information from this dialog, makes a DataGridViewColumn out of it
        // and inserts it at the right index in the data grid view column collection
        AddColumn();
    }

    private void cancelButton_Click(object? sender, EventArgs e)
    {
        Close();
    }

    protected override bool ProcessDialogKey(Keys keyData)
    {
        if ((keyData & Keys.Modifiers) == 0)
        {
            switch (keyData & Keys.KeyCode)
            {
                case Keys.Enter:
                    // Validate the name before adding the column.
                    IDesignerHost? host = _liveDataGridView.Site?.GetService<IDesignerHost>();
                    IContainer? container = host?.Container;
                    INameCreationService? nameCreationService = _liveDataGridView.Site?.GetService<INameCreationService>();

                    if (ValidName(
                        _nameTextBox.Text,
                        _dataGridViewColumns,
                        container,
                        nameCreationService,
                        _liveDataGridView.Columns,
                        !_persistChangesToDesigner,
                        out string errorString))
                    {
                        AddColumn();
                        Close();
                    }
                    else
                    {
                        IUIService? uiService = _liveDataGridView.Site?.GetService<IUIService>();
                        DataGridViewDesigner.ShowErrorDialog(uiService, errorString, _liveDataGridView);
                    }

                    return true;
            }
        }

        return base.ProcessDialogKey(keyData);
    }

    internal void Start(int insertAtPosition, bool persistChangesToDesigner)
    {
        _insertAtPosition = insertAtPosition;
        _persistChangesToDesigner = persistChangesToDesigner;

        if (_persistChangesToDesigner)
        {
            _initialDataGridViewColumnsCount = _liveDataGridView.Columns.Count;
        }
        else
        {
            _initialDataGridViewColumnsCount = -1;
        }
    }

    private void SetDefaultDataGridViewColumnType(Type type)
    {
        TypeConverter imageTypeConverter = TypeDescriptor.GetConverter(typeof(Image));

        if (type == typeof(bool) || type == typeof(CheckState))
        {
            // get the data grid view check box column type
            _columnTypesCombo.SelectedIndex = TypeToSelectedIndex(typeof(DataGridViewCheckBoxColumn));
        }
        else if (typeof(Image).IsAssignableFrom(type) || imageTypeConverter.CanConvertFrom(type))
        {
            // get the data grid view image column type
            _columnTypesCombo.SelectedIndex = TypeToSelectedIndex(typeof(DataGridViewImageColumn));
        }
        else
        {
            // get the data grid view text box column type
            _columnTypesCombo.SelectedIndex = TypeToSelectedIndex(typeof(DataGridViewTextBoxColumn));
        }
    }

    private int TypeToSelectedIndex(Type type)
    {
        for (int i = 0; i < _columnTypesCombo.Items.Count; i++)
        {
            if (type == ((ComboBoxItem)_columnTypesCombo.Items[i]!).ColumnType)
            {
                return i;
            }
        }

        Debug.Fail("we should have found a type by now");

        return -1;
    }

    public static bool ValidName(string name,
        DataGridViewColumnCollection columns,
        IContainer? container,
        INameCreationService? nameCreationService,
        DataGridViewColumnCollection liveColumns,
        bool allowDuplicateNameInLiveColumnCollection)
        => ValidName(name, columns, container, nameCreationService, liveColumns, allowDuplicateNameInLiveColumnCollection, out _);

    /// <devdoc>
    ///  A column name is valid if it does not cause any name conflicts in the DataGridViewColumnCollection
    ///  and the IContainer::Component collection.
    /// </devdoc>
    public static bool ValidName(string name,
        DataGridViewColumnCollection columns,
        IContainer? container,
        INameCreationService? nameCreationService,
        DataGridViewColumnCollection? liveColumns,
        bool allowDuplicateNameInLiveColumnCollection,
        out string errorString)
    {
        if (columns.Contains(name))
        {
            errorString = string.Format(SR.DataGridViewDuplicateColumnName, name);
            return false;
        }

        if (container is not null && container.Components[name] is not null)
        {
            if (!allowDuplicateNameInLiveColumnCollection || liveColumns is null || !liveColumns.Contains(name))
            {
                errorString = string.Format(SR.DesignerHostDuplicateName, name);
                return false;
            }
        }

        if (nameCreationService is not null && !nameCreationService.IsValidName(name))
        {
            if (!allowDuplicateNameInLiveColumnCollection || liveColumns is null || !liveColumns.Contains(name))
            {
                errorString = string.Format(SR.CodeDomDesignerLoaderInvalidIdentifier, name);
                return false;
            }
        }

        errorString = string.Empty;
        return true;
    }

    private class ListBoxItem
    {
        public ListBoxItem(Type propertyType, string propertyName)
        {
            PropertyType = propertyType;
            PropertyName = propertyName;
        }

        public Type PropertyType { get; }

        public string PropertyName { get; }

        public override string ToString() => PropertyName;
    }

    private class ComboBoxItem
    {
        public ComboBoxItem(Type columnType)
        {
            ColumnType = columnType;
        }

        public override string ToString() => ColumnType.Name;

        public Type ColumnType { get; }
    }
}
