/*
** 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 DrawHDiagram.hpp
 */

#ifndef DRAW_HDIAGRAM_HPP
#define DRAW_HDIAGRAM_HPP

/*!
 * \class DrawHDiagram
 * \brief Browse the stats and call back T drawing methods
 */
template<class T>
class DrawHDiagram : public DrawStats<T> {
protected:
  double _startx;
  double _starty;
  double _graph_width;
  double _draw_width;
  double _draw_height;
  double _legend_width;
  double _legend_height;
  std::set<const EntityValue*> _setstates;
    
public:
    /*
     * \brief The default constructor
     */
    DrawHDiagram() {
        _startx = _START_HISTOGRAM_X_DEFAULT;
        _starty = 100.0f;
	
        this->_size_for_one_container = _HEIGHT_FOR_ONE_CONTAINER_DEFAULT;
        this->_percentage_height_default = (this->_size_for_one_container - _START_HISTOGRAM_Y_DEFAULT) / 100.;

        this->_pos_x_container_name   = _POS_X_CONTAINER_NAME;
        this->_pos_y_container_name   = _POS_Y_CONTAINER_NAME;
     
        /* Size for rectangles in the legend */
        this->_width_for_rect_legend  = 20.;
        this->_height_for_rect_legend = 15.;
    }

    
    /*!
     * \brief The destructor
     */
    virtual ~DrawHDiagram() {
    }


    /*!
     * \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) {
        int nbcont;

        draw_object->clear();

        _draw_height               = draw_object->height();
        _draw_width                = draw_object->width();
        _legend_height             = draw_object->height();
        _legend_width              = draw_object->width();
	_graph_width               = _draw_width - _startx - 30.;
        this->_containers_to_print = containers_to_print;
        nbcont = this->_containers_to_print.size();

        draw_object->start_draw();
        draw_object->set_total_height((nbcont+1)*_WIDTH_HISTOGRAM_DEFAULT
 				      + 10.);
        draw_object->set_total_width(draw_object->width());

	draw_object->draw_axis(_startx,
			       _starty - (nbcont-1)*_WIDTH_HISTOGRAM_DEFAULT, 
			       _graph_width + 10.,
			       (nbcont+1)*_WIDTH_HISTOGRAM_DEFAULT);

	draw_object->draw_horizontal_line(_startx,
			       _starty + _WIDTH_HISTOGRAM_DEFAULT, 
			       _graph_width + 10.);

	for (int i=25; i < 101; i+=25)
	  {
	    // Draw Up Scale
	    draw_object->draw_vertical_line(_startx + i*_graph_width/100., 
					    _starty + _WIDTH_HISTOGRAM_DEFAULT - 2.5, 
					    5.);
	    draw_object->draw_text(_startx + i*_graph_width/100 - 10., 
				   this->_size_for_one_container-(_starty + _WIDTH_HISTOGRAM_DEFAULT + 15.),
				   QString::number(i, 'd', 1).toStdString()+"%");
	    // Draw Down Scale
	    draw_object->draw_vertical_line(_startx + i*_graph_width/100., 
					    _starty - (nbcont-1)*_WIDTH_HISTOGRAM_DEFAULT - 2.5, 
					    5.);
	    draw_object->draw_text(_startx + i*_graph_width/100 - 10., 
				   this->_size_for_one_container-(_starty - (nbcont-1)*_WIDTH_HISTOGRAM_DEFAULT - 15.),
				   QString::number(i, 'd', 1).toStdString()+"%");
	  }

        for(int i = 0 ; i < nbcont ; i ++) {
            draw_diagram(draw_object, i);            
        }
	draw_legend(draw_object,
		    _POS_X_LEGEND_DEFAULT + _startx,
		    _POS_Y_LEGEND_DEFAULT + _starty - (nbcont+3)*_WIDTH_HISTOGRAM_DEFAULT);
	this->end_draw(draw_object);
    }

    /*!
     * \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.
     */
    void draw_diagram(T* draw_object, const int container_id) {
        Statistic                           *stat_temp;
        std::map<const EntityValue*, stats*> temp_states;
	double                               duration;
	int                                  pos_x, pos_y;
        std::string                          ctname;
		
	stat_temp   = new Statistic();
        this->_containers_to_print[container_id]->fill_stat(stat_temp, Interval(this->_start_time, this->_end_time));
	temp_states = stat_temp->get_states();
	duration = this->_end_time - this->_start_time;

        // Printing of the trace
	//std::cout << "nb states " << temp_states.size() << std::endl;
	
        // Depending on the kind of diagram...
	pos_x = _startx;
	pos_y = _starty - container_id * _WIDTH_HISTOGRAM_DEFAULT;
	
	// Draw the container name 
	ctname = this->_containers_to_print[container_id]->get_name().to_string();
	draw_object->draw_text(_POS_X_CONTAINER_NAME, 
			       this->_size_for_one_container-(pos_y + _WIDTH_HISTOGRAM_DEFAULT / 2. - 5.),
			       ctname);

	// Draw the stats
	for (std::map<const EntityValue *, stats *>::iterator it = temp_states.begin();
	     it != temp_states.end();
	     it ++) 
	  {
	    double      length  = (*it).second->_total_length;
	    double      percent = length / duration ;
	    double      width   = percent * _graph_width;
	    std::string name    = (*it).first->get_name().to_string();
	    double      red     = 0.7;
	    double      green   = 0.7;
	    double      blue    = 0.75;

	    // We search for a color
	    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;
		red   = color->get_red();
		green = color->get_green();
		blue  = color->get_blue();
	      }

	    draw_object->draw_rect(pos_x, pos_y, 
				   width, _WIDTH_HISTOGRAM_DEFAULT, 
				   red, green, blue);
	    
	    if ( width > 30. )
	      draw_object->draw_text(pos_x + width / 2 - 10.,
                                     this->_size_for_one_container-(pos_y + _WIDTH_HISTOGRAM_DEFAULT / 2. - 5.),
				     QString::number(percent*100., 'f', 1).toStdString()+"%");

	    pos_x += width;
	    this->_setstates.insert((*it).first);

	  }

        delete stat_temp;
    }

    /*!
     * \fn draw_legend(T* draw_object, int pos_x, int pos_y)
     * \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 pos_x the x position of the legend.
     * \param pos_y the y position of the legend.
     */
    void draw_legend(T* draw_object, int pos_x, int pos_y) {
        std::set<const EntityValue *>::const_iterator it;
        std::set<const EntityValue *>::const_iterator end;
        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;

	end = this->_setstates.end();
        for (it  = this->_setstates.begin();
             it != end;
             it ++, decalage ++) {
	    std::string name = (*it)->get_name().to_string();
            
            draw_object->draw_text(pos_x+w+_POS_X_LEGEND_DEFAULT,
                                   this->_size_for_one_container-pos_y,
                                   name.substr(0, 10));
	    
            if((*it)->get_extra_fields()->find(std::string("Color")) != (*it)->get_extra_fields()->end()) 
	      {
                const Color *color = (const Color *)(*it)->get_extra_fields()->find(std::string("Color"))->second;
                draw_object->draw_rect(pos_x, 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.7, 0.7, 0.75);
	      }
            
            switch(decalage%3) {
            case 2:
                pos_x += 100;
                pos_y += 40;
                break;
            default:
                pos_y -= 20;
                break;
            }
        }

        this->_max_width = pos_x + w + _POS_X_LEGEND_DEFAULT;
        this->set_geometrical_informations_object(draw_object);

    }
};
    
#endif
