//
//  PacketStringBuilder.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.Collections.Generic;
using System.Text;
using Remora.Results;
namespace NosSmooth.Packets;
/// 
/// String builder for packets.
/// 
public class PacketStringBuilder
{
    private readonly StringBuilder _builder;
    private StringBuilderLevel _currentLevel;
    private char? _preparedLevelSeparator;
    private char? _insertSeparator;
    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// The top level separator.
    public PacketStringBuilder(char separator = ' ')
    {
        _currentLevel = new StringBuilderLevel(null, separator);
        _preparedLevelSeparator = _insertSeparator = null;
        _builder = new StringBuilder();
    }
    /// 
    /// Sets the separator to search for only once.
    /// 
    /// 
    /// This separator will have the most priority.
    /// 
    /// The separator to look for.
    public void SetAfterSeparatorOnce(char separator)
    {
        _currentLevel.SeparatorOnce = separator;
    }
    /// 
    /// Prepare the given level that can be set when needed.
    /// 
    /// The separator of the prepared level.
    public void PrepareLevel(char separator)
    {
        _preparedLevelSeparator = separator;
    }
    /// 
    /// Reset the prepared level, if there is any.
    /// 
    public void RemovePreparedLevel()
    {
        _preparedLevelSeparator = null;
    }
    /// 
    /// Create next level with the separator given in the prepared level.
    /// 
    /// 
    /// Level of the current builder will stay the same.
    /// Will return null, if there is not a level prepared.
    /// 
    /// An enumerator with the new level pushed.
    public bool PushPreparedLevel()
    {
        if (_preparedLevelSeparator is null)
        {
            return false;
        }
        _currentLevel = new StringBuilderLevel(_currentLevel, _preparedLevelSeparator.Value);
        return true;
    }
    /// 
    /// Push new separator level to the stack.
    /// 
    /// 
    /// This will change the current enumerator.
    /// It has to be  after parent level should be used.
    /// 
    /// The separator of the new level.
    public void PushLevel(char separator)
    {
        _preparedLevelSeparator = null;
        _currentLevel = new StringBuilderLevel(_currentLevel, separator);
    }
    /// 
    /// Pop the current level.
    /// 
    /// Whether to replace the last separator with the parent one.
    /// A result that may or may not have succeeded. There will be an error if the current level is the top one.
    public Result PopLevel(bool replaceSeparator = true)
    {
        if (_currentLevel.Parent is null)
        {
            return new InvalidOperationError("The level cannot be popped, the stack is already at the top level.");
        }
        if (replaceSeparator)
        {
            ReplaceWithParentSeparator();
        }
        _currentLevel = _currentLevel.Parent;
        return Result.FromSuccess();
    }
    /// 
    /// Appends the value to the string.
    /// 
    /// The value to append.
    public void Append(string value)
    {
        if (_insertSeparator is not null)
        {
            _builder.Append(_insertSeparator);
            _insertSeparator = null;
        }
        _builder.Append(value);
        _insertSeparator = _currentLevel.SeparatorOnce ?? _currentLevel.Separator;
        _currentLevel.SeparatorOnce = null;
    }
    /// 
    /// Replace the last separator with the parent separator.
    /// 
    public void ReplaceWithParentSeparator()
    {
        var parent = _currentLevel.Parent;
        if (_insertSeparator is null || parent is null)
        {
            return;
        }
        _insertSeparator = parent.SeparatorOnce ?? parent.Separator;
        parent.SeparatorOnce = null;
    }
    /// 
    public override string ToString()
    {
        return _builder.ToString();
    }
    private class StringBuilderLevel
    {
        public StringBuilderLevel(StringBuilderLevel? parent, char separator)
        {
            Parent = parent;
            Separator = separator;
        }
        public StringBuilderLevel? Parent { get; }
        public char Separator { get; }
        public char? SeparatorOnce { get; set; }
    }
}