// src/holt_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 HOLT_WIDGET_HH
#define HOLT_WIDGET_HH 1

#include "cairo_widget.hh"

#include "sgpemv2/history_observer.hh"
#include "sgpemv2/request.hh"
#include "sgpemv2/sub_request.hh"
#include "sgpemv2/simulation_observer.hh"

#include <complex>


namespace sgpem
{
  class History;
  class Schedulable;
  class Resource;
}

namespace sgpem
{
  typedef SubRequest::resource_key_t     resource_key_t;

  /**
   * \brief Every point or vector is a Vec2.
   *
   * This phisical vector class, Vec2 is realized trough
   * complex<double> because it's a full functional
   * class with operators and easy vector operation as
   * sum, multiply by scalar, rotation.
   */
  typedef std::complex<double> Vec2;


  /**
   * \brief Base class to draw holt graph nodes (schedulables and resources).
   *
   * This class is an "element" used by HoltWidget to draw holt graphs.
   * An holt graph is built of circular nodes representing schedulables
   * and square nodes representing resources connected as needed by
   * arrows.
   *
   * This is a base abstract class for schedulables and resources.
   * It has basic methods for positioning and sizing.
   * The abstract method get_intersection() must be defined
   * in derived classes to calculate the intersection of a request
   * arrow with the node edge.
   *
   * Method draw() (abstract too) must provide effective object drawing.
   */
  class HoltNode
  {
  public:
    /**
     * \brief Unique constructor taking a Vec2 point as position.
     *
     * \param pt the predefined node position; default position at (0,0).
     */
    HoltNode(Vec2 pt = Vec2(0.0, 0.0));

    /**
     * \brief Class virtual destructor.
     */
    virtual ~HoltNode();

    /**
     * \brief Effective output cairo drawing method.
     *
     * \param cr The cairo context to draw to.
     */
    virtual void draw(Cairo::RefPtr<Cairo::Context>& cr) = 0;

    /**
     * \brief Setter and getter method for position parameter.
     *
     * Position is in the center of object.
     *
     * \param pt The point to position the object.
     * \return The previous position.
     */
    Vec2 set_position(Vec2 pt);
    
    /**
     * \brief Getter method for position parameter.
     *
     * Position is in the center of object.
     *
     * \return The object actual position.
     */
    Vec2 get_position();

    /**
     * \brief Sets dimension of object.
     *
     * Radius represent the node dimension.
     * By default these object are symmetrical and radius stay
     * for "radius" in circular shaped nodes (schedulables),
     * an half of the side for square objects (resources).
     *
     * \param radius The new desired value.
     * \return The radius previous value.
     */
    double set_radius(double radius);

    /**
     * \brief Gets dimension of object.
     *
     * Radius represent the node dimension.
     * By default these object are symmetrical and radius stay
     * for "radius" in circular shaped nodes (schedulables),
     * an half of the side for square objects (resources).
     *
     * \return The actual radius value.
     */
    double get_radius();

    /**
     * \brief Computes point of intersection with edge.
     *
     * Giving a point outside the object edge this funcion returns
     * the intersection of the segment connecting the shape center
     * with the given point.
     * Because is "shape dependent" it must be redefined in derived
     * classes.
     *
     * \param pt The point to (ideally) connect to.
     * \return The intersection of edge with segment from center to pt.
     */
    virtual Vec2 get_intersection_to(Vec2 pt) = 0;

  protected:
    /**
     * \brief Object dimension.
     */
    double _radius;

    /**
     * \brief Object position.
     */
    Vec2 _pos;
  };

  /**
   * \brief An holt node representing resources.
   *
   * A resource is drawn in form of square.
   * This class derives from HoltNode and implements
   * the abstract methods draw() and get_intersection().
   *
   * This class is used internally by HoltWidget, an HistoryObserver
   * and is strictly related to backend class Resource (and derived).
   * Inside there is a pointer to the rapresented resource and its key.
   *
   */
  class HoltResource : public HoltNode
  {
  public:
    /**
     * \brief Unique constructor referring to resource and position in graph.
     *
     * \param resource The referred resource rapresented by this object.
     * \param resource_key Unique numeric key associated with this resource.
     * \param pt Position of object in graph.
     */
    HoltResource(const Resource& resource, resource_key_t resource_key, Vec2 pt = Vec2(0.0, 0.0));

    /**
     * \brief Object's virtual destructor.
     */
    virtual ~HoltResource();

    /**
     * \brief Object's drawing method.
     *
     * \param cr Cairo context to draw to.
     */
    virtual void draw(Cairo::RefPtr<Cairo::Context>& cr);

    /**
     * \brief Computes point of intersection with edge.
     *
     * Giving a point outside the object (square) edge this funcion returns
     * the intersection of the segment connecting the shape center
     * with the given point.
     *
     * \param pt The point to (ideally) connect to.
     * \return The intersection of edge with segment from center to pt.
     */
    virtual Vec2 get_intersection_to(Vec2 pt);

    /**
     * \brief Allocates resource places.
     *
     * \param places Number to allocate.
     */
    void allocate(unsigned int places);

    /**
     * \brief Gets allocates resource places.
     *
     * \return Number of places allocated.
     */
    unsigned int get_allocated();

  private:
    /**
     * \brief Pointer to the related resource.
     */
    const Resource* _resource;

    /**
     * \brief Numeric key associated with this resource.
     */
    resource_key_t _resource_key;

    /**
     * \brief Numeric key associated with this resource.
     */
    unsigned int _used_places;


  };




  /**
   * \brief An holt node representing schedulables (processes and threads).
   *
   * A schedulable is drawn in form of circle.
   * This class derives from HoltNode and implements
   * the abstract methods draw() and get_intersection().
   *
   * This class is used internally by HoltWidget, an HistoryObserver
   * and is strictly related to backend class Schedulable (and derived).
   * Inside there is a pointer to the rapresented schedulable.
   *
   */
  class HoltSchedulable : public HoltNode
  {
  public:
    /**
     * \brief Unique constructor referring to schedulable and position in graph.
     *
     * \param schedulable The referred schedulable rapresented by this object.
     * \param pt Position of object in graph.
     */
    HoltSchedulable(const Schedulable& schedulable, Vec2 pt = Vec2(0.0, 0.0));

    /**
     * \brief Object's virtual destructor.
     */
    virtual ~HoltSchedulable();

    /**
     * \brief Object's drawing method.
     *
     * \param cr Cairo context to draw to.
     */
    virtual void draw(Cairo::RefPtr<Cairo::Context>& cr);

    /**
     * \brief Computes point of intersection with edge.
     *
     * Giving a point outside the object (circle) edge this funcion returns
     * the intersection of the segment connecting the shape center
     * with the given point.
     *
     * \param pt The point to (ideally) connect to.
     * \return The intersection of edge with segment from center to pt.
     */
    virtual Vec2 get_intersection_to(Vec2 pt);

  private:
    /**
     * \brief Pointer to the related schedulable.
     */
    const Schedulable* _schedulable;
  };



  /**
   * \brief Base class to draw holt graph arrows (requests/allocation).
   *
   * An arrow from a schedulable to a resource is called
   * a request, counter is called an assignment.
   *
   * This is the class for both.
   * It "connects" two objects: a schedulable and a resource and
   * has a state to tell the direction of arrow.
   * The state definition come from the class Request.
   * Not all the values are drawn but only allocated (green),
   * allocable (yellow), unallocable (red).
   */
  class HoltRequest
  {
  public:
    /**
     * \brief Object construcor.
     *
     * \param hp Reference to the HoltSchedulable.
     * \param hr Reference to HoltResource.
     * \param state Type of request.
     */
    HoltRequest(HoltSchedulable& hp, HoltResource& hr, Request::state state, unsigned int places);

    /**
     * \brief Object's virtual destructor.
     */
    virtual ~HoltRequest();

    /**
     * \brief Object's drawing method.
     *
     * \param cr Cairo context to draw to.
     */
    virtual void draw(Cairo::RefPtr<Cairo::Context>& cr);

  private:
    /**
     * \brief Methot for draw an arrow giving starting and ending points.
     *
     * \param cr Cairo context.
     * \param first Starting point.
     * \param first Ending point.
     */
    virtual void arrow(Cairo::RefPtr<Cairo::Context>& cr, Vec2 first, Vec2 second);

    /**
     * \brief Pointer to the referring schedulable.
     */
    HoltSchedulable*   _hp;

    /**
     * \brief Pointer to the referring resource.
     */
    HoltResource*  _hr;

    /**
     * \brief State of request.
     */
    Request::state _state;
  };



  /**
   * \brief Widget representing an Holt graph.
   *
   * This class is based on Simulation and History observers
   * to get updates during the simulation progress; it's
   * derived from CairoWidget to get the buffering and scaling
   * features of that class.
   *
   * The objects disposition can be done in three ways:
   * - horizontal: resources  top, schedulables bottom, from left to right
   * - vertical: resources  left, schedulables right, from top to bottom
   * - circular: resources and processes along a cricle
   * This disposition is called "arrange mode"
   *
   * \deprecated The class should implement only HistoryObserver
   *
   */
  class HoltWidget
  : public SimulationObserver,
  public HistoryObserver,
  public  CairoWidget
  {
  public:
    /**
     * \brief Modes to dispose graph nodes.
     */
    enum arrange_mode
    {
      arrange_horizontal  =  1 << 0,
      arrange_vertical    =  1 << 1,
      arrange_circular    =  1 << 2
    };

    /**
     * \brief Unique constructor.
     *
     * Saves the passed argument in data member _simulation.
     *
     * \param simulation The observed Simulation
     */
    HoltWidget(Simulation& simulation);

    /**
     * \brief Object's virtual destructor.
     */
    virtual ~HoltWidget();

    /**
     * \brief SimulationObserver's update method redefinition.
     *
     * Actually is a dummy method.
     *
     * \param changed_simulation the observed Simulation
     */
    void update(const Simulation& changed_simulation);

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



    /**
     * \brief Sets dimension of contained objects.
     *
     * \param radius The new desired value.
     * \return The radius previous value.
     */
    double set_radius(double radius);

    /**
     * \brief Gets dimension of contained objects.
     *
     * \return The actual radius value.
     */
    double get_radius();

    /**
     * \brief Gets the current arrange mode.
     *
     * \return The actual arrange mode value.
     */
    arrange_mode get_arrange_mode();

    /**
     * \brief Sets and gets arrange mode.
     *
     * \param mode The desired arrange mode.
     * \return The previous mode value.
     */
    arrange_mode set_arrange_mode(arrange_mode mode);

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

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

  protected:


    /**
     * \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);

    // virtual void calc_widget_size(size_t& width, size_t& height);

    /**
     * \brief Gets the actual history status and make graph objects.
     */
    void acquire();
  
    /**
     * \brief Reposition objects respecting actual arrange mode.
     */
    void arrange();
  private:
    /**
     * \brief Associative container to keep HoltResource elements.
     *
     * This is a map because each schedulables request must find
     * the related object throug its key.
     */
    typedef std::map<resource_key_t, HoltResource*>   HoltResources;

    /**
     * \brief Container to keep HoltSchedulable elements.
     */
    typedef std::vector<HoltSchedulable*>             HoltProcesses;

    /**
     * \brief Container to keep HoltRequest elements.
     */
    typedef std::vector<HoltRequest*>                 HoltRequests;


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

    /**
     * \brief Radius used to dimension all controlled objects.
     */
    double _radius;

    /**
     * \brief The HoltResource container.
     */
    HoltResources _holt_resources;

    /**
     * \brief The HoltProcess container.
     */
    HoltProcesses _holt_schedulables;

    /**
     * \brief The HoltRequest container.
     */
    HoltRequests  _holt_requests;

    /**
     * \brief Number of schedulables (processes or threads) to draw.
     */
    int           _n_proc;

    /**
     * \brief Number of resources to draw.
     */
    int           _n_res;

    /**
     * \brief The current "arrange mode".
     *
     * \see arrange_mode
     */
    arrange_mode  _arrange_mode;

    /**
     * \brief Flag to select processes or threads visualization.
     */
    bool          _show_threads;
  };

} //~ namespace sgpem


#endif //~ HOLT_WIDGET_HH
