using System;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Jellyfish.Library;

namespace Jellyfish.Virtu.Services
{
    public sealed class WpfVideoService : VideoService
    {
        public WpfVideoService(Machine machine, UserControl page, Image image) : 
            base(machine)
        {
            if (page == null)
            {
                throw new ArgumentNullException("page");
            }
            if (image == null)
            {
                throw new ArgumentNullException("image");
            }

            _page = page;
            _image = image;
            _image.Source = _bitmap;

            _page.Loaded += (sender, e) => SetWindowSizeToContent();
            _page.SizeChanged += (sender, e) => SetImageSize();
        }

        public override void SetFullScreen(bool isFullScreen)
        {
            if (_isFullScreen != isFullScreen)
            {
                _isFullScreen = isFullScreen;
                _page.Dispatcher.Send(() =>
                {
                    var window = Window.GetWindow(_page);
                    if (_isFullScreen)
                    {
                        window.ResizeMode = ResizeMode.NoResize;
                        window.WindowStyle = WindowStyle.None;
                        window.WindowState = WindowState.Maximized;
                    }
                    else
                    {
                        window.WindowState = WindowState.Normal;
                        window.WindowStyle = WindowStyle.SingleBorderWindow;
                        window.ResizeMode = ResizeMode.CanResize;
                    }
                });
            }
        }

        [SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow")]
        public override void SetPixel(int x, int y, uint color)
        {
            _pixels[y * BitmapWidth + x] = color;
            _pixelsDirty = true;
        }

        public override void Update() // main thread
        {
            if (_pixelsDirty)
            {
                _pixelsDirty = false;
                _bitmap.WritePixels(BitmapRect, _pixels, BitmapStride, 0);
            }
        }

        private void SetImageSize()
        {
            int uniformScale = Math.Max(1, Math.Min((int)_page.RenderSize.Width / BitmapWidth, (int)_page.RenderSize.Height / BitmapHeight));
            _image.Width = uniformScale * BitmapWidth;
            _image.Height = uniformScale * BitmapHeight;
        }

        private void SetWindowSizeToContent()
        {
            if (!_sizedToContent)
            {
                _sizedToContent = true;
                var window = Application.Current.MainWindow;
                var size = window.DesiredSize;
                window.Width = size.Width;
                window.Height = size.Height;
            }
        }

        private const int BitmapWidth = 560;
        private const int BitmapHeight = 384;
        private const int BitmapDpi = 96;
        private static readonly PixelFormat BitmapPixelFormat = PixelFormats.Bgr32;
        private static readonly int BitmapStride = (BitmapWidth * BitmapPixelFormat.BitsPerPixel + 7) / 8;
        private static readonly Int32Rect BitmapRect = new Int32Rect(0, 0, BitmapWidth, BitmapHeight);

        private UserControl _page;
        private Image _image;
        private WriteableBitmap _bitmap = new WriteableBitmap(BitmapWidth, BitmapHeight, BitmapDpi, BitmapDpi, BitmapPixelFormat, null);
        private uint[] _pixels = new uint[BitmapWidth * BitmapHeight];
        private bool _pixelsDirty;
        private bool _isFullScreen;
        private bool _sizedToContent;
    }
}
