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


#ifndef DRAW_TRACE_HPP
#define DRAW_TRACE_HPP

/*
 * Theses constants can not be put as static const float because it is a template and there binary representation is not normed by the C++ langage.
 */

/*!
 * \def _DRAWING_CONTAINER_HEIGHT_DEFAULT
 * \brief The default height for basic containers.
 */
#define _DRAWING_CONTAINER_HEIGHT_DEFAULT 1.2f

/*!
 * \def _DRAWING_CONTAINER_WIDTH_DEFAULT
 * \brief The default width for containers.
 */
#define _DRAWING_CONTAINER_WIDTH_DEFAULT 2.5f

/*!
 * \def _DRAWING_CONTAINER_H_SPACE_DEFAULT
 * \brief The default horizontal space between containers.
 */
#define _DRAWING_CONTAINER_H_SPACE_DEFAULT 0.1f

/*!
 * \def _DRAWING_CONTAINER_V_SPACE_DEFAULT
 * \brief The default vertical space between containers.
 */
#define _DRAWING_CONTAINER_V_SPACE_DEFAULT 0.2f


/*!
 * \def _DRAWING_STATE_HEIGHT_DEFAULT
 * \brief The default height for states.
 */
#define _DRAWING_STATE_HEIGHT_DEFAULT 1.2f

/*!
 * \def _DRAWING_STATE_V_SPACE_DEFAULT
 * \brief The default vertical space between states.
 */
#define _DRAWING_STATE_V_SPACE_DEFAULT 0.2f


/*!
 * \class DrawTrace
 * \brief Browse the trace and call back T drawing methods
 */
/*template<class T>*/
class DrawTrace
{

protected:

    //  Interface_graphic* _window;

    /*!
     * \brief Containers with states or events
     */
    std::list<const Container *> _entity_containers;
    /*!
     * \brief Containers with links
     */
    std::list<const Container *> _link_containers;
    /*!
     * \brief Containers with variables
     */
    std::list<const Container *> _variable_containers;
    std::map<const Container *, Element_pos, std::less<const Container *> > _container_positions;
    std::map<const Container *, Element_pos, std::less<const Container *> > _container_sizes;
    std::map<const Variable*, Element_pos> _var_positions;

    // Geometrical informations about the trace shape.
    /*!
     * \brief  _container_width width of the container
     */
    Element_pos _container_width;
    /*!
     * \brief _container_height height of the container
     */
    Element_pos _container_height;
    /*!
     * \brief _container_h_space Horizontal space beetween 2 containers
     */
    Element_pos _container_h_space;
    /*!
     * \brief _container_v_space Vertical space between 2 containers
     */
    Element_pos _container_v_space;
    /*!
     * \brief _state_height Height of the state
     */
    Element_pos _state_height;
    /*!
     * \brief _state_v_space Vertical space between 2 states
     */
    Element_pos _state_v_space;

public:

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

    /*!
     * \brief The default constructor
     */
    DrawTrace() {
        _container_width   = _DRAWING_CONTAINER_WIDTH_DEFAULT;
        _container_height  = _DRAWING_CONTAINER_HEIGHT_DEFAULT;
        _container_h_space = _DRAWING_CONTAINER_H_SPACE_DEFAULT;
        _container_v_space = _DRAWING_CONTAINER_V_SPACE_DEFAULT;

        _state_height  = _DRAWING_STATE_HEIGHT_DEFAULT;
        _state_v_space = _DRAWING_STATE_V_SPACE_DEFAULT;
    }


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

    /***********************************
      *
      * Building functions.
      *
      **********************************/

    /*!
     * \fn build(T* draw_object, Trace* trace)
     * \brief The trace building function that do not draw all the containers but only a part.
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
     * \param trace the trace data.
     */
    template<class T>
    void build(T* draw_object, Trace* trace) {
        Info::Container::y_max=0;//reset the vertical zoom when rebuilding
        double zoom = trace->get_filter();
        Interval * interval;// = trace->get_interval_constrained();
        //clear entities
        _container_positions.clear();
        _container_sizes.clear();
        _entity_containers.clear();
        _link_containers.clear();
        _variable_containers.clear();

        std::vector<const Container *> *container = trace->get_selected_container();
        if(container == NULL ||

           container->empty()){
            container = new std::vector<const Container *>();

            trace->set_filter(0);

            std::stack<Container *> containers;
            const Container::Vector *root_containers = trace->get_view_root_containers();
            if(root_containers->empty())root_containers= trace->get_root_containers();
            for (Container::VectorIt i = root_containers->begin();
                 i != root_containers->end();
                 i++){
                containers.push(*i);
                container->push_back(*i);
            }
            add(container, &containers);

        }
        //Adding the parent containers if not added yet
        else{
            bool ended = false;
            std::vector<const Container *> store;
            store.clear();
            while (!ended){
                ended = true;
                for(std::vector<const Container *>::const_iterator it = container->begin() ;
                    it != container->end();
                    it ++){

                    if( *it && (*it)->get_parent())
                        if(!is_in_set((*it)->get_parent(),container)){
                            store.push_back((*it)->get_parent());
                            ended = false;
                        }
                }//end for
                //TODO Warning the same container should be added more than 1 time
                for(std::vector<const Container *>::const_iterator it = store.begin() ;
                    it != store.end();
                    it ++){
                    if( !is_in_set(*it,container))
                        container->push_back(*it);
                }
                store.clear();
            }//end while
        }//end else


        interval = trace->get_interval_constrained();

        draw_object->start_draw();

        draw_object->start_draw_containers();
        browse_container_tree(draw_object, trace,container);
        draw_object->end_draw_containers();
        browse_entities(draw_object,zoom,interval,container);

        draw_object->end_draw();
    }

    /***********************************
     *
     * Browsing functions.
     *
     **********************************/
    /*
     * \fn browse_container_tree(T* draw_object, Trace* trace, Container::Vector container)
     * \brief Function that browses the containers of the trace argument that are in the set container and make them painted with a T object
     */
    template<class T>
    inline void browse_container_tree(T* draw_object, Trace* trace, std::vector<const Container *> *container){
        /*** Drawing containers ***/
        int position = 0;

        const Container::Vector *root_containers = trace->get_view_root_containers();
        if(root_containers->empty())root_containers= trace->get_root_containers();
        if (root_containers->empty()) {
            *Message::get_instance() << QObject::tr("There is no container. The trace can not be drawn.").toStdString() << Message::endw;
        }
        else
            for (Container::VectorIt i = root_containers->begin();
                i != root_containers->end();
                i++)
                // Use the fact a container is selected implies all his ancestors are
                if(is_in_set(*i,container))
                    position += browse_container(draw_object, *i, position, 0,container);
    }/* end browse_container_tree */


    /*
     * \fn browse_container(T* draw_object, const Container *container, int position, int depth, Container::Vector set_container)
     * \brief Recursive function that browse a container to draw it if it is in the set of container with a T painting object in position, knowing the current depth in the tree
     */

    template<class T>
    int browse_container(T* draw_object, const Container *container, int position, int depth, std::vector<const Container *> *set_container) {
        int size = 0;

        // Draw children
        const Container::Vector *children = container->get_view_children();//we want to display only children meant to be displayed
        if(children->empty())children = container->get_children();

        for (Container::VectorIt i = children->begin();
            i != children->end();
            i++) {
            if(is_in_set(*i,set_container))
                size += browse_container(draw_object, (*i), position+size, depth+1,set_container);
        }

        // Use one line for states and events
#ifdef USE_ITC
        if ((container->get_states()!=NULL && !container->get_states()->empty() )|| (container->get_events()!=NULL && !container->get_events()->empty())) {
#else
                if ((!container->get_states()->empty() )|| (!container->get_events()->empty())) {
#endif
                        size++;
            _entity_containers.push_back(container);
        }


        // Store the position to draw links
        _container_positions[container] = position; // First line after children
        _container_sizes[container]     = size; // First line after children

        // Use one line for each variable
        if (container->get_variable_number() > 0) {
            _variable_containers.push_back(container);
            size += container->get_variable_number();
        }

        if (size < 1) // Minimum size
            size = 1;

        // Push containers with links to draw
        if (!container->get_links()->empty())
            _link_containers.push_back(container);

        // Draw this container
        draw_container(draw_object, position, size, depth, container->get_name().to_string());

        return size;
    }

    /*!
     * \brief Draw a container
     * \param draw_object Object that contains drawing methods to call
     * \param position Starting line of the container
     * \param size Height of the container in number of line
     * \param depth Depth of container in the tree
     * \param text Name of the container
     */
    template<class T>
    inline void draw_container(T* draw_object, int position, int size, int depth, const std::string &text) {
        Element_pos x = depth*(_container_width+_container_h_space) + _container_h_space/2;
        Element_pos y = position*(_container_height+_container_v_space) + _container_v_space/2;
        Element_pos height = size*(_container_height+_container_v_space) - _container_v_space;
        draw_object->draw_container(x, y, _container_width, height);
        draw_object->draw_container_text(x, y+height/2, text);
    }
    /*!
     * \brief Browse the states list and draw them
     */
    template<class T>
    inline void browse_entities(T* draw_object, double zoom, Interval* interval, std::vector<const Container *> *set_container) {
        //////////////////////////////////////////////////////////
        const Container *container;
        StateChange::Tree *state_tree;
        Event::Tree *event_tree;
        const Link::Vector *link_list;
        Link *link;
        const std::map<VariableType *, Variable *> *variable_map;
        Variable *var;
        const std::list<std::pair<Date, Double> > *variable_values;
        int position;
        const Color *color;
        std::map<std::string, Value *>::const_iterator field;
        Element_pos lvl_zoom;

        color = NULL;

        if(zoom>=0)
            lvl_zoom = zoom;
        else
            lvl_zoom = 0;

        draw_object->start_draw_states();
        draw_object->start_draw_events();
        for (std::list<const Container *>::const_iterator c = _entity_containers.begin();
            c != _entity_containers.end();
            c++) {
            if(is_in_set(*c,set_container)){
                container = *c;

                position = (int)_container_positions[container] + _container_sizes[container] - 1;

                state_tree = container->get_states();
                event_tree = container->get_events();
#ifdef USE_ITC
                if(state_tree!=NULL){
#endif
                    if ( !state_tree->empty() ) {
                    //printf("drawing states for %s\n", container->get_name().to_string().c_str());
                        // Browse states
                        DrawTree<T, StateChange>(draw_object, position, lvl_zoom,
                                                 _container_height, _container_v_space, _state_height, _state_v_space)
                            .draw_tree(state_tree, *interval);
                                    }
#ifdef USE_ITC
                                }
                                if(event_tree!=NULL){
#endif
                                    if ( !event_tree->empty()){
                                        //printf("drawing events for %s\n", container->get_name().to_string().c_str());
                        // Browse events
                        DrawTree<T, Event>(draw_object, position, lvl_zoom,
                                           _container_height, _container_v_space, _state_height, _state_v_space)
                            .draw_tree(event_tree, *interval);
                    }
#ifdef USE_ITC
                }
#endif
            }
        }/* end for (!_stack_states.empty()) */

        draw_object->end_draw_events();
        draw_object->end_draw_states();


        draw_object->start_draw_arrows();

        for (std::list<const Container *>::const_iterator c = _link_containers.begin();
            c != _link_containers.end();
            c++) {
            if(is_in_set(*c,set_container)){
                container = *c;

                // Browse links
                link_list = container->get_links();
                for (Link::VectorIt it = link_list->begin();
                     it != link_list->end();
                     it++) {



                    link = *it;

                    bool display=false;
                    color=NULL;
                    if(!Session::get_use_palette("link_types")) display = true;
                    else{
                        if (link->get_type()){
                            Palette *lt = Session::get_palette("link_types", Session::get_current_palette("link_types"));

                            color = lt->get_color(link->get_type()->get_name().to_string());
                            if(color) display=true;

                        /*for(std::list<std::string>::const_iterator it2= link_types->get_->begin();
                            it2!= link_types->end();
                            it2++ ){
                            if(*it2 ==  link->get_type()->get_name().to_string()){
                                display=true;
                                break;

                            }
                         } */

                       }
                    }
                            if(display &&
                            link_is_in_set(link,set_container,interval)){

                                // Search the color
                                if (color==NULL &&
                                    link->get_type()&&
                                    link->get_type()->get_extra_fields()!=NULL &&
                                    !link->get_type()->get_extra_fields()->empty() &&
                                    ((field = link->get_type()->get_extra_fields()->find(std::string("Color"))) != link->get_type()->get_extra_fields()->end()))
                                    /* Call the object link drawing function with the link color */
                                    color = (const Color *)(*field).second;

                                draw_link(draw_object, link, color );
                    }
                }/* end for */
            }//end for
        }/* end while (!_stack_states.empty()) */

        draw_object->end_draw_arrows();
        draw_object->start_draw_counter();

        for (std::list<const Container *>::const_iterator c = _variable_containers.begin();
            c != _variable_containers.end();
            c++) {

            if(is_in_set(*c,set_container)){

                container = *c;
                position = (int)_container_positions[container] + _container_sizes[container];

                // Browse variables
                variable_map = container->get_variables();

                for (std::map<VariableType *, Variable *>::const_iterator i = variable_map->begin();
                     i != variable_map->end();
                     i++) {

                    var = (*i).second;
                    double min = var->get_min().get_value();
                    double max = var->get_max().get_value();
                    variable_values = var->get_values();

                    double first_value = 0.;
                    double second_value = 0.;

                    draw_object->draw_text_value((long int)var,0.0, (position+1)*(_container_height+_container_v_space) - _container_v_space/2 -
            0.5*_container_height);
                    _var_positions[var]=position;
                    draw_variable_value(draw_object, 0.0, 0.0, position);
                    for (std::list<std::pair<Date, Double> >::const_iterator value = variable_values->begin();
                         value != variable_values->end();
                         value++) {

                        /* Call the object state drawing function.
                           We pass the first value if correspond to the beginning */
                        first_value = (*value).first.get_value();
                        second_value =((*value).second.get_value()-min)/(max-min) ;
                        if(!(first_value == 0. && second_value == 0.)) {
                            draw_variable_value(draw_object, first_value, second_value, position);
                        }
                    }
                    draw_variable_value(draw_object, 0.0, 0.0, position);
                    position++; // One line was used
                }/* end for */
            }
        }//end for

        draw_object->end_draw_counter();
    }


    /*!
     * \brief Draw a point of a variable curve
     * \param draw_object Object that contains the drawing methods
     * \param time Time of the point
     * \param value Value of of the variable (between 0.0 and 1.0)
     * \param position Line where the variable is drawn
     */
    template<class T>
    inline void draw_variable_value(T *draw_object, double time, double value, int position) {
        Element_pos y = (position+1)*(_container_height+_container_v_space) - _container_v_space/2 -
            value*_container_height;
        draw_object->draw_counter(time, y);
    }

    /*!
     * \brief Draw a link
     * \param draw_object Object that contains the drawing methods
     * \param starttime Time of the start of the link
     * \param endtime Time of the end of the link
     * \param start Line of the start of the link
     * \param end Line of the end of the link
     * \param color The link color
     */
    template<class T>
        inline void draw_link(T *draw_object, const Link *link, const Color* color)
    {
        double starttime = link->get_start_time().get_value();
        double endtime   = link->get_end_time().get_value();
        double srcpos    = _container_positions[link->get_source()];
        double dstpos    = _container_positions[link->get_destination()];
        double srcsize   = _container_sizes[link->get_source()];
        double dstsize   = _container_sizes[link->get_destination()];

        Element_pos y1 = (srcpos + 0.5 * srcsize)*(_container_height+_container_v_space);
        Element_pos y2 = (dstpos + 0.5 * dstsize)*(_container_height+_container_v_space);

        if (color != NULL)
            draw_object->draw_arrow(starttime, endtime, y1, y2, color->get_red(), color->get_green(), color->get_blue());
        else/* Draw white link */
            draw_object->draw_arrow(starttime, endtime, y1, y2, 1.0, 1.0, 1.0);
    }

    /*
     * \brief Assuming someone has clicked in (x, y), display the description corresponding to the item clicked
     */
    void display_information(const Trace *trace, double x, double y, double d) {
        const Container *container = NULL;
        const Container *ancestor = NULL;
        const Link *link;
        const Event *event;
        const State *state;
        const Variable *variable;

        // find container needs to know the position of each container
        double yr = y;
        const Container::Vector *root_containers = trace->get_view_root_containers();
        if(root_containers->empty())root_containers= trace->get_root_containers();
        if (!root_containers->empty())
            for (Container::VectorIt i = root_containers->begin();
                i != root_containers->end();
                i++)
                if ((container = search_container_by_position(*i, yr)))
                    break;

        // If the clic is out
        if (!container)
            return;

        // Calculate the container positions
        int position = 0;
        for (Container::VectorIt i = root_containers->begin();
                i != root_containers->end();
                i++)
                position += calc_container_positions(*i, position);

        // First we browse to find a communication
        ancestor = container;
        if (!Info::Render::_no_arrows) {

            while (ancestor) {
                if ((link = get_link(ancestor, x, y, d))) {
                *Message::get_instance() << "<center><strong>Link</strong></center>"
                    << "<strong>Value:</strong> " << link->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Source:</strong> " << link->get_source()->get_name().to_string() << "<br />"
                    << "<strong>Destination:</strong> " << link->get_destination()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << link->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << link->get_start_time().get_value() << " - " << link->get_end_time().get_value() << "<br />"
                    << "<strong>Duration:</strong> " << link->get_duration() << "<br />";
                print_extra_fields("Link", link->get_extra_fields());
                print_extra_fields("Value", link->get_value()->get_extra_fields());
                print_extra_fields("Type", link->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;
                    return;
                }
                else
                    ancestor = ancestor->get_parent();
            }

            //if not found, the link may hav been assigned to the first root container.

             if ((link = get_link(root_containers->front(), x, y, d))) {
                *Message::get_instance() << "<center><strong>Link</strong></center>"
                    << "<strong>Value:</strong> " << link->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Source:</strong> " << link->get_source()->get_name().to_string() << "<br />"
                    << "<strong>Destination:</strong> " << link->get_destination()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << link->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << link->get_start_time().get_value() << " - " << link->get_end_time().get_value() << "<br />"
                    << "<strong>Duration:</strong> " << link->get_duration() << "<br />";
                print_extra_fields("Link", link->get_extra_fields());
                print_extra_fields("Value", link->get_value()->get_extra_fields());
                print_extra_fields("Type", link->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;
                    return;
                }
        }
        // Now browsing for the events of the container root
        // Verification if it is a clic on an event
#ifndef USE_ITC
        if ((!container->get_events()->empty() || !container->get_states()->empty()) && yr < _container_height+_container_v_space) {
#else
                if (((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty())) && yr < _container_height+_container_v_space) {
#endif
            if (!Info::Render::_no_events)
                if ((event = find_event(container, x, d))) {
                *Message::get_instance() << "<center><strong>Event</strong></center>"
                    << "<strong>Value:</strong> " << event->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Container:</strong> " << event->get_container()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << event->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << event->get_time().get_value() << "<br />";
                print_extra_fields("Event", event->get_extra_fields());
                print_extra_fields("Value", event->get_value()->get_extra_fields());
                print_extra_fields("Type", event->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;
                    return;
                }
            if ((state = find_state(container, x))) {
                *Message::get_instance() << "<center><strong>State</strong></center>"
                    << "<strong>Value:</strong> " << state->get_value()->get_name().to_string() << "<br />"
                    << "<strong>Container:</strong> " << state->get_container()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << state->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Date:</strong> " << state->get_start_time().get_value() << " - " << state->get_end_time().get_value() << "<br />"
                    << "<strong>Duration:</strong> " << state->get_duration() << "<br />";
                print_extra_fields("State", state->get_extra_fields());
                print_extra_fields("Value", state->get_value()->get_extra_fields());
                print_extra_fields("Type", state->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;
                return;
            }
        }
        else {
#ifdef USE_ITC
                        if ((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty()))
#else
                        if (!container->get_events()->empty() || !container->get_states()->empty())
#endif
                yr -= _container_height+_container_v_space;
            const std::map<VariableType *, Variable *> *variable_map = container->get_variables();
            std::map<VariableType *, Variable *>::const_iterator i = variable_map->begin();
            while (yr > _container_height+_container_v_space) {
                yr -= _container_height+_container_v_space;
                i++;
            }
            if (i != variable_map->end()) {
                variable = (*i).second;
                *Message::get_instance() << "<center><strong>Variable</strong></center>"
                    << "<strong>Container:</strong> " << variable->get_container()->get_name().to_string() << "<br />"
                    << "<strong>Type:</strong> " << variable->get_type()->get_name().to_string() << "<br />"
                    << "<strong>Value:</strong> " << variable->get_value_at(x) << "<br />"
                    << "<strong>Value:</strong> " << variable->get_value_at(x) << "<br />"
                    << "<strong>Min:</strong> " << variable->get_min().get_value()  << "<br />"
                    << "<strong>Max:</strong> " << variable->get_max().get_value() << "<br />";
                print_extra_fields("Type", variable->get_type()->get_extra_fields());
                *Message::get_instance() << Message::endsi;

                return;
            }
        }

        *Message::get_instance() << Message::endsi;
        // Nothing has been found
        return;


    }

    void print_extra_fields(std::string name, const std::map<std::string, Value *> *extra_fields) {
        if (extra_fields!=NULL &&!extra_fields->empty()) {
            *Message::get_instance() << "<em>" << name << " extra fields</em><br />";
            for (std::map<std::string, Value *>::const_iterator i = extra_fields->begin();
                i != extra_fields->end();
                i++)
                *Message::get_instance() << "<strong>" << (*i).first << ":</strong> " << (*i).second->to_string() << "<br />";
        }
    }

    const Container *search_container_by_position(const Container *container, double &y) {
        const Container *result;
        // Search if the result is a descendant
        const Container::Vector *children = container->get_view_children();//we want to display only children meant to be displayed
        if(children->empty())children = container->get_children();
        for (Container::VectorIt i = children->begin();
            i != children->end();
            i++) {
            if ((result = search_container_by_position(*i, y)) != NULL)
                return result;
        }

        // Calculate the size of the container (without its children)
        int size = 0;
#ifdef USE_ITC
                if ((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty()))
#else
                if (!container->get_states()->empty() || !container->get_events()->empty())
#endif
            size++;
        if (container->get_variable_number() > 0)
            size += container->get_variable_number();


        if (children->empty() && size < 1) // Minimum size
            size = 1;

        // Test if the position is in this container
        if (y < size*(_container_height+_container_v_space))
            return container;
        else
            y -= size*(_container_height+_container_v_space);

        // The position is outside this container
        return NULL;
    }

    /*
     * \fn browse_container(T* draw_object, const Container *container, int position, int depth)
     * \brief Recursive function that browse a container to draw it with a T painting object in position, knowing the current depth in the tree
     */
    int calc_container_positions(const Container *container, int position) {
        int size = 0;

        // Draw children
        const Container::Vector *children = container->get_view_children();//we want to display only children meant to be displayed
        if( children->empty() )
            children = container->get_children();
        for (Container::VectorIt i = children->begin();
            i != children->end();
            i++) {
            size += calc_container_positions((*i), position+size);
        }

        // Store the position to draw links
        _container_positions[container] = position; // First line after children
        _container_sizes[container]     = size; // First line after children

        // Use one line for states and events
#ifdef USE_ITC
                if ((container->get_states()!=NULL && !container->get_states()->empty()) ||(container->get_events()!=NULL && !container->get_events()->empty())){
#else
                if (!container->get_states()->empty() || !container->get_events()->empty()) {
#endif
            size++;
        }

        // Use one line for each variable
        if (container->get_variable_number() > 0) {
            size += container->get_variable_number();
        }

        return size;
    }

    /*!
     * \brief Tries to find a link passing by x and y in the container
     */
    const Link* get_link(const Container *container, Element_pos x, Element_pos y, Element_pos d) {
        const Link::Vector *link_list;
        Link *link;
        double a, b, c; // Equation: ax + by + c = 0
        double x1, x2, y1, y2;

        if(!container)
            return NULL;

        // Browse links
        link_list = container->get_links();
        for (Link::VectorIt it = link_list->begin();
             it != link_list->end();
             it++) {

            link = *it;

            double srcpos  = _container_positions[link->get_source()];
            double dstpos  = _container_positions[link->get_destination()];
            double srcsize = _container_sizes[link->get_source()];
            double dstsize = _container_sizes[link->get_destination()];

            x1 = link->get_start_time().get_value();
            x2 = link->get_end_time().get_value();

            y1 = (srcpos + 0.5 * srcsize)*(_container_height+_container_v_space);
            y2 = (dstpos + 0.5 * dstsize)*(_container_height+_container_v_space);

            if (((x1-d <= x && x <= x2+d) || (x2-d <= x && x <= x1+d)) &&
                ((y1-d <= y && y <= y2+d) || (y2-d <= y && y <= y1+d))) { // Test the interval
                a = y1 - y2;
                b = x2 - x1;
                c = -(a*x1 + b*y1);

                double e = a*x + b*y + c;

                if (e*e/(a*a + b*b) < d*d) // Test the distance
                    return link;
            }
        }

        return NULL;
    }

    /*
     * \brief Returns the event that occurs at the time x in the container
     */
    const Event *find_event(const Container *container, Element_pos x, Element_pos d) {
        if(!container || container->get_events()==NULL)
            return NULL;

        Node<Event> *node = container->get_events()->get_root();

        while(node) {
            Element_pos t = node->get_element()->get_time().get_value();
            if (x < t) {
                if (t - x < d)
                    return node->get_element();
                node = node->get_left_child();
            }
            else {
                if (x - t < d)
                    return node->get_element();
                node = node->get_right_child();
            }
        }

        return NULL;
    }

    /*
     * \brief Returns the state at the time x
     */
    const State * find_state(const Container *container, Element_pos x) {
        if(!container || container->get_states()==NULL)
            return NULL;

        Node<StateChange> *node = container->get_states()->get_root();

        while(node) {
            Element_pos t = node->get_element()->get_time().get_value();
            if (x < t) {
                if (node->get_element()->get_left_state() && node->get_element()->get_left_state()->get_start_time().get_value() < x)
                    return node->get_element()->get_left_state();
                node = node->get_left_child();
            }
            else {
                if (node->get_element()->get_right_state() && x < node->get_element()->get_right_state()->get_end_time().get_value())
                    return node->get_element()->get_right_state();
                node = node->get_right_child();
            }
        }

        return NULL;
    }


  bool link_is_in_set(Link * link, std::vector<const Container *> *set_container, Interval * interval ){
        const Container * src = link->get_source();
        const Container * dest = link->get_destination();
        for(unsigned int i = 0 ; i < set_container->size() ; i++){
            if(src == (*set_container)[i]){
                for(unsigned int j = 0 ; j < set_container->size() ; j++)
                    if(dest == (*set_container)[j])
                        if(
                           (interval->_left.get_value() < link->get_start_time().get_value() && interval->_right.get_value() > link->get_end_time().get_value()) ||
                           (interval->_left.get_value() < link->get_end_time().get_value() && interval->_right.get_value() > link->get_start_time().get_value()))
                            return true;
            }
        }
        return false;
    }

  bool is_in_set(const Container * c, std::vector<const Container *> *set_container){
        if(!c || !set_container)
            return false;
        for(unsigned int i = 0 ; i<set_container->size() ; i++ )
            if(c==(*set_container)[i])
                return true;
        return false;
    }



  void add( std::vector<const Container *> *container,std::stack<Container *> *containers){


        while (!containers->empty()) {
            const Container * c = containers->top();
            containers->pop();
            const Container::Vector *children = c->get_view_children();//we want to display only children meant to be displayed
            if(children->empty())children = c->get_children();
            for (Container::VectorIt i = children->begin();
                 i != children->end();
                 i++){
                containers->push(*i);
                container->push_back(*i);
            }
            add(container,containers);
        }
    }

template<class T>
void draw_text_variable_values(T* render, std::map<long int, double>* var_map,  double date){
    std::map<long int, double>::const_iterator it=var_map->begin();
    const std::map<long int, double>::const_iterator it_end=var_map->end();

    while(it!=it_end){
        render->draw_text_value((*it).first,(*it).second, -1);
        it++;
    }

}
};
#endif
