// 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.Diagnostics;
using System.Drawing;
using static Interop;

namespace System.Windows.Forms
{
    public partial class DataGridViewTopLeftHeaderCell
    {
        protected class DataGridViewTopLeftHeaderCellAccessibleObject : DataGridViewColumnHeaderCellAccessibleObject
        {
            public DataGridViewTopLeftHeaderCellAccessibleObject(DataGridViewTopLeftHeaderCell owner) : base(owner)
            {
            }

            public override Rectangle Bounds
            {
                get
                {
                    if (Owner is null)
                    {
                        throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                    }

                    if (Owner.DataGridView is null || !Owner.DataGridView.IsHandleCreated)
                    {
                        return Rectangle.Empty;
                    }

                    Rectangle cellRect = Owner.DataGridView.GetCellDisplayRectangle(-1, -1, false /*cutOverflow*/);
                    return Owner.DataGridView.RectangleToScreen(cellRect);
                }
            }

            public override string DefaultAction
            {
                get
                {
                    if (Owner is null)
                    {
                        throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                    }

                    if (Owner.DataGridView?.MultiSelect ?? false)
                    {
                        return SR.DataGridView_AccTopLeftColumnHeaderCellDefaultAction;
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
            }

            public override string Name
            {
                get
                {
                    if (Owner is null)
                    {
                        throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                    }

                    object value = Owner.Value;
                    if (value is not null && !(value is string))
                    {
                        // The user set the Value on the DataGridViewTopLeftHeaderCell and it did not set it to a string.
                        // Then the name of the DataGridViewTopLeftHeaderAccessibleObject is String.Empty;
                        //
                        return string.Empty;
                    }

                    string? strValue = value as string;
                    if (string.IsNullOrEmpty(strValue))
                    {
                        if (Owner.DataGridView is not null)
                        {
                            if (Owner.DataGridView.RightToLeft == RightToLeft.No)
                            {
                                return SR.DataGridView_AccTopLeftColumnHeaderCellName;
                            }
                            else
                            {
                                return SR.DataGridView_AccTopLeftColumnHeaderCellNameRTL;
                            }
                        }
                        else
                        {
                            return string.Empty;
                        }
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
            }

            public override AccessibleStates State
            {
                get
                {
                    if (Owner is null)
                    {
                        throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                    }

                    AccessibleStates resultState = AccessibleStates.Selectable;

                    // get the Offscreen state from the base method.
                    AccessibleStates state = base.State;
                    if ((state & AccessibleStates.Offscreen) == AccessibleStates.Offscreen)
                    {
                        resultState |= AccessibleStates.Offscreen;
                    }

                    // If all the cells are selected, then the top left header cell accessible object is considered to be selected as well.
                    if (Owner.DataGridView is not null && Owner.DataGridView.AreAllCellsSelected(false /*includeInvisibleCells*/))
                    {
                        resultState |= AccessibleStates.Selected;
                    }

                    return resultState;
                }
            }

            public override string Value
            {
                get
                {
                    // We changed DataGridViewTopLeftHeaderCellAccessibleObject::Name to return a string
                    // However, DataGridViewTopLeftHeaderCellAccessibleObject::Value should still return String.Empty.
                    return string.Empty;
                }
            }

            public override void DoDefaultAction()
            {
                if (Owner?.DataGridView?.IsHandleCreated is true)
                {
                    Owner.DataGridView.SelectAll();
                }
            }

            public override AccessibleObject? Navigate(AccessibleNavigation navigationDirection)
            {
                if (Owner is null)
                {
                    throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                }

                if (Owner.DataGridView is null)
                {
                    return null;
                }

                Debug.Assert(Owner.DataGridView.RowHeadersVisible, "if the row headers are not visible how did you get the top left header cell acc object?");
                switch (navigationDirection)
                {
                    case AccessibleNavigation.Previous:
                        return null;
                    case AccessibleNavigation.Left:
                        if (Owner.DataGridView.RightToLeft == RightToLeft.No)
                        {
                            return null;
                        }
                        else
                        {
                            return NavigateForward();
                        }

                    case AccessibleNavigation.Next:
                        return NavigateForward();
                    case AccessibleNavigation.Right:
                        if (Owner.DataGridView.RightToLeft == RightToLeft.No)
                        {
                            return NavigateForward();
                        }
                        else
                        {
                            return null;
                        }

                    default:
                        return null;
                }
            }

            public override void Select(AccessibleSelection flags)
            {
                if (Owner is null)
                {
                    throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                }

                if (Owner.DataGridView?.IsHandleCreated != true)
                {
                    return;
                }

                // AccessibleSelection.TakeFocus should focus the grid and then focus the first data grid view data cell
                if ((flags & AccessibleSelection.TakeFocus) == AccessibleSelection.TakeFocus)
                {
                    // Focus the grid
                    Owner.DataGridView.Focus();
                    if (Owner.DataGridView.Columns.GetColumnCount(DataGridViewElementStates.Visible) > 0 &&
                        Owner.DataGridView.Rows.GetRowCount(DataGridViewElementStates.Visible) > 0)
                    {
                        // This means that there are visible rows and columns.
                        // Focus the first data cell.
                        DataGridViewRow row = Owner.DataGridView.Rows[Owner.DataGridView.Rows.GetFirstRow(DataGridViewElementStates.Visible)];
                        DataGridViewColumn col = Owner.DataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible);

                        // DataGridView::set_CurrentCell clears the previous selection.
                        // So use SetCurrenCellAddressCore directly.
                        Owner.DataGridView.SetCurrentCellAddressCoreInternal(col.Index, row.Index, false /*setAnchorCellAddress*/, true /*validateCurrentCell*/, false /*thoughMouseClick*/);
                    }
                }

                // AddSelection selects the entire grid.
                if ((flags & AccessibleSelection.AddSelection) == AccessibleSelection.AddSelection)
                {
                    if (Owner.DataGridView.MultiSelect)
                    {
                        Owner.DataGridView.SelectAll();
                    }
                }

                // RemoveSelection clears the selection on the entire grid.
                // But only if AddSelection is not set.
                if ((flags & AccessibleSelection.RemoveSelection) == AccessibleSelection.RemoveSelection &&
                    (flags & AccessibleSelection.AddSelection) == 0)
                {
                    Owner.DataGridView.ClearSelection();
                }
            }

            private AccessibleObject? NavigateForward()
            {
                if (Owner is null)
                {
                    throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                }

                if (Owner.DataGridView is null || Owner.DataGridView.Columns.GetColumnCount(DataGridViewElementStates.Visible) == 0)
                {
                    return null;
                }

                // return the acc object for the first visible column
                return Owner.DataGridView.AccessibilityObject.GetChild(0)?.GetChild(1);
            }
            #region IRawElementProviderFragment Implementation

            internal override UiaCore.IRawElementProviderFragment? FragmentNavigate(UiaCore.NavigateDirection direction)
            {
                if (Owner is null)
                {
                    throw new InvalidOperationException(SR.DataGridViewCellAccessibleObject_OwnerNotSet);
                }

                if (Owner.DataGridView is null)
                {
                    return null;
                }

                DataGridView dataGridView = Owner.DataGridView;

                switch (direction)
                {
                    case UiaCore.NavigateDirection.Parent:
                        return dataGridView.AccessibilityObject.GetChild(0);
                    case UiaCore.NavigateDirection.PreviousSibling:
                        return null;
                    case UiaCore.NavigateDirection.NextSibling:
                        if (dataGridView.Columns.GetColumnCount(DataGridViewElementStates.Visible) == 0)
                        {
                            return null;
                        }

                        return NavigateForward();
                    default:
                        return null;
                }
            }

            #endregion

            #region IRawElementProviderSimple Implementation

            internal override object? GetPropertyValue(UiaCore.UIA propertyId)
            {
                switch (propertyId)
                {
                    case UiaCore.UIA.NamePropertyId:
                        return Name;
                    case UiaCore.UIA.ControlTypePropertyId:
                        return UiaCore.UIA.HeaderControlTypeId;
                    case UiaCore.UIA.IsEnabledPropertyId:
                        return Owner?.DataGridView?.Enabled ?? false;
                    case UiaCore.UIA.HelpTextPropertyId:
                        return Help ?? string.Empty;
                    case UiaCore.UIA.IsKeyboardFocusablePropertyId:
                    case UiaCore.UIA.IsPasswordPropertyId:
                    case UiaCore.UIA.IsOffscreenPropertyId:
                        return false;
                    case UiaCore.UIA.AccessKeyPropertyId:
                        return string.Empty;
                }

                return base.GetPropertyValue(propertyId);
            }

            #endregion
        }
    }
}
