using System;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;

namespace FingerPaint
{
    public sealed partial class MainPage : Page
    {
        int pastedPixelWidth, pastedPixelHeight;
        byte[] pastedPixels;

        void InitializeSharing()
        {
            // Inicjowanie przycisku Wklej i zapewnienie aktualizacji
            CheckForPasteEnable();
            Clipboard.ContentChanged += OnClipboardContentChanged;

            // Dodanie klawiszy skrótu dla Kopiuj i Wklej
            Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated +=
                                                                    OnAcceleratorKeyActivated;

            // Podłączenie do panelu Udostępnianie i dostarczenie danych
            DataTransferManager.GetForCurrentView().DataRequested += OnDataTransferDataRequested;
        }

        async void OnDataTransferDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            DataRequestDeferral deferral = args.Request.GetDeferral();

            // Pobranie referencji strumienia i przekazanie go
            RandomAccessStreamReference reference = await GetBitmapStream(bitmap);
            args.Request.Data.SetBitmap(reference);
            args.Request.Data.Properties.Title = "Finger Paint";
            args.Request.Data.Properties.Description = "Udostępnianie rysunku innym aplikacjom";

            deferral.Complete();
        }

        void OnClipboardContentChanged(object sender, object args)
        {
            CheckForPasteEnable();
        }

        void CheckForPasteEnable()
        {
            pasteAppBarButton.IsEnabled = CheckClipboardForBitmap();
        }

        bool CheckClipboardForBitmap()
        {
            DataPackageView dataView = Clipboard.GetContent();
            return dataView.Contains(StandardDataFormats.Bitmap);
        }

        async void OnCopyAppBarButtonClick(object sender, RoutedEventArgs args)
        {
            DataPackage dataPackage = new DataPackage
            {
                RequestedOperation = DataPackageOperation.Move,
            };
            dataPackage.SetBitmap(await GetBitmapStream(bitmap));

            Clipboard.SetContent(dataPackage);
            this.BottomAppBar.IsOpen = false;
        }

        async Task<RandomAccessStreamReference> GetBitmapStream(WriteableBitmap bitmap)
        {
            // Pobranie tablicy pikseli dla tej mapy bitowej
            byte[] pixels = new byte[4 * bitmap.PixelWidth * bitmap.PixelHeight];
            Stream stream = bitmap.PixelBuffer.AsStream();
            await stream.ReadAsync(pixels, 0, pixels.Length);

            // Tworzenie BitmapEncoder skojaroznego ze strumieniem pamięciowym
            InMemoryRandomAccessStream memoryStream = new InMemoryRandomAccessStream();
            BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId,
                                                                    memoryStream);

            // Ustawienie pikseli w tym kodreze
            encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied,
                                 (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96, 96, pixels);
            await encoder.FlushAsync();

            // Zwrócenie RandomAccessStreamReference
            return RandomAccessStreamReference.CreateFromStream(memoryStream);
        }

        async void OnPasteAppBarButtonClick(object sender, RoutedEventArgs args)
        {
            // Tymczasowe zablokowanie przycisku Wklej
            Button button = sender as Button;
            button.IsEnabled = false;

            // Pobranie zawartości schowka i sprawdzenie, czy jest to mapa bitowa
            DataPackageView dataView = Clipboard.GetContent();

            if (dataView.Contains(StandardDataFormats.Bitmap))
            {
                // Pobranie referencji strumienia oraz samego strumienia
                RandomAccessStreamReference streamRef = await dataView.GetBitmapAsync();
                IRandomAccessStreamWithContentType stream = await streamRef.OpenReadAsync();

                // Tworzenie BitmapDecoder do odczytu mapy bitowej
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
                BitmapFrame bitmapFrame = await decoder.GetFrameAsync(0);
                PixelDataProvider pixelProvider =
                    await bitmapFrame.GetPixelDataAsync(BitmapPixelFormat.Bgra8,
                                                        BitmapAlphaMode.Premultiplied,
                                                        new BitmapTransform(),
                                                        ExifOrientationMode.RespectExifOrientation,
                                                        ColorManagementMode.ColorManageToSRgb);

                // Zapisanie danych wystarczających do utworzenia obiektu WriteableBitmap
                pastedPixelWidth = (int)bitmapFrame.PixelWidth;
                pastedPixelHeight = (int)bitmapFrame.PixelHeight;
                pastedPixels = pixelProvider.DetachPixelData();

                // Sprawdzenie, czy można zastąpić bieżący rysunek
                await CheckIfOkToTrashFile(FinishPasteBitmapAndPixelArray);
            }

            // Ponowne włączenie przycisku i zamknięcie paska aplikacji
            button.IsEnabled = true;
            this.BottomAppBar.IsOpen = false;
        }

        async Task FinishPasteBitmapAndPixelArray()
        {
            bitmap = new WriteableBitmap(pastedPixelWidth, pastedPixelHeight);
            pixels = pastedPixels;

            // Przesłanie pikseli do mapy bitowej oraz inne zadania
            await InitializeBitmap();

            // Ustawienie właściwości AppSettings dla nowego obrazu
            appSettings.LoadedFilePath = null;
            appSettings.LoadedFilename = null;
            appSettings.IsImageModified = false;
        }

        void OnAcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args)
        {
            if ((args.EventType == CoreAcceleratorKeyEventType.SystemKeyDown ||
                    args.EventType == CoreAcceleratorKeyEventType.KeyDown) &&
                (args.VirtualKey == VirtualKey.C || args.VirtualKey == VirtualKey.V))
            {
                CoreWindow window = Window.Current.CoreWindow;
                CoreVirtualKeyStates down = CoreVirtualKeyStates.Down;

                // Interesuje nas przypadek, gdy jest wciśnięty Ctrl 
                if ((window.GetKeyState(VirtualKey.Shift) & down) == down ||
                    (window.GetKeyState(VirtualKey.Control) & down) != down ||
                    (window.GetKeyState(VirtualKey.Menu) & down) == down)
                {
                    return;
                }

                if (args.VirtualKey == VirtualKey.C)
                {
                    OnCopyAppBarButtonClick(null, null);
                }
                else if (args.VirtualKey == VirtualKey.V)
                {
                    OnPasteAppBarButtonClick(pasteAppBarButton, null);
                }
            }
        }
    }
}
