﻿// 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.

namespace Microsoft.CodeAnalysis.Syntax
{
    internal partial class SyntaxList
    {
        internal sealed class SeparatedWithManyChildren : SyntaxList
        {
            private readonly ArrayElement<SyntaxNode?>[] _children;

            internal SeparatedWithManyChildren(InternalSyntax.SyntaxList green, SyntaxNode? parent, int position)
                : base(green, parent, position)
            {
                _children = new ArrayElement<SyntaxNode?>[(green.SlotCount + 1) >> 1];
            }

            internal override SyntaxNode? GetNodeSlot(int i)
            {
                if ((i & 1) != 0)
                {
                    //separator
                    return null;
                }

                return this.GetRedElement(ref _children[i >> 1].Value, i);
            }

            internal override SyntaxNode? GetCachedSlot(int i)
            {
                if ((i & 1) != 0)
                {
                    //separator
                    return null;
                }

                return _children[i >> 1].Value;
            }

            internal override int GetChildPosition(int index)
            {
                // If the previous sibling (ignoring separator) is not cached, but the next sibling
                // (ignoring separator) is cached, use the next sibling to determine position.
                int valueIndex = (index & 1) != 0 ? index - 1 : index;
                // The check for valueIndex >= Green.SlotCount - 2 ignores the last item because the last item
                // is a separator and separators are not cached. In those cases, when the index represents
                // the last or next to last item, we still want to calculate the position from the end of
                // the list rather than the start.
                if (valueIndex > 1
                    && GetCachedSlot(valueIndex - 2) is null
                    && (valueIndex >= Green.SlotCount - 2 || GetCachedSlot(valueIndex + 2) is { }))
                {
                    return GetChildPositionFromEnd(index);
                }

                return base.GetChildPosition(index);
            }
        }
    }
}
