//
//  DatReader.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics.CodeAnalysis;
using System.Text;
using NosSmooth.Data.NOSFiles.Files;
using Remora.Results;

namespace NosSmooth.Data.NOSFiles.Parsers.Dat;

/// <summary>
/// Reader of .dat files.
/// </summary>
public class DatReader
{
    private readonly RawFile _file;
    private IReadOnlyList<string> _lines;
    private int _currentLine;
    private string _separator;

    /// <summary>
    /// Initializes a new instance of the <see cref="DatReader"/> class.
    /// </summary>
    /// <param name="file">The file to read.</param>
    public DatReader(RawFile file)
    {
        _lines = Encoding.ASCII.GetString(file.Content).Split('\r', '\n').ToArray();
        _currentLine = 0;
        _file = file;
        _separator = "VNUM";
    }

    /// <summary>
    /// Gets whether the reader has reached the end.
    /// </summary>
    public bool ReachedEnd => _currentLine >= _lines.Count;

    /// <summary>
    /// Sets the separator of a new item.
    /// </summary>
    /// <param name="separator">The separator of new item.</param>
    public void SetSeparatorField(string separator)
    {
        _separator = separator;
    }

    /// <summary>
    /// Read next item.
    /// </summary>
    /// <param name="item">The read item.</param>
    /// <returns>Whether an item was read.</returns>
    public bool ReadItem([NotNullWhen(true)] out DatItem? item)
    {
        return ReadItem(out item, _currentLine > 0);
    }

    private bool ReadItem([NotNullWhen(true)] out DatItem? item, bool readFirstItem)
    {
        if (ReachedEnd)
        {
            item = null;
            return false;
        }

        int startLine = _currentLine;
        if (readFirstItem && _lines[_currentLine].Trim().StartsWith(_separator))
        {
            _currentLine++;
        }

        while (!ReachedEnd && !_lines[_currentLine].Trim().StartsWith(_separator))
        {
            _currentLine++;
        }

        if (!readFirstItem)
        {
            return ReadItem(out item, true);
        }

        var dictionary = new Dictionary<string, IReadOnlyList<DatEntry>>();
        for (int i = startLine; i < _currentLine; i++)
        {
            var line = _lines[i];
            var splitted = line.Trim().Split('\t');
            var key = splitted[0];
            var entry = new DatEntry(key, splitted);
            if (!dictionary.ContainsKey(key))
            {
                dictionary.Add(key, new List<DatEntry>());
            }

            ((List<DatEntry>)dictionary[key]).Add(entry);
        }

        item = new DatItem(dictionary);
        return true;
    }
}