using System;
using System.Runtime.InteropServices;
using Avalonia.Platform;

namespace Avalonia.LinuxFramebuffer
{
    unsafe class LockedFramebuffer : ILockedFramebuffer
    {
        private readonly int _fb;
        private readonly fb_fix_screeninfo _fixedInfo;
        private fb_var_screeninfo _varInfo;
        private readonly IntPtr _address;

        public LockedFramebuffer(int fb, fb_fix_screeninfo fixedInfo, fb_var_screeninfo varInfo, IntPtr address, Vector dpi)
        {
            _fb = fb;
            _fixedInfo = fixedInfo;
            _varInfo = varInfo;
            _address = address;
            Dpi = dpi;
            //Use double buffering to avoid flicker
            Address = Marshal.AllocHGlobal(RowBytes * Size.Height);
        }


        void VSync()
        {
            NativeUnsafeMethods.ioctl(_fb, FbIoCtl.FBIO_WAITFORVSYNC, null);
        }

        public void Dispose()
        {
            VSync();
            NativeUnsafeMethods.memcpy(_address, Address, new IntPtr(RowBytes * Size.Height));

            Marshal.FreeHGlobal(Address);
            Address = IntPtr.Zero;
        }

        public IntPtr Address { get; private set; }
        public PixelSize Size => new PixelSize((int)_varInfo.xres, (int) _varInfo.yres);
        public int RowBytes => (int) _fixedInfo.line_length;
        public Vector Dpi { get; }
        public PixelFormat Format => _varInfo.blue.offset == 16 ? PixelFormat.Rgba8888 : PixelFormat.Bgra8888;
    }
}
