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

#nullable disable

using System;
using System.Collections.Generic;

namespace Microsoft.AspNetCore.Razor.Language.Syntax;

internal class SyntaxTriviaListBuilder
{
    private SyntaxTrivia[] _nodes;

    public SyntaxTriviaListBuilder(int size)
    {
        _nodes = new SyntaxTrivia[size];
    }

    public static SyntaxTriviaListBuilder Create()
    {
        return new SyntaxTriviaListBuilder(4);
    }

    public static SyntaxTriviaList Create(IEnumerable<SyntaxTrivia> trivia)
    {
        if (trivia == null)
        {
            return new SyntaxTriviaList();
        }

        var builder = Create();
        builder.AddRange(trivia);
        return builder.ToList();
    }

    public int Count { get; private set; }

    public void Clear()
    {
        Count = 0;
    }

    public SyntaxTrivia this[int index]
    {
        get
        {
            if (index < 0 || index > Count)
            {
                throw new IndexOutOfRangeException();
            }

            return _nodes[index];
        }
    }

    public void AddRange(IEnumerable<SyntaxTrivia> items)
    {
        if (items != null)
        {
            foreach (var item in items)
            {
                Add(item);
            }
        }
    }

    public SyntaxTriviaListBuilder Add(SyntaxTrivia item)
    {
        if (_nodes == null || Count >= _nodes.Length)
        {
            Grow(Count == 0 ? 8 : _nodes.Length * 2);
        }

        _nodes[Count++] = item;
        return this;
    }

    public void Add(SyntaxTrivia[] items)
    {
        Add(items, 0, items.Length);
    }

    public void Add(SyntaxTrivia[] items, int offset, int length)
    {
        if (_nodes == null || Count + length > _nodes.Length)
        {
            Grow(Count + length);
        }

        Array.Copy(items, offset, _nodes, Count, length);
        Count += length;
    }

    public void Add(in SyntaxTriviaList list)
    {
        Add(list, 0, list.Count);
    }

    public void Add(in SyntaxTriviaList list, int offset, int length)
    {
        if (_nodes == null || Count + length > _nodes.Length)
        {
            Grow(Count + length);
        }

        list.CopyTo(offset, _nodes, Count, length);
        Count += length;
    }

    private void Grow(int size)
    {
        var tmp = new SyntaxTrivia[size];
        Array.Copy(_nodes, tmp, _nodes.Length);
        _nodes = tmp;
    }

    public static implicit operator SyntaxTriviaList(SyntaxTriviaListBuilder builder)
    {
        return builder.ToList();
    }

    public SyntaxTriviaList ToList()
    {
        if (Count > 0)
        {
            var tmp = new ArrayElement<GreenNode>[Count];
            for (var i = 0; i < Count; i++)
            {
                tmp[i].Value = _nodes[i].Green;
            }
            return new SyntaxTriviaList(InternalSyntax.SyntaxList.List(tmp).CreateRed(), position: 0, index: 0);
        }
        else
        {
            return default(SyntaxTriviaList);
        }
    }
}
