using System;
using SlatedGameToolkit.Framework.Graphics.OpenGL;
using SlatedGameToolkit.Framework.Graphics.Render;
using SlatedGameToolkit.Framework.Graphics.Window;
using SlatedGameToolkit.Framework.AssetSystem;

namespace SlatedGameToolkit.Framework.Graphics.Textures
{
    public class Texture : IAssetUseable, ITexture {
        public readonly uint width, height;
        private bool disposed;
        private GLContext glContext;
        private uint handle;

        public uint Handle {get { return handle; }}

        public uint Width => width;

        public uint Height => height;

        public bool SingleChanneled => false;

        public bool Flipped => true;

        /// <summary>
        /// Creates an OpenGL Texture2D in the given GL Context.
        /// </summary>
        /// <param name="textureData">The texture data to use to create the Texture2D.</param>
        /// <param name="context">The openGL context to associate this with. If null, will use the currently active context. Defaults to null.</param>
        public unsafe Texture(TextureData textureData, GLContext context = null) {
            this.glContext = context ?? WindowContextsManager.CurrentGL;
            this.width = (uint)textureData.width;
            this.height = (uint)textureData.height;
            uint[] handles = new uint[1];
            glContext.GenTextures(1, handles);
            this.handle = handles[0];
            Use();
            glContext.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
            glContext.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
            glContext.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
            glContext.TexParameteri(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
            fixed(void* p = &textureData.data[0]) {
                glContext.PixelStorei(PixelStoreParameter.UnpackAlignment, 4);
                glContext.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, (uint)textureData.width, (uint)textureData.height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, new IntPtr(p));
            }
            glContext.GenerateMipmap(OpenGL.TextureTarget.Texture2D);
        }

        public void Use() {
            if (disposed) throw new ObjectDisposedException("Texture");
            glContext.BindTexture(OpenGL.TextureTarget.Texture2D, handle);
        }

        public void Dispose()
        {
            if (disposed) return;
            disposed = true;
            glContext.DeleteTextures(1, new uint[] {handle});
            GC.SuppressFinalize(this);
        }

        ~Texture() {
            Dispose();
        }
    }
}