// src/simulation_widget.hh - Copyright 2005, 2006, University
//               of Padova, dept. of Pure and Applied
//               Mathematics
//
// This file is part of SGPEMv2.
//
// This is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// SGPEMv2 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with SGPEMv2. If not, see http://www.gnu.org/licenses/.


#ifndef SIMULATION_WIDGET_HH
#define SIMULATION_WIDGET_HH 1

#include "cairo_widget.hh"

#include "sgpemv2/history_observer.hh"
#include "sgpemv2/schedulable.hh"
#include "sgpemv2/simulation_observer.hh"

#include <cairomm/pattern.h>

namespace sgpem
{
  /**
   * \brief Implements a cairo widget to draw the simulation
   * processes status graphical rapresentation.
   *
   * It shows the simulation processes (and threads if flag is enabled)
   * names on the left and a bar for each of these on the right.
   * The bar begins at the time the process bring to life and ends
   * when it die.
   *
   * The bar is composed of small rectangles of different colors
   * depending on the process' status:
   * - green = running
   * - yellow = ready
   * - red = blocked
   * This is the Fantasy Kingdom, do you know? ;)
   *
   * At the bottom of the graph there is a time line ruler.
   *
   * This class implements an HistoryObserver
   * to have an update signal (and related update) every simulation step.
   *
   * \see SimulationObserver
   * \see HistoryObserver
   */
  class SimulationWidget
  : public HistoryObserver, public CairoWidget
  {
  public:
    /**
     * \brief Unique constructor.
     *
     * Saves the passed argument in data member _simulation.
     *
     * \param simulation The observed Simulation
     */
    SimulationWidget(Simulation& simulation);

    /**
     * Destructor!
     */
    virtual ~SimulationWidget();

    /**
     * \brief HistoryObserver's update method redefinition.
     *
     * Updates the widget to reflects history current state.
     *
     * \param changed_history the observed History
     */
    virtual void update(const History& changed_history);

    /**
     * \brief Gets the _show_threads flag current status.
     *
     * \return true if threads visualization is enabled
     */
    bool get_show_threads() const;

    /**
     * \brief Sets and gets the _show_threads flag status.
     *
     * If _show_threads is enabled both processes and threads
     * will be drawn on widget.
     * If _show_threads is disabled only processes 
     * will be shown.
     *
     * \param show the new desired status of threads visualization
     * \return the previous status
     */
    bool set_show_threads(bool show);

  protected:
    /**
     * \brief Catches the mouse click to show a "scaling options"
     * popup menu.
     *
     * \param event the type and status of mouse event occurred
     */
    virtual bool on_button_press_event(GdkEventButton* event);

    /**
     * \brief Execute the widget painting when needed.
     *
     * \param ctx the cairo context to draw to
     * \see CairoWidget for more.
     */
    void draw_widget(Cairo::RefPtr<Cairo::Context>& ctx);

    /**
     * \brief calculated the needed drawing surface dimensions.
     *
     * \param ctx the cairo context to calc draw related dimensions
     * \param width the return parameter for desired width
     * \param height the return parameter for desired height
     */
    virtual void calc_drawing_size(Cairo::RefPtr<Cairo::Context>& ctx, size_t& width, size_t& height);

    /**
     * \brief Adds the click events to the underlying Gdk::Window
     */
    virtual void on_realize();


  private:

    /**
     * \brief Counts the processes number to have the final picture size.
     */
    void count_elements();

    /**
     * \brief Used internally by draw_widget to show processes/threads name.
     *
     * \param ctx the cairo context to draw to
     */
    void draw_names(Cairo::RefPtr<Cairo::Context>& ctx);
    
    /**
     * \brief Used internally by draw_widget to show the bars container grid.
     *
     * \param ctx the cairo context to draw to
     */
    void draw_grid(Cairo::RefPtr<Cairo::Context>& ctx);
    
    /**
     * \brief Used internally by draw_widget to show processes/threads bars.
     *
     * \param ctx the cairo context to draw to
     */
    void draw_bars(Cairo::RefPtr<Cairo::Context>& ctx);
    
    /**
     * \brief Used internally by draw_widget to build the bars.
     *
     * \param ctx the cairo context to draw to
     * \param x horizontal coordinate of starting point
     * \param y vertical coordinate of starting point
     * \param w width of rectangle
     * \param h height of rectangle
     * \param state select the color to apply
     */
    void draw_instant_rect(Cairo::RefPtr<Cairo::Context>& ctx, double x, double y,
                           double w, double h, sgpem::Schedulable::state state);

    /**
     * \brief Build the gradients used to picture the bars.
     *
     * Gradients are filling colors soft degrading.
     * Please refer to cairo documentetion for more.
     */
    void make_gradients();

    /**
     * \brief "No scaling" menu command responding mathod.
     * Sets the actual scaling mode to scaling_none.
     */
    void _on_no_scaling();

    /**
     * \brief "Fit scaling" menu command responding mathod.
     * Sets the actual scaling mode to scaling_min.
     */
    void _on_fit_scaling();

    /**
     * \brief "Stetch scaling" menu command responding mathod.
     * Sets the actual scaling mode to scaling_all.
     */
    void _on_stretch_scaling();


    /**
     * \brief Pointer to the observed simulation.
     */
    Simulation* _simulation;

    /**
     * \brief Flag to enable/disable threads visualization.
     */
    bool        _show_threads;

    /**
      * \brief Drawing x unit.
      *
      * The drawing is constructed upon an arbitrary "squared" surface.
      * All widgets drawing measure are defined as upon x and y units.
      * To avoid alignement problems the drawing units are evaluated
      * on text size. The widtx/height of the text "999" are used as unit.
      */
    double _x_unit;

    /**
      * \brief Drawing y unit.
      *
      * \see _x_unit
      */
    double _y_unit;

    /**
      * \brief Actual number of processes, needed by drawing rountines.
      */
    int _n_proc;

    /**
      * \brief Actual number of threads, needed by drawing rountines.
      */
    int _n_thr;


    /**
      * top margin in y units
      */
    double _yu_top_margin;

    /**
      * left margin in x units
      */
    double _xu_left_margin;

    /**
      * left margin in x units
      */
    double _xu_left_graph_margin;

    /**
      * bar spacing in y units
      */
    double _yu_process_bar_spacing;

    /**
      * process bar height in y units
      */
    double _yu_process_bar_height;

    /**
      * thread bar spacing in y units
      */
    double _yu_thread_bar_spacing;

    /**
      * thread bar height in y units
      */
    double _yu_thread_bar_height;

    /**
     * \brief Gradient used to draw ready processes/threads.
     */
    Cairo::RefPtr<Cairo::Gradient> _ready_process_gradient;

    /**
     * \brief Gradient used to draw running processes/threads.
     */
    Cairo::RefPtr<Cairo::Gradient> _running_process_gradient;

    /**
     * \brief Gradient used to draw blocked processes/threads.
     */
    Cairo::RefPtr<Cairo::Gradient> _blocked_process_gradient;

    /**
      * Used to redraw partially the widget.
      * If the redraw come from Simulation update this flag is true
      * and are redrawn only the last time tics.
      * If the redraw is needed by History update or resize this flag is false.
      */
    bool _partial_redraw;

    /**
      * Last time tic drawn.
      */
    unsigned int _last_drawn;
  };

} //~ namespace sgpem


#endif //~ SIMULATION_WIDGET_HH
