/******************************************************************************
*	File		-	glGraphics.h
*	Author		-	Joey Pollack
*	Date		-	2021/08/30 (y/m/d)
*	Mod Date	-	2021/09/02 (y/m/d)
*	Description	-	An openGL implementation of the engine Graphics interface.
******************************************************************************/

#ifndef OGLGRAPHICS_H_
#define OGLGRAPHICS_H_

#include "../graphics.h"
#include <glad/gl.h>
#include "glShader.h"
#include "glText.h"
#include <assets/types/image.h>
#include <map>
#include <string>


namespace lunarium
{
    class OglGraphics : public IGraphics
    {
    private:	// Interface methods for use only by the engine
		friend Core;

        OglGraphics();

		virtual OpRes Initialize(Window* pWindow, bool enableDebugMessages = true);
		virtual void Shutdown();

		virtual void ResizeCanvas();

		virtual void BeginDraw(int framebuffer = -1);	// -1 means draw to the window/default frame buffer

		/// The image returned by this method is dynamic
		/// and needs to be cleaned up
		virtual Image* EndDraw();

	public:	// 

		virtual void SetClearColor(Color c);
        virtual Color GetClearColor() const;

		virtual int CreateRenderTexture(int width, int height, int channels);
		virtual void DestroyRenderTexture(int texture);

		// Draw Methods
		virtual void DrawFilledPolygon(float* pVerts, int numVerts, Color color, glm::vec2 position, float angle = 0.0f);
		virtual void DrawLine(glm::vec2 point1, glm::vec2 point2, Color color, float lineWidth, float angle = 0.0f);
		virtual void DrawEllipse(glm::vec2 center, glm::vec2 radii, Color color, float thickness, int resolution);
		virtual void DrawFilledEllipse(glm::vec2 center, glm::vec2 radii, Color color, int resolution);
		virtual void DrawBox(Rectangle box, Color color, float thickness, float angle = 0.0f);
		virtual void DrawFilledBox(Rectangle box, Color color, float angle = 0.0f);
		virtual void DrawImage(Image& image, glm::vec2 position, Color color, float angle = 0.0f);
		virtual void DrawImage(Image& image, Rectangle source, Rectangle destination, Color color, float angle = 0.0f);
		virtual void DrawString(const char* string, Rectangle boundingArea, Color color, float scale = 1.0f, int font = 0);

		virtual void RegisterImage(Image& image);

		// Fonts
		int DefaultFont() const;

		// For weight, 400 is normal and 700 is bold
		virtual int CreateNewFont(const char* name, const unsigned char* fontData, int bufferSize, float size = 12.0f, int weight = 400);

    private:    // DATA
        Window* mpWindow;
		glm::mat4 mProjection;

		// Viewport/Framebuffer width and height
		int mFBWidth;
		int mFBHeight;

		// Objects for rendering to texture
		struct FrameBuffer
		{
			Image Texture;
			unsigned char* Buffer;
			unsigned int FBO;
			unsigned int RBO; // for depth and stencil
		};
		std::map<int, FrameBuffer*> mFrameBuffers;
		int mActiveFrameBuffer;

		// TEXT
		glText mText;
        
        // Sprite Data
		unsigned int mImageVAO;
		glShader mImageShader;

        // Shapes
		GLuint mRectVAO;
		GLuint mRectVBO;
		glShader mShapeShader;

		// Ellipse
		GLuint mEllipseVAO;
		GLuint mEllipseVBO;

    private:    // Helper Initializers
    	void InitDebugMsgSystem();
		void InitImageSystem();
		void InitShapeSystem();
		void InitTextureFrameBuffer();

	private: // Helper methods

    private:    // Debug Message System

    friend void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id,
			GLenum severity, GLsizei length, const GLchar* message, const void* userParam);
		static std::map<int, std::string> mDebugMsgTypes;
		static std::map<int, std::string> mDebugMsgSources;
		static std::map<int, std::string> mDebugMsgSeverity;
    };
}

#endif  // OGLGRAPHICS_H_