/**
 *
 * @file src/render/Geometry.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Mathieu Faverge
 * @author Thibault Soucarre
 * @author Olivier Lagrasse
 *
 * @date 2024-07-17
 */
/*!
 *\file Geometry.cpp
 */

#include <algorithm> /* for min and max functions */
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
/* -- */
#include "render/Geometry.hpp"

using namespace std;

#define message *Message::get_instance() << "(" << __FILE__ << " l." << __LINE__ << "): "

/***********************************
 *
 *
 *
 * Constructor and destructor.
 *
 *
 *
 **********************************/

Geometry::Geometry() {

    init_geometry();

    /* Camera is placed on (0,0,0) and looks to (0,0,-1) */

    _z_ruler = -0.5;
    _z_ruler_over = -0.4;
    _z_ruler_under = -0.6;
    _z_container = -1.0;
    _z_container_under = -1.2;
    _z_state = -5.0;
    _z_event = -2.0; /* closer to camera than containers or states (MUST be negative)*/
    _z_arrow = -3.0; /* closer to camera than containers or states (MUST be negative)*/
    _z_counter = -4.0;
    _ruler_distance = 0.0;
}

Geometry::~Geometry() = default;

/***********************************
 *
 *
 *
 * Init function.
 *
 *
 *
 ***********************************/

void Geometry::init_geometry() {

    _counter_last_x = 0.0;
    _counter_last_y = 0.0;

    /* init main information about OpenGL scene and QGLWidget size */
    _x_scale_container_state = 0.2; /* 20% of screen is used for containers then the other part for states */

    _ruler_height = 8.5; /* height of the ruler   */
    _ruler_y = 0.0; /* highness of the ruler */

    _default_entity_x_translate = 20; /* Info::Render::width * _x_scale_container_state */

    _state_y_max = 0;
    _state_y_min = 0;

    _x_state_scale = 1; /* for states scaling */
    _x_state_translate = 0; /* for states translation */
    _y_state_scale = 1; /* for states scaling */
    _y_state_translate = 0; /* for states translation */
}

/***********************************
 *
 *
 *
 * Coordinate convert functions.
 *
 *
 *
 **********************************/

Element_pos Geometry::screen_to_render_x(Element_pos e) const {

    return e * coeff_screen_render_x();
}

Element_pos Geometry::screen_to_render_y(Element_pos e) const {

    return e * coeff_screen_render_y();
}

Element_pos Geometry::render_to_trace_x(Element_pos e) const {
    return (e - _default_entity_x_translate + _x_state_translate) / coeff_trace_render_x();
}

Element_pos Geometry::render_to_trace_y(Element_pos e) const {

    return (e - _ruler_y - _ruler_height + _y_state_translate) / coeff_trace_render_y();
}

Element_pos Geometry::render_to_screen_x(Element_pos e) const {

    return e / coeff_screen_render_x();
}

Element_pos Geometry::render_to_screen_y(Element_pos e) const {

    return e / coeff_screen_render_y();
}

Element_pos Geometry::trace_to_render_x(Element_pos e) const {

    return e * coeff_trace_render_x() + _default_entity_x_translate - _x_state_translate;
}

Element_pos Geometry::trace_to_render_y(Element_pos e) const {

    return e * coeff_trace_render_y() + _ruler_y + _ruler_height - _y_state_translate;
}

Element_pos Geometry::coeff_screen_render_x() const {
    return Info::Render::width / (Element_pos)Info::Screen::width;
}

Element_pos Geometry::coeff_screen_render_y() const {
    return Info::Render::height / (Element_pos)Info::Screen::height;
}

Element_pos Geometry::coeff_trace_render_x() const {

    return ((Info::Render::width - _default_entity_x_translate) * _x_state_scale) / (Info::Entity::x_max - Info::Entity::x_min);
}

Element_pos Geometry::coeff_trace_render_y() const {

    return ((Info::Render::height - _ruler_height) * _y_state_scale) / (Info::Container::y_max - Info::Container::y_min);
}

void Geometry::update_visible_interval_value() const {
    Info::Render::_x_min_visible = max(Info::Entity::x_min, (_x_state_translate - _default_entity_x_translate) / coeff_trace_render_x());
    Info::Render::_x_min = max(Info::Entity::x_min, _x_state_translate / coeff_trace_render_x());
    Info::Render::_x_max = (_x_state_translate - _default_entity_x_translate + Info::Render::width) / coeff_trace_render_x();
    Info::Render::_x_max_visible = min(Info::Entity::x_max, (_x_state_translate - _default_entity_x_translate + Info::Render::width) / coeff_trace_render_x());
}
