using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace PicView.Avalonia.AnimatedImage.Extensions;
    
[DebuggerStepThrough]
internal static class StreamExtensions
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ushort SpanToShort(Span<byte> b) => (ushort)(b[0] | (b[1] << 8));

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void Skip(this Stream stream, long count)
    {
        stream.Position += count;
    }

    /// <summary>
    /// Read a Gif block from stream while advancing the position.
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static int ReadBlock(this Stream stream, byte[] tempBuf)
    {
        _ = stream.Read(tempBuf, 0, 1);

        var blockLength = (int)tempBuf[0];

        if (blockLength > 0)
            _ = stream.Read(tempBuf, 0, blockLength);

        // Guard against infinite loop.
        if (stream.Position >= stream.Length)
            throw new InvalidGifStreamException("Reach the end of the filestream without trailer block.");

        return blockLength;
    }

    /// <summary>
    /// Skips GIF blocks until it encounters an empty block.
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void SkipBlocks(this Stream stream, byte[] tempBuf)
    {
        int blockLength;
        do
        {
            _ = stream.Read(tempBuf, 0, 1);

            blockLength = tempBuf[0];
            stream.Position += blockLength;

            // Guard against infinite loop.
            if (stream.Position >= stream.Length)
                throw new InvalidGifStreamException("Reach the end of the filestream without trailer block.");
        } while (blockLength > 0);
    }

    /// <summary>
    /// Read a <see cref="ushort"/> from stream by providing a temporary buffer.
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ushort ReadUShortS(this Stream stream, byte[] tempBuf)
    {
        _ = stream.Read(tempBuf, 0, 2);
        return SpanToShort(tempBuf);
    }

    /// <summary>
    /// Read a <see cref="ushort"/> from stream by providing a temporary buffer.
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static byte ReadByteS(this Stream stream, byte[] tempBuf)
    {
        _ = stream.Read(tempBuf, 0, 1);
        var finalVal = tempBuf[0];
        return finalVal;
    }
}