/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A license under French law
** and abiding by the rules of distribution of free software. You can
** use, modify and/or redistribute the software under the terms of the
** CeCILL-A license as circulated by CEA, CNRS and INRIA at the following
** URL: "http://www.cecill.info".
**
** As a counterpart to the access to the source code and rights to copy,
** modify and redistribute granted by the license, users are provided
** only with a limited warranty and the software's author, the holder of
** the economic rights, and the successive licensors have only limited
** liability.
**
** In this respect, the user's attention is drawn to the risks associated
** with loading, using, modifying and/or developing or reproducing the
** software by the user in light of its specific status of free software,
** that may mean that it is complicated to manipulate, and that also
** therefore means that it is reserved for developers and experienced
** professionals having in-depth computer knowledge. Users are therefore
** encouraged to load and test the software's suitability as regards
** their requirements in conditions enabling the security of their
** systems and/or data to be ensured and, more generally, to use and
** operate it in the same conditions as regards security.
**
** The fact that you are presently reading this means that you have had
** knowledge of the CeCILL-A license and that you accept its terms.
**
**
** ViTE developers are (for version 0.* to 1.0):
**
**        - COULOMB Kevin
**        - FAVERGE Mathieu
**        - JAZEIX Johnny
**        - LAGRASSE Olivier
**        - MARCOUEILLE Jule
**        - NOISETTE Pascal
**        - REDONDY Arthur
**        - VUCHENER Clément
**
*/
/*!
 *\file DrawVDiagram.hpp
 */

#ifndef DRAW_VDIAGRAM_HPP
#define DRAW_VDIAGRAM_HPP

/*!
 * \class DrawVDiagram
 * \brief Browse the stats and call back T drawing methods
 */
template<class T>
class DrawVDiagram : public DrawStats<T> {

public:
    /*
     * \brief The default constructor
     */
    DrawVDiagram() {
        this->_size_for_one_container = _HEIGHT_FOR_ONE_CONTAINER_DEFAULT;
        set_geometrical_informations();
    }


    /*!
     * \brief The destructor
     */
    ~DrawVDiagram() override = default;


    /*!
     * \fn build(T* draw_object, std::vector<Container *> containers_to_print)
     * \brief The trace building function.
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
     * \param containers_to_print the container's data
     */
    void build(T* draw_object, std::vector<Container *> containers_to_print) override {

        draw_object->clear();

        this->_size_for_one_container = draw_object->height();

        this->_containers_to_print = containers_to_print;
        const int number_of_containers = this->_containers_to_print.size();
        draw_object->start_draw();
        draw_object->set_total_height((number_of_containers-1)*this->_size_for_one_container);

        for(int i = 0 ; i < number_of_containers ; i ++) {
            draw_container_name(draw_object, i);

            draw_diagram(draw_object, i);

            draw_legend(draw_object, i);
        }
        this->set_geometrical_informations_object(draw_object);
        this->end_draw(draw_object);
    }

    /*!
     * \fn draw_container_name(T* draw_object, const int container_id) const
     * \brief Print the i-th container name
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
     * \param container_id the id of the container.
     */
    virtual void draw_container_name(T* draw_object, const int container_id) const {
        // Get the position for the i-th container name

        const Element_pos pos_x = this->_pos_x_container_name;
        const Element_pos pos_y = this->_size_for_one_container*(container_id+1)-this->_pos_y_container_name;
        const std::string name = this->_containers_to_print[container_id]->get_Name().to_string();


        draw_object->draw_text(pos_x, pos_y, name);
    }

    /*!
     * \fn draw_diagram(T* draw_object, const int container_id)
     * \brief Print the i-th diagram
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
     * \param container_id the id of the container.
     */
    virtual void draw_diagram(T* draw_object, const int container_id) {
        Statistic *stat_temp = new Statistic();
        this->_containers_to_print[container_id]->fill_stat(stat_temp, Interval(this->_start_time, this->_end_time));
        std::map<const EntityValue*, stats*> temp_states = stat_temp->get_states();
        this->_states.push_back(temp_states);

        // Printing of the trace

        int pos_x = _START_HISTOGRAM_X_DEFAULT;
        int pos_y = _START_HISTOGRAM_Y_DEFAULT - container_id*this->_size_for_one_container;
        const double max_percentage = get_max_percentage(temp_states);
        // Draw axes
        draw_object->draw_axis(pos_x, pos_y, _WIDTH_HISTOGRAM_DEFAULT*(this->_states[container_id].size()+1), this->_percentage_height_default*100);

        draw_object->draw_text(pos_x-35,
                               this->_size_for_one_container-(pos_y+this->_percentage_height_default*100-5),
                               QString::number(max_percentage*100., 'g', 3).toStdString()+"%");

        draw_object->draw_horizontal_line(pos_x, pos_y+this->_percentage_height_default*100, _WIDTH_HISTOGRAM_DEFAULT*(this->_states[container_id].size()+1));


        // Draw the stats
        for (auto & temp_state : temp_states) {

            // We have to convert the percentage in a rectangle and print it
            const double length = temp_state.second->_total_length;
            const double height = length*100.*this->_percentage_height_default/(this->_end_time-this->_start_time);

            // We search for a color
            if(temp_state.first->get_extra_fields()->find(std::string("Color")) != temp_state.first->get_extra_fields()->end()) {
                const Color *color = (const Color *)temp_state.first->get_extra_fields()->find(std::string("Color"))->second;
                draw_object->draw_rect(pos_x, pos_y, _WIDTH_HISTOGRAM_DEFAULT, height/max_percentage, color->get_red(), color->get_green(), color->get_blue());
            }
            else {
                draw_object->draw_rect(pos_x, pos_y, _WIDTH_HISTOGRAM_DEFAULT, height/max_percentage, 0.7f, 0.7f, 0.75f);
            }

            // We print the percentage above
            draw_object->draw_text(pos_x,
                                   this->_size_for_one_container-(pos_y+height/max_percentage+1),
                                   QString::number(length/(this->_end_time-this->_start_time)*100., 'f', 1).toStdString()+"%");

            pos_x += _WIDTH_HISTOGRAM_DEFAULT;
        }

        // We check for the width
        if(pos_x > this->_max_width){
            this->_max_width = pos_x;
        }

        delete stat_temp;
    }

    /*!
     * \fn draw_legend(T* draw_object, const int container_id)
     * \brief Print the legend for the i-th element (eg the color of each stats)
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
     * \param container_id the id of the container.
     */
    virtual void draw_legend(T* draw_object, const int container_id) {
        Element_pos pos_x = _POS_X_CONTAINER_NAME + _POS_X_LEGEND_DEFAULT;
        Element_pos pos_y = this->_size_for_one_container * (container_id+1) - _POS_Y_LEGEND_DEFAULT;
        const double w = this->_width_for_rect_legend;
        const double h = this->_height_for_rect_legend;

        /* used to print legend on 3 rows */
        int decalage = 0;

        for (std::map<const EntityValue *, stats *>::iterator it = this->_states[container_id].begin();
             it != this->_states[container_id].end();
             it ++, decalage ++) {

            std::string name = (*it).first->get_name();

            // We cut the name to don't exceed the place
            draw_object->draw_text(pos_x+w+_POS_X_LEGEND_DEFAULT, pos_y, name.substr(0, 10));

            if((*it).first->get_extra_fields()->find(std::string("Color")) != (*it).first->get_extra_fields()->end()) {
                const Color *color = (const Color *)(*it).first->get_extra_fields()->find(std::string("Color"))->second;
                draw_object->draw_rect(pos_x, this->_size_for_one_container-pos_y, w, h, color->get_red(), color->get_green(), color->get_blue());
            }
            else {
                draw_object->draw_rect(pos_x, pos_y, w, h, 0.7f, 0.7f, 0.75f);
            }

            switch(decalage%3) {
            case 2:
                pos_x += 100;
                pos_y -= 40;
                break;
            default:
                pos_y += 20;
                break;
            }
        }

        // We check for the width
        if(pos_x > this->_max_width){
            this->_max_width = pos_x;
        }
    }


    /*!
     * \fn get_max_percentage(std::map<const EntityValue*, stats*> &temp_states) const
     * \brief Get the biggest percentage of times for all the stats
     * \param temp_states The stats where we want to get the longest
     *
     * \return a value between 0. and 1.
     *
     */
    double get_max_percentage(std::map<const EntityValue*, stats*> &temp_states) const override {
        double value;
        double max_length = 0.;
        for (std::map<const EntityValue *, stats *>::const_iterator it = temp_states.begin();
             it != temp_states.end();
             it ++) {
            if((*it).second->_total_length >= max_length) {
                max_length = (*it).second->_total_length;
            }
        }
        value = max_length/(this->_end_time-this->_start_time);

        return value;
    }


    /*!
     * \fn set_geometrical_informations()
     * \brief Set some infos for the displaying
     */
    void set_geometrical_informations() override {
        this->_pos_x_container_name = _POS_X_CONTAINER_NAME;
        this->_pos_y_container_name = this->_size_for_one_container - 50;

        this->_percentage_height_default = (this->_size_for_one_container - _START_HISTOGRAM_Y_DEFAULT - 20) / 100.;

        /* Size for rectangles in the legend */
        this->_width_for_rect_legend = 20.;
        this->_height_for_rect_legend = 15.;
        this->_max_width = 0;
    }

};

#endif
