// Decompiled with JetBrains decompiler
// Type: Microsoft.Iris.Render.Graphics.Image
// Assembly: UIX.RenderApi, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
// MVID: D47658B8-A8EA-43D6-8837-ECE823BFFFC1
// Assembly location: C:\Program Files\Zune\UIX.RenderApi.dll

using Microsoft.Iris.Render.Common;
using Microsoft.Iris.Render.Internal;
using Microsoft.Iris.Render.Protocol;
using Microsoft.Iris.Render.Remote;
using System;
using System.Runtime.InteropServices;

namespace Microsoft.Iris.Render.Graphics
{
    internal class Image : SharedResource, IImage, ISharedRenderObject, ISurfaceContentOwner
    {
        private SurfaceManager m_surfaceManager;
        private Surface m_surface;
        private ImageFormat m_imageFormat;
        private Size m_sizeImage;
        private Size m_sizeGutterPxl;
        private DataBufferTracker m_dataTracker;
        private ContentNotifyHandler m_handlerContent;
        private string m_stIdentifier;
        private ImageLoadInfo m_loadInfo;
        private bool m_insideReleaseCallback;

        internal Image(
          RenderSession session,
          SurfaceManager surfaceManager,
          string identifier,
          ContentNotifyHandler handler,
          Size sizeGutter)
          : base(session)
        {
            session.AssertOwningThread();
            this.m_session = session;
            this.m_surfaceManager = surfaceManager;
            this.m_stIdentifier = identifier;
            this.m_handlerContent = handler;
            this.m_sizeGutterPxl = sizeGutter;
        }

        protected override void Dispose(bool fInDispose)
        {
            try
            {
                if (fInDispose && this.m_dataTracker != null)
                    MessagingSession.Current.ReturnDataBufferTracker(this.m_dataTracker);
                this.m_surface = null;
                this.m_surfaceManager = null;
                this.m_dataTracker = null;
                this.m_handlerContent = null;
                this.m_session = null;
            }
            finally
            {
                base.Dispose(fInDispose);
            }
        }

        internal Size Size => this.m_sizeImage;

        internal ImageFormat Format => this.m_imageFormat;

        internal Surface Surface => this.m_surface;

        internal string Identifier => this.m_stIdentifier;

        internal Size GutterSize
        {
            get => this.m_sizeGutterPxl;
            set
            {
                if (value.Width <= this.m_sizeGutterPxl.Width && value.Height <= this.m_sizeGutterPxl.Height)
                    return;
                this.m_sizeGutterPxl.Width = Math.Max(value.Width, this.m_sizeGutterPxl.Width);
                this.m_sizeGutterPxl.Height = Math.Max(value.Height, this.m_sizeGutterPxl.Height);
                if (!this.InUse)
                    return;
                this.AcquireContent();
            }
        }

        void ISurfaceContentOwner.OnSurfaceDisposed(Surface surface)
        {
            if (this.m_surface != surface)
                return;
            this.m_surface = null;
        }

        void ISurfaceContentOwner.OnRestoreContent(Surface surface)
        {
            if (this.m_surface != surface)
                return;
            this.AcquireContent();
        }

        Size IImage.Size => this.m_sizeImage;

        ImageFormat IImage.Format => this.m_imageFormat;

        string IImage.Identifier => this.m_stIdentifier;

        bool IImage.LoadContent(
          ImageFormat imageFormat,
          Size sizeImage,
          int nStride,
          IntPtr rgData)
        {
            this.m_session.AssertOwningThread();
            bool flag1 = false;
            bool flag2 = false;
            DataBuffer buffer = null;
            try
            {
                SurfaceFormat nFormat = SurfaceFormatInfo.FromImageFormat(imageFormat);
                if (nFormat == SurfaceFormat.RGB32)
                    nFormat = SurfaceFormat.ARGB32;
                if (this.m_surface != null && (this.m_imageFormat != imageFormat || this.m_sizeImage != sizeImage || this.m_sizeGutterPxl != this.m_surface.GutterSize))
                {
                    if (this.InUse)
                        this.m_surface.RemoveActiveUser(this);
                    this.m_surface = null;
                }
                if (this.m_surface == null)
                {
                    this.m_surface = this.m_surfaceManager.RequestSurface(this, nFormat, sizeImage, this.m_sizeGutterPxl);
                    flag2 = true;
                    if (this.InUse)
                        this.m_surface.AddActiveUser(this);
                }
                IntPtr num1 = IntPtr.Zero;
                if (this.m_session.IsForeignByteOrderOnWindowing)
                {
                    int bitsPerPixel = SurfaceFormatInfo.GetBitsPerPixel(nFormat);
                    int num2 = sizeImage.Height * nStride;
                    num1 = Marshal.AllocHGlobal(num2);
                    Memory.ConvertEndian(num1, rgData, num2, bitsPerPixel);
                }
                this.m_imageFormat = imageFormat;
                this.m_sizeImage = sizeImage;
                uint cbSize = (uint)(nStride * this.m_sizeImage.Height);
                buffer = this.m_session.BuildDataBuffer(num1 == IntPtr.Zero ? rgData : num1, cbSize);
                this.Track(buffer, num1, rgData, nStride);
                buffer.Commit();
                ++this.m_loadInfo.nLoadsInProgress;
                ImageHeader header;
                header.sizeActualPxl = this.m_sizeImage;
                header.sizeOriginalPxl = this.m_sizeImage;
                header.nStride = nStride;
                header.nFormat = nFormat;
                this.m_session.LoadSurface(buffer, this.m_surface, header);
                if (flag2 && this.ContentReloadedEvent != null)
                    this.ContentReloadedEvent(this);
                flag1 = true;
                return flag1;
            }
            finally
            {
                if (!flag1)
                {
                    if (buffer != null)
                        this.StopTracking(buffer);
                    this.m_surface = null;
                }
            }
        }

        internal event Image.ContentReloadedHandler ContentReloadedEvent;

        private void AcquireContent()
        {
            Debug2.Validate(!this.m_insideReleaseCallback, typeof(InvalidOperationException), "AcquireContent must not be called while inside ContentNotify(Release) callback");
            ContentNotifyHandler handlerContent = this.m_handlerContent;
            if (this.m_handlerContent != null)
            {
                if (this.m_loadInfo != null && this.m_loadInfo.nLoadsInProgress > 0)
                {
                    ++this.m_loadInfo.nSystemLoadRequests;
                    ((IImage)this).LoadContent(this.m_imageFormat, this.m_sizeImage, this.m_loadInfo.nStride, this.m_loadInfo.rgAppData);
                }
                else
                    this.m_handlerContent(ContentNotification.Acquire, this, IntPtr.Zero);
            }
            Surface surface = this.m_surface;
        }

        protected override void OnUsageChange(bool fUsed)
        {
            if (fUsed)
            {
                if (this.m_surface == null)
                    this.AcquireContent();
                else
                    this.m_surface.AddActiveUser(this);
            }
            else
            {
                if (this.m_surface == null)
                    return;
                this.m_surface.RemoveActiveUser(this);
            }
        }

        private void Track(DataBuffer buffer, IntPtr rgConvertData, IntPtr rgAppData, int nStride)
        {
            ImageLoadInfo imageLoadInfo;
            if (this.m_loadInfo != null && this.m_loadInfo.rgAppData == rgAppData && this.m_loadInfo.nStride == nStride)
            {
                imageLoadInfo = this.m_loadInfo;
            }
            else
            {
                imageLoadInfo = new ImageLoadInfo();
                imageLoadInfo.imageOwner = this;
                imageLoadInfo.nLoadsInProgress = 0;
                imageLoadInfo.nSystemLoadRequests = 0;
                imageLoadInfo.handlerNotify = this.m_handlerContent;
                imageLoadInfo.rgAppData = rgAppData;
                imageLoadInfo.nStride = nStride;
                if (this.m_dataTracker != null)
                {
                    MessagingSession.Current.ReturnDataBufferTracker(this.m_dataTracker);
                    this.m_dataTracker = null;
                }
                this.m_dataTracker = MessagingSession.Current.CreateDataBufferTracker(this);
            }
            DataBufferCleanupInfo bufferCleanupInfo = new DataBufferCleanupInfo();
            bufferCleanupInfo.rgConvertData = rgConvertData;
            bufferCleanupInfo.imageLoadInfo = imageLoadInfo;
            DataBufferTracker.CleanupEventHandler handler = new DataBufferTracker.CleanupEventHandler(OnDataBufferConsumed);
            this.m_dataTracker.Track(buffer, handler, bufferCleanupInfo);
            this.m_loadInfo = imageLoadInfo;
        }

        private void StopTracking(DataBuffer buffer)
        {
            if (this.m_dataTracker == null)
                return;
            this.m_dataTracker.Release(buffer, DataBufferTracker.Users.Valid);
        }

        private static void OnDataBufferConsumed(object sender, DataBufferTracker.CleanupEventArgs args)
        {
            DataBufferCleanupInfo contextData = (DataBufferCleanupInfo)args.ContextData;
            ImageLoadInfo imageLoadInfo = contextData.imageLoadInfo;
            --imageLoadInfo.nLoadsInProgress;
            if (imageLoadInfo.nSystemLoadRequests > 0)
            {
                --imageLoadInfo.nSystemLoadRequests;
            }
            else
            {
                if (imageLoadInfo.handlerNotify != null)
                {
                    imageLoadInfo.imageOwner.m_insideReleaseCallback = true;
                    imageLoadInfo.handlerNotify(ContentNotification.Release, imageLoadInfo.imageOwner, imageLoadInfo.rgAppData);
                    imageLoadInfo.imageOwner.m_insideReleaseCallback = false;
                }
                imageLoadInfo.rgAppData = IntPtr.Zero;
                imageLoadInfo.handlerNotify = null;
                imageLoadInfo.imageOwner = null;
            }
            if (!(contextData.rgConvertData != IntPtr.Zero))
                return;
            Marshal.FreeHGlobal(contextData.rgConvertData);
            contextData.rgConvertData = IntPtr.Zero;
        }

        internal delegate void ContentReloadedHandler(Image image);

        public override string ToString() => $"{{Image {Identifier} {Format} {Size}}}";
    }
}
