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

#include <cmath>
#include <sstream>
/* -- */
#include "common/common.hpp"
#include "common/Info.hpp"
/* -- */
#include "render/Ruler.hpp"

using namespace std;

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

/***********************************
 *
 *
 *
 * Ruler methods.
 *
 *
 *
 **********************************/

Element_pos Ruler::get_graduation_diff(const Element_pos min, const Element_pos max) {
    Element_pos diff;
    char step;
    Element_pos adjust;
    char security_counter;

    diff = max - min;
    adjust = 1;
    step = 0;
    security_counter = 0;

    if (diff == 0.0)
        return 0.0;

    while ((diff > 100) && (security_counter < 20)) {
        diff /= 10;
        adjust *= 10;
        security_counter++;
    }

    /* It is not necessary to reinitialize security_counter */

    while ((diff < 10) && (security_counter < 20)) {
        diff *= 10;
        adjust /= 10;
        security_counter++;
    }

    diff /= 10; /* Now, diff is within [1;10] */

    if (diff > 7) { /* Check within ] 7 ; 10 ] */
        step = 10; /* 10 trace units between each graduation */
    }
    else // if (diff > 3){/* Check within ] 3 ; 7 ] */
        step = 5; /* 5 trace units between each graduation */

    // }else //if (diff > 1){/* Check within ] 1 ; 3 ] */
    //    step = 2;/* 2 trace units between each graduation */

    // }else{
    //     step = 1;/* 1 trace unit between each graduation */
    // }

    return step * adjust;
}

string Ruler::get_common_part_string(const Element_pos &first_pos, const Element_pos &second_pos) {
    // Confert float (Element_pos) to string
    std::string first_string = std::to_string(first_pos);
    std::string second_string = std::to_string(second_pos);

    // If the strings have not the same integer part length
    if (first_string.find_first_of('.') != second_string.find_first_of('.')) {
        return "";
    }

    int min_length = min(first_string.size(), second_string.size());

    int index_first_diff = 0;
    while (index_first_diff < min_length && first_string[index_first_diff] == second_string[index_first_diff]) {
        index_first_diff++;
    }

    return first_string.substr(0, index_first_diff);
}

string Ruler::get_variable_part(const Element_pos &graduation_pos, const std::string &common_part_string, const std::size_t &length_after_point) {

    std::ostringstream buf_txt;
    buf_txt.str(""); /* flush the buffer */

    // Display graduation text
    std::size_t length_common_part = common_part_string.size();

    // Take i -> Shift it to the left -> Round it -> Take integer value -> Convert to string
    // Rounding prevents float error which could lead to .399999 instead of .4 for exemple
    // It is easier to transform i into an integer while keeping precision
    std::string round_i_string = std::to_string(int(round(graduation_pos * pow(10, length_after_point))));

    // Base value is zero, it could be discarded during the left shift
    std::string integer_part = "0";

    // The the first 'size - length_after_point' digits are the integer part
    if (round_i_string.size() >= length_after_point) {
        integer_part = round_i_string.substr(0, round_i_string.size() - length_after_point);
    }

    // If the common part does not contain the entire integer part
    // -> Display the integer part that is not in common
    if (integer_part.size() >= length_common_part) {
        buf_txt << integer_part.substr(length_common_part);
    }

    // If there is numbers to show after the floating point
    if (length_after_point > 0) {

        // If an interger part was shown, writes a point, because there are digits after the point
        if (integer_part.size() >= length_common_part) {
            buf_txt << '.';
        }

        // Compute the number of digits displayed after the float point
        int displayed_digits_after_point = 0;
        if (common_part_string.find_first_of('.') != std::string::npos) {
            displayed_digits_after_point = common_part_string.size() - common_part_string.find_first_of('.') - 1;
        }

        if (round_i_string.size() >= length_after_point) {
            // The last 'length_after_point' digits are the float part
            buf_txt << round_i_string.substr(round_i_string.size() - length_after_point + displayed_digits_after_point);
        }
        else { // For small number there is a padding with '0'
            buf_txt << std::string(length_after_point - round_i_string.size() - displayed_digits_after_point, '0');
            buf_txt << round_i_string;
        }
    }

    return buf_txt.str();
}
