#include "renderer.hpp"

#include <list>

#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtc/random.hpp>
#include <glm/vec3.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "glclasses.hpp"

#include "game.hpp"

#include "state/trace.hpp"
#include "state/object.hpp"
#include "state/missile.hpp"
#include "state/player.hpp"
#include "state/planet.hpp"
#include "state/ship.hpp"
#include "state/explosion.hpp"

#include "particle_batch.hpp"
#include "polygon_model.hpp"
#include "image_texture.hpp"

namespace endofthejedi {

    class RendererPolygon3d : public Renderer {
        public:
            void setup();
            void render(const game::State *state) override;

            void setWindowSize(int px, int py);
            void setCameraMatrix(const glm::mat4 &cam);

        private:
            void renderPlanets();
            void renderMissiles();
            void renderShips();
            void renderParticles();

            void addModel(const std::string &filename, PolygonModel **dest);

            void addExplosionEffect(
                    size_t id, const glm::vec2 &pos, const glm::vec2 &missileVelocity,
                    bool hitPlanet,
                    size_t n, float duration);

            void advanceGraphicObjects(float dt);

            // shortcuts which use the lower versions
            glm::mat4 computeModelMatrix(const game::Planet  *planet);
            glm::mat4 computeModelMatrix(const game::Missile *missile);
            glm::mat4 computeModelMatrix(const game::Ship    *ship);

            // do the actual computation with these values
            glm::mat4 computeModelMatrix(const glm::vec2 &pos, float scale, float angle=0.0);

            void renderTraces();

            void configureLightningInShader(Shader *shader) const;

            void renderBackgroundImage();

        private:
            // all models are also here (for easy reloading etc.)
            std::vector<PolygonModel*>  m_models;

            // and with a specific variable name here
            PolygonModel               *m_missileModel;
            PolygonModel               *m_planetModel;
            PolygonModel               *m_shipModel;

            // for rendering everything
            Shader m_shader_background;
            Shader m_shader_game_objects;
            Shader m_shader_particles;

            // for accessing
            const game::State *m_state;

            std::list<ParticleBatch*> m_particles;

            // time value for last rendering cycle (-1 after setup/startup)
            float m_lastTime;

            float m_aspectRatio;

            // TODO: put representation specialized for rendering in here
            std::list<const game::Missile*> m_missiles;
            std::list<const game::Ship*>    m_ships;

            ImageTexture *m_texture;
    };
}
