using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VisimBox.Renderer;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics;
using OpenTK.Platform;
using OpenTK;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace VisimRenderGL
{
    public class RenderPlugin : Renderer
    {


        public override void Initialize(RenderContextSettings settings)
        {
            if (initialized)
            {
                return;
            }

            VisimBox.Console.WriteLine("Initializing OpenGL Renderer, creating managers...");

            //note!!! add texman to resource managers?
            base.TexMan = new GLTextureMan();
            _FontMan = new VisimBox.Renderer.Render2D.FontManager();
            _VertexMan = new GLVertexBufferManager();
            _IndexMan = new GLIndexManager();
            _MeshMan = new GLMeshManager();
            _MaterialMan = new GLMaterialMan(this);
            _LightMan = new GLLightMan();

            VisimBox.Console.WriteLine("OpenGL Renderer initialized...");
            base.Initialize(settings);
        }

        protected override IRenderContext CreateNewContext(RenderContextSettings settings)
        {
            VisimBox.Console.WriteLine("Creating new render context...");

            if (settings.Window == null)
            {
                BaseRenderWindow brw = new BaseRenderWindow(settings);
                brw.Show();
            }

            System.Windows.Forms.Control userwin = (Control)settings.Window;
            GLControl glc = new GLControl();
            glc.Parent = userwin;
            glc.Dock = DockStyle.Fill;
            glc.Visible = true;
            GLRenderContext glrc = new GLRenderContext(this, settings, glc);
            settings.Window.AttachContext(glrc, glc);
            VisimBox.Console.WriteLine("Render context created.");
            return glrc;        
        }

        public override bool IsIdle()
        {
            foreach (var rc in rContexts)
            {
                GLRenderContext glrc = (GLRenderContext)rc;
                OpenTK.GLControl glc = (OpenTK.GLControl)glrc.RenderControl;
                if (glc.IsIdle)
                    return true;
            }
            return false;
        }

        #region linux stuff and experiments

/*
        protected IRenderContext CreateNewContext2(RenderContextSettings settings)
        {
            if (settings.Window == null)
                throw;

            IWindowInfo iw = null;

            if (Configuration.RunningOnWindows)
            {
                iw = Utilities.CreateWindowsWindowInfo(settings.Window.Handle);
            }
            else if (Configuration.RunningOnMacOS)
            {
                iw = Utilities.CreateMacOSCarbonWindowInfo(settings.Window.Handle, false, true);
            }
            else if (Configuration.RunningOnX11)
            {
                iw = CreateX11Context(settings);
            }
            else throw new PlatformNotSupportedException();

            IGraphicsContext igc = new GraphicsContext(GraphicsMode.Default, iw);

            if (!initialized)
            {
                igc.MakeCurrent(iw);
                GL.LoadAll();
                initialized = true;
            }

            GLRenderContext glrc = new GLRenderContext(this, igc, iw);

            //settings.Window.AttachContext(glrc);
            return glrc;
        }

        static void SetStaticFieldValue(Type type, string fieldName, object value)
        {
            type.GetField(fieldName,
                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).SetValue(null, value);
        }

        static object GetStaticFieldValue(Type type, string fieldName)
        {
            return type.GetField(fieldName,
                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
        }

        [StructLayout(LayoutKind.Sequential)]
        struct XVisualInfo
        {
            public IntPtr Visual;
            public IntPtr VisualID;
            public int Screen;
            public int Depth;
            public int Class;
            public long RedMask;
            public long GreenMask;
            public long blueMask;
            public int ColormapSize;
            public int BitsPerRgb;

            public override string ToString()
            {
                return String.Format("id ({0}), screen ({1}), depth ({2}), class ({3})",
                    VisualID, Screen, Depth, Class);
            }
        }

        [DllImport("libX11")]
        static extern IntPtr XCreateColormap(IntPtr display, IntPtr window, IntPtr visual, int alloc);

        [DllImport("libX11", EntryPoint = "XGetVisualInfo")]
        static extern IntPtr XGetVisualInfoInternal(IntPtr display, IntPtr vinfo_mask, ref XVisualInfo template, out int nitems);

        static IntPtr XGetVisualInfo(IntPtr display, int vinfo_mask, ref XVisualInfo template, out int nitems)
        {
            return XGetVisualInfoInternal(display, (IntPtr)vinfo_mask, ref template, out nitems);
        }

        static IWindowInfo CreateX11Context(RenderContextSettings settings)
        {
            //Note: taken from openTK - probably won't work

            Type xplatui = Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms");
            if (xplatui == null) throw new PlatformNotSupportedException();

            IntPtr display = (IntPtr)GetStaticFieldValue(xplatui, "DisplayHandle");
            IntPtr rootWindow = (IntPtr)GetStaticFieldValue(xplatui, "RootWindow");
            int screen = (int)GetStaticFieldValue(xplatui, "ScreenNo");

            // get the XVisualInfo for this GraphicsMode
            XVisualInfo info = new XVisualInfo();

            GraphicsMode gm = new GraphicsMode();
            info.VisualID = gm.Index.Value;
            int dummy;
            IntPtr infoPtr = XGetVisualInfo(display, 1 , ref info, out dummy);
            info = (XVisualInfo)Marshal.PtrToStructure(infoPtr, typeof(XVisualInfo));

            // set the X11 colormap.
            SetStaticFieldValue(xplatui, "CustomVisual", info.Visual);
            SetStaticFieldValue(xplatui, "CustomColormap", XCreateColormap(display, rootWindow, info.Visual, 0));

            return Utilities.CreateX11WindowInfo(display, screen, settings.Window.Handle, rootWindow, infoPtr);
        }

        */

        #endregion
    }
}
