using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VisimBox;
using VisimBox.Resources;
using VisimBox.Renderer;
using System.Drawing;
using System.Drawing.Imaging;
using OpenTK.Graphics.OpenGL;

namespace VisimRenderGL
{

    class GLTexture : Texture
    {
        public int GLID;

        public GLTexture(int id, int width, int height, TextureFormat tf, string name, string filename)
        {
            //note!!! require texture format too!
            GLID = id;
            _width = width;
            _height = height;
            _name = name;
            _filename = filename;
            _format = tf;
        }

        public override int InternalID
        {
            get
            {
                return GLID;
            }
        }

        public override void Dispose()
        {
            base.Dispose();
            GLID = -1;
            GL.DeleteTexture(GLID);
        }

        public override void Activate(IRenderContext rc)
        {
            rc.CurrentTexture = this;
            //note, change context directly?
            //note! cache activated texture?

            OpenTK.Graphics.OpenGL.GL.Enable(EnableCap.Texture2D);
            OpenTK.Graphics.OpenGL.GL.BindTexture(OpenTK.Graphics.OpenGL.TextureTarget.Texture2D, GLID);
            if (HasAlpha)
                GL.Enable(EnableCap.Blend);
            else GL.Disable(EnableCap.Blend);
        }

        public override Bitmap GetBitmap()
        {
            if (_format != TextureFormat.RGBA)
            {
                VisimBox.Console.DebugLine("Unsupported type of texture format!");
                //todo - support other formats too!!!
                return null;

            }
            
            GL.BindTexture(TextureTarget.Texture2D, GLID);

            Bitmap bmp = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            
            BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            GL.GetTexImage(TextureTarget.Texture2D, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmp_data.Scan0);
            bmp.UnlockBits(bmp_data);
            return bmp;
        }
    }



    /// <summary>
    /// OpenGL texture manager
    /// </summary>
    class GLTextureMan : TextureManager
    {

        public override void Add(string key, Texture value)
        {
            if (!(value is GLTexture))
            {
                VisimBox.Console.DebugLine("Texture is not GL texture!");
                return;
            }
            base.Add(key, value);
        }

        /// <summary>
        /// Creates new texture from the System.Drawing.Bitmap. Note, doesn't add this to resources.
        /// Use Add(bitmap)
        /// </summary>
        /// <param name="bmp">Bitmap for the texture</param>
        /// <returns>New texture</returns>
        public override Texture CreateTexture(System.Drawing.Bitmap bmp, string name, bool alpha = false)
        {
            int id = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D, id);
            BitmapData bmp_data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bmp_data.Width, bmp_data.Height, 0,
            OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, bmp_data.Scan0);
            bmp.UnlockBits(bmp_data);
            GLTexture glt = new GLTexture(id, bmp.Width, bmp.Height, TextureFormat.RGBA, name, null);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            //GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
            //GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
            return glt;
        }

        public override Texture Load(string key, string filename)
        {
            Texture t = base.Load(key, filename);
            if (t != null)
                return t;

            if (String.IsNullOrEmpty(filename))
            {
                VisimBox.Console.DebugLine("Texture Loader: cannot load file with no name!");
                return null;
            }


            ///NOTE: use image loader later

            System.IO.Stream strm;
            try
            {
                strm = FileSystem.Instance.GetFile(filename);
            }
            catch
            {
                VisimBox.Console.DebugLine("Texture loader: Can't find file " + filename);
                return null;
            }
            
            Bitmap bmp;

            try
            {
                bmp = new Bitmap(strm);
            }
            catch
            {
                VisimBox.Console.DebugLine("Texture loader: Texture loading failed: " + filename);
                return null;
            }

            if (bmp == null)
            {
                VisimBox.Console.DebugLine("Texture loader: Texture loading failed: " + filename);
                return null;
            }

            Texture glt = CreateTexture(bmp, key);
            glt.FileName = filename;
            bmp.Dispose();

            Add(key, glt);

            return glt;
        }
    }
}
