#ifndef VIS_ENGINE_CAMERA_HPP
#define VIS_ENGINE_CAMERA_HPP

#include "point.hpp"
#include "vector.hpp"
#include "mesh.hpp"
#include <vector>

namespace visual_engine {
namespace detail {

class camera final {
    struct grid {
        int cols_;
        int rows_;
        std::vector<vector> vec_grid_;
        coord_t viewport_distance_;
    };

    point  pos_;
    vector dir_x_;
    vector dir_y_;
    grid   grid_;
    std::string frame_buffer_;
    std::vector<mesh> *objects_ = nullptr;

public:
    static constexpr coord_t pixel_size_x = (coord_t)1;
    static constexpr coord_t pixel_size_y = (coord_t)2;

    camera(int cols_term, int rows_term, point pos = {0,0,0}, vector dirx = {0,-1,0}, vector diry = vector{0,0,1}.normalized(),
           coord_t vp_dist = 1) : pos_(pos), dir_x_(dirx.normalized()), dir_y_(diry.normalized()) {
        if (!cols_term || !rows_term) throw; // @TODO exception
        grid_.cols_ = cols_term;
        grid_.rows_ = rows_term;
        grid_.viewport_distance_ = vp_dist;
        grid_.vec_grid_.reserve( cols_term      * rows_term);
        frame_buffer_  .reserve((cols_term/* + 1*/) * rows_term);

        coord_t y_size = rows_term * pixel_size_y;
        coord_t x_size = cols_term * pixel_size_x;
        vector  y_step = dir_y_ * ((coord_t)1        / rows_term);
        vector  x_step = dir_x_ * ((x_size / y_size) / cols_term);
        vector dirz = dir_y_.product(dir_x_);
        vector begin_vec = (dirz   *  vp_dist)                     -
                           (x_step * ((coord_t)(cols_term-1) / 2)) +
                           (y_step * ((coord_t)(rows_term-1) / 2));
        for (int i = 0; i != rows_term; ++i)
            for (int j = 0; j != cols_term; ++j)
                grid_.vec_grid_.push_back((begin_vec + j*x_step - i*y_step).normalized());
    }

    void console_dump() const;
    void render();
    void show() const;
    void set_objects(std::vector<mesh> *obj) { objects_ = obj; }
    void move(const vector& v);

private:
    double get_best_intersection_scene(const vector& v) const;
    static char get_ascii_for_cos(double t);
};

// @TODO exception

} // namespace detail
} // namespace visual_engine

#endif // VIS_ENGINE_CAMERA_HPP
