using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using CPF.Drawing;
using CPF.OpenGL;

namespace CPF.Windows.OpenGL
{
    public class WglContext : CPF.OpenGL.IGlContext
    {
        public const int WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091;
        public const int WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092;
        public const int WGL_CONTEXT_LAYER_PLANE_ARB = 0x2093;
        public const int WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126;
        public const int GL_FRAMEBUFFER_BINDING = 0x8CA6;

        private IntPtr dc;
        private IntPtr rc;
        IntPtr handle;

        public WglContext(IntPtr handle)
        {
            this.handle = handle;
            dc = UnmanagedMethods.GetDC(handle);
            var pfd = new PIXELFORMATDESCRIPTOR();
            pfd.nSize = (ushort)Marshal.SizeOf(pfd);
            pfd.nVersion = 1;
            pfd.dwFlags = Wgl.PFD_DRAW_TO_WINDOW | Wgl.PFD_SUPPORT_OPENGL | Wgl.PFD_SUPPORT_COMPOSITION;
            pfd.iPixelType = Wgl.PFD_TYPE_RGBA;
            pfd.cColorBits = 32;
            pfd.cDepthBits = 24;
            pfd.cStencilBits = 8;
            pfd.cAlphaBits = 8;
            pfd.iLayerType = Wgl.PFD_MAIN_PLANE;

            var format = Wgl.ChoosePixelFormat(dc, ref pfd);
            Wgl.SetPixelFormat(dc, format, ref pfd);
            rc = Wgl.wglCreateContext(dc);

            //var nPixelFormat = new int[] { -1 };
            //var r = Wgl.wglChoosePixelFormatARB(dc, new int[] {
            //Wgl.WGL_SUPPORT_OPENGL_ARB, 1,    // Must support OGL rendering
            //Wgl.WGL_DRAW_TO_WINDOW_ARB, 1,    // pf that can run a window
            //Wgl.WGL_ACCELERATION_ARB, Wgl.WGL_FULL_ACCELERATION_ARB,    // must be HW accelerated

            //Wgl.WGL_PIXEL_TYPE_ARB, Wgl.WGL_TYPE_RGBA_ARB,
            //Wgl.WGL_COLOR_BITS_ARB, 32,             // 8 bits of each R, G and B
            //Wgl. WGL_DEPTH_BITS_ARB, 24,             // 24 bits of depth precision for window
            //Wgl.WGL_STENCIL_BITS_ARB, 8,            // 开启模板缓冲区,模板缓冲区位数=8
            //Wgl.WGL_ALPHA_BITS_ARB, 8, 
            ////Wgl.WGL_SAMPLE_BUFFERS_ARB, 1,    // MSAA on,开启多重采样
            ////Wgl.WGL_SAMPLES_ARB, 4,                 // 4x MSAA ,多重采样样本数量为4
            //0, 0
            //}, new float[] { 0, 0 }, 1, nPixelFormat, out var f);
            //r= Wgl.SetPixelFormat(dc, nPixelFormat[0], ref pfd);
            //rc = Wgl.WglCreateContextAttribsArb(dc, IntPtr.Zero,
            //new[]
            //{
            //    // major
            //    WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
            //    // minor
            //    WGL_CONTEXT_MINOR_VERSION_ARB,  3,
            //    // core profile
            //    //WGL_CONTEXT_PROFILE_MASK_ARB, 0, 
            //    // debug 
            //    // WGL_CONTEXT_FLAGS_ARB, 1,
            //    // end
            //    0, 0
            //});

            if (rc == IntPtr.Zero)
            {
                Console.WriteLine("无法创建OpenGLContext   DC:" + dc + "  Handle:" + handle);
                System.Diagnostics.Debug.WriteLine("无法创建OpenGLContext   DC:" + dc + "  Handle:" + handle);
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("OpenGL Context创建成功");
                Console.WriteLine("OpenGL Context创建成功");
            }
        }

        public IntPtr RC
        {
            get { return rc; }
        }

        public IDisposable GRContext { get; set; }

        public IntPtr GetProcAddress(string name)
        {
            var ptr = Wgl.wglGetProcAddress(name);
            if (ptr == IntPtr.Zero)
            {
                ptr = UnmanagedMethods.GetProcAddress(OpenGl32Handle, name);
            }
            return ptr;
        }
        public static IntPtr OpenGl32Handle = UnmanagedMethods.LoadLibrary("opengl32");
        IntPtr oldRc;
        IntPtr oldDc;
        public void MakeCurrent()
        {
            if (rc != IntPtr.Zero)
            {
                oldDc = Wgl.wglGetCurrentDC();
                oldRc = Wgl.wglGetCurrentContext();
                if (!Wgl.wglMakeCurrent(dc, rc))
                {
                    throw new Exception("Could not set the context.");
                }
            }
        }

        public void SwapBuffers()
        {
            if (rc != IntPtr.Zero)
            {
                if (!Wgl.SwapBuffers(dc))
                {
                    throw new Exception("Could not complete SwapBuffers.");
                }
                Wgl.wglMakeCurrent(oldDc, oldRc);
            }
        }

        public void Dispose()
        {
            UnmanagedMethods.ReleaseDC(handle, dc);
            if (rc != IntPtr.Zero)
            {
                Wgl.wglDeleteContext(rc);
            }
            GRContext?.Dispose();
        }


        //public override GRGlTextureInfo CreateTexture(SKSizeI textureSize)
        //{
        //    var textures = new uint[1];
        //    Wgl.glGenTextures(textures.Length, textures);
        //    var textureId = textures[0];

        //    Wgl.glBindTexture(Wgl.GL_TEXTURE_2D, textureId);
        //    Wgl.glTexImage2D(Wgl.GL_TEXTURE_2D, 0, Wgl.GL_RGBA, textureSize.Width, textureSize.Height, 0, Wgl.GL_RGBA, Wgl.GL_UNSIGNED_BYTE, IntPtr.Zero);
        //    Wgl.glBindTexture(Wgl.GL_TEXTURE_2D, 0);

        //    return new GRGlTextureInfo
        //    {
        //        Id = textureId,
        //        Target = Wgl.GL_TEXTURE_2D,
        //        Format = Wgl.GL_RGBA8
        //    };
        //}

        //public override void DestroyTexture(uint texture)
        //{
        //    Wgl.glDeleteTextures(1, new[] { texture });
        //}

        public void GetFramebufferInfo(out int framebuffer, out int samples, out int stencil)
        {
            Wgl.glGetIntegerv(GL_FRAMEBUFFER_BINDING, out framebuffer);
            Wgl.glGetIntegerv(3415, out stencil);
            Wgl.glGetIntegerv(32937, out samples);
        }
    }
}
