﻿using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using System;
using System.Drawing;

namespace OpenTKEngine
{
    public class Graphics
    {
        public enum RenderMode
        {
            _3D, _2D
        }

        private static RenderMode renderMode = RenderMode._2D;
        private static int projectionWidth, projectionHeight;
        private static BitmapFont currentFont;

        public static void SetRenderMode(RenderMode mode)
        {
            if (renderMode != mode)
            {
                renderMode = mode;
                LoadProjection(projectionWidth, projectionHeight);
            }
        }

        public static RenderMode GetRenderMode()
        {
            return renderMode;
        }

        public static void LoadProjection(int width, int height)
        {
            Matrix4 projection;
            projectionWidth = width;
            projectionHeight = height;
            if (renderMode == RenderMode._3D)
            {
                projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, width / (float)height, 1.0f,
                    1000.0f);
            }
            else
            {
                projection = Matrix4.CreateOrthographicOffCenter(0, width, height, 0, -1000f, 1000f);
            }
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadMatrix(ref projection);
        }

        public static void Clear()
        {
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();
            GL.Color4(Color4.White);
        }

        public static void SetFont(BitmapFont font)
        {
            currentFont = font;
        }

        public static BitmapFont GetFont()
        {
            return currentFont;
        }

        public static void DrawText(String text, float x, float y, float z, Color4 color)
        {
            currentFont.RenderText(text, x, y, z, color);
        }

        public static void DrawTexture(Texture texture, Vector3 dest, Color4 color)
        {
            DrawTexture(texture, dest.X, dest.Y, dest.Z, texture.GetWidth(), texture.GetHeight(), 0, 0,
                texture.GetWidth(), texture.GetHeight(),
                0, 0, 0, 0, 0, 0, color);
        }

        public static void DrawTexture(Texture texture, Vector3 dest, Vector3 offset, Vector3 rotation, Color4 color)
        {
            DrawTexture(texture, dest.X, dest.Y, dest.Z, texture.GetWidth(), texture.GetHeight(), 0, 0,
                texture.GetWidth(), texture.GetHeight(),
                offset.X, offset.Y, offset.Z, rotation.X, rotation.Y, rotation.Z, color);
        }

        public static void DrawTexture(Texture texture, Vector3 dest, Vector2 dim, Vector3 offset, Vector3 rotation,
            Color4 color)
        {
            DrawTexture(texture, dest.X, dest.Y, dest.Z, dim.X, dim.Y, 0, 0, texture.GetWidth(), texture.GetHeight(),
                offset.X, offset.Y, offset.Z, rotation.X, rotation.Y, rotation.Z, color);
        }

        public static void DrawTexture(Texture texture, Vector3 dest, Vector2 dim, Vector2 src, Vector2 srcDim,
            Vector3 offset, Vector3 rotation, Color4 color)
        {
            DrawTexture(texture, dest.X, dest.Y, dest.Z, dim.X, dim.Y, src.X, src.Y, srcDim.X, srcDim.Y,
                offset.X, offset.Y, offset.Z, rotation.X, rotation.Y, rotation.Z, color);
        }

        public static void DrawTexture(Texture texture, Rectangle dest, Rectangle source, Vector3 offset, Vector3 rotation, Color4 color)
        {
            DrawTexture(texture, dest, 0, source, offset, rotation, color);
        }

        public static void DrawTexture(Texture texture, Rectangle dest, float z, Rectangle source, Vector3 offset, Vector3 rotation, Color4 color)
        {
            DrawTexture(texture, dest.X, dest.Y, z, dest.Width, dest.Height, source.X, source.Y, source.Width, source.Height, 
                        offset.X, offset.Y, offset.Z, rotation.X, rotation.Y, rotation.Z, color);
        }

        public static void DrawTexture(Texture texture, float dX, float dY, float dZ, float dW, float dH,
            float tX, float tY, float tW, float tH, float oX, float oY, float oZ,
            float pitch, float yaw, float roll, Color4 color)
        {
            GL.Color4(color);
            texture.Bind();

            float tx = tX/texture.GetWidth();
            float ty = tY/texture.GetHeight();
            float tw = tW/texture.GetWidth();
            float th = tH/texture.GetHeight();

            GL.PushMatrix();
            {
                GL.Translate(dX, dY, dZ);
                GL.Rotate(pitch, Vector3d.UnitX);
                GL.Rotate(yaw, Vector3d.UnitY);
                GL.Rotate(roll, Vector3d.UnitZ);
                if (renderMode == RenderMode._3D)
                {
                    GL.Begin(PrimitiveType.Quads);
                    {
                        GL.TexCoord2(tx + tw, ty + th);
                        GL.Vertex3(0 + oX, 0 + oY, 0 + oZ);
                        GL.TexCoord2(tx, ty + th);
                        GL.Vertex3(dW + oX, 0 + oY, 0 + oZ);
                        GL.TexCoord2(tx, ty);
                        GL.Vertex3(dW + oX, dH + oY, 0 + oZ);
                        GL.TexCoord2(tx + th, ty);
                        GL.Vertex3(0 + oX, dH + oY, 0 + oZ);
                    }
                    GL.End();
                }
                else
                {
                    GL.Begin(PrimitiveType.Quads);
                    {
                        GL.TexCoord2(tx, ty);
                        GL.Vertex3(0 + oX, 0 + oY, 0 + oZ);
                        GL.TexCoord2(tx + tw, ty);
                        GL.Vertex3(dW + oX, 0 + oY, 0 + oZ);
                        GL.TexCoord2(tx + tw, ty + th);
                        GL.Vertex3(dW + oX, dH + oY, 0 + oZ);
                        GL.TexCoord2(tx, ty + th);
                        GL.Vertex3(0 + oX, dH + oY, 0 + oZ);
                    }
                    GL.End();
                }
            }
            GL.PopMatrix();
            Texture.BindNone();
        }

        // Primitives
        public static void DrawLine(Vector3 start, Vector3 end, Color4 color)
        {
            Texture.BindNone();
            GL.Color4(color);

            GL.Begin(PrimitiveType.Lines);
            {
                GL.Vertex3(start);
                GL.Vertex3(end);
            }
            GL.End();
        }

        public static void DrawCircle(Vector3 center, float radius, Color4 color)
        {
            GL.PushMatrix();
            GL.Color4(color);
            GL.Begin(PrimitiveType.LineLoop);
            for (int i = 0; i < 360; i++)
            {
                float degInRad = MathHelper.DegreesToRadians(i);
                GL.Vertex2(center.X + Math.Cos(degInRad) * radius,center.Y + Math.Sin(degInRad) * radius);
            }

            GL.End();
            GL.PopMatrix();
        }

        public static void DrawRectangle(Vector3 position, Vector2 dimension, Color4 color)
        {
            DrawRectangle(position.X, position.Y, position.Z, dimension.X, dimension.Y, color);
        }

        public static void DrawRectangle(float x, float y, float z, float width, float height, Color4 color)
        {
            GL.Color4(color);
            GL.Begin(PrimitiveType.Quads);
            GL.Vertex3(x, y, z);
            GL.Vertex3(x + width, y, z);
            GL.Vertex3(x + width, y + height, z);
            GL.Vertex3(x, y + height, z);
            GL.End();
        }
    }
}