#include "../../device/device.h"
#include "../../library/glm/detail/func_geometric.hpp"
#include "../../library/glm/gtc/matrix_transform.hpp"
#include "../../library/glm/gtc/type_ptr.hpp"
#include "camera.h"

/**
 * TODO remove ogl include
 */


#include "GL/gl.h"

namespace sleek
{
    namespace scene3d
    {
        namespace camera
        {
            Camera::Camera(device::Device *dev) noexcept : screen(dev)
            {
                frust = new Frustum();

                fars  = 2500.f;
                nears = 0.1f;
                fovs  =  45.f;
                asps  = (f32)screen->getInfo().size.x/(f32)screen->getInfo().size.y;
                mode = CVM_PERSPECTIV;
//                mode = CVM_ORTHOGRAPHIC;
                updatePerspective();
                updateProjection();
            }

            Camera::~Camera() noexcept
            {
                delete frust;
            }

            bool Camera::manage(device::input*) noexcept
            {
            }

            void Camera::setFovValue(const f32 i) noexcept
            {
                fovs = i;
            }

            void Camera::setFarValue(const f32 i) noexcept
            {
                fars = i;
            }

            void Camera::setNearValue(const f32 i) noexcept
            {
                nears = i;
            }

            void Camera::setAspectRatio(const f32 i) noexcept
            {
                asps = i;
            }

            void Camera::setViewMode(const CAMERA_VIEW_MODE i) noexcept
            {
                mode = i;
            }

            void Camera::setTarget(const math::vector3df &i) noexcept
            {
                tar = i;
            }

            void Camera::setPosition(const math::vector3df &i) noexcept
            {
                pos = i;
            }

            void Camera::setRotation(const math::vector3df &i) noexcept
            {
                rot = i;
            }

            math::aabbox2di Camera::getViewPort() const noexcept
            {
                return viewport;
            }

            math::vector3df Camera::getPosition() const noexcept
            {
                return pos;
            }

            math::vector3df Camera::getRotation() const noexcept
            {
                return rot;
            }

            math::vector3df Camera::getTarget() const noexcept
            {
                return tar;
            }

            CAMERA_VIEW_MODE Camera::getViewMode() const noexcept
            {
                return mode;
            }

            Frustum* Camera::getViewFrustum() const noexcept
            {
                return frust;
            }

            f32 Camera::getAspectRatio() const noexcept
            {
                return asps;
            }

            f32 Camera::getNearValue() const noexcept
            {
                return nears;
            }

            f32 Camera::getFarValue() const noexcept
            {
                return fars;
            }

            f32 Camera::getFovValue() const noexcept
            {
                return fovs;
            }

            void Camera::render() noexcept
            {
                glMatrixMode(GL_PROJECTION);
                glLoadMatrixf(glm::value_ptr(pers*proj));
                glMatrixMode(GL_MODELVIEW);
                glLoadIdentity();
            }

            void Camera::updatePerspective() noexcept
            {
                pers = {
                    mode != CVM_ORTHOGRAPHIC ?
                    glm::perspective<f32>(fovs, asps, nears, fars) :
                    glm::ortho<f32>(
                        -screen->getInfo().size.x/2, screen->getInfo().size.x/2,
                        -screen->getInfo().size.y/2, screen->getInfo().size.y/2,
                        nears, fars
                    )
                };
            }

            void Camera::updateProjection() noexcept
            {
                eye = pos;
                cen = tar;
                up = normalize(rot);
                proj = glm::lookAt(eye, cen, up);
            }
        }
    }
}