#ifndef _OPENGL_GAME_H
#define _OPENGL_GAME_H

#include <glm/glm.hpp>

// TODO: Rewrite this to work with the new version of IMGUI
#include "IMGUI/imgui.h"
#include "imgui_impl_glfw_gl3.h"

#include "game-gui-glfw.hpp"
#include "graphics-pipeline_opengl.hpp"

// TODO: Figure out if these structs should be defined in the OpenGLGame class

enum ObjectType {
   TYPE_SHIP,
   TYPE_ASTEROID,
   TYPE_LASER,
   TYPE_EXPLOSION,
};

struct SceneObject {
   unsigned int id;
   ObjectType type;
   bool deleted;

   // Currently, model_transform should only have translate, and rotation and scale need to be done in model_base since
   // they need to be done when the object is at the origin. I should change this to have separate scale, rotate, and translate
   // matrices for each object that can be updated independently and then applied to the object in that order.
   // TODO: Actually, to make this as generic as possible, each object should have a matrix stack to support,
   // for instance, applying a rotate, then a translate, then another rotate. Think about and implement the best approach.
   glm::mat4 model_mat, model_base, model_transform;
   glm::mat4 translate_mat; // beginning of doing what's mentioned above
   unsigned int num_points;
   GLuint vertex_vbo_offset;
   GLuint ubo_offset;
   vector<GLfloat> points;
   vector<GLfloat> colors;
   vector<GLfloat> texcoords;
   vector<GLfloat> normals;
   glm::vec3 bounding_center;
   GLfloat bounding_radius;
};

struct ParticleEffect : SceneObject {
   vector<GLfloat> particleVelocities;
   vector<GLfloat> particleTimes;
   GLfloat startTime;
   GLfloat duration;
};

class OpenGLGame {
   public:
      OpenGLGame();
      ~OpenGLGame();

      void run(int width, int height, unsigned char guiFlags);

   private:
      GameGui* gui;
      Viewport viewport;

      vector<GraphicsPipeline_OpenGL> graphicsPipelines;

      GLFWwindow* window;

      bool initWindow(int width, int height, unsigned char guiFlags);
      void initOpenGL();
      void mainLoop();
      void renderScene();
      void renderUI();
      void cleanup();
};

void APIENTRY opengl_debug_callback(
   GLenum source,
   GLenum type,
   GLuint id,
   GLenum severity,
   GLsizei length,
   const GLchar* message,
   const void* userParam
);

#endif // _OPENGL_GAME_H