// src/backend/dynamic_thread.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 DYNAMIC_THREAD_HH
#define DYNAMIC_THREAD_HH 1


#include "gettext.h"
#include "glibmm/ustring.h"
#include <vector>

#include <sgpemv2/thread.hh>
#include "dynamic_process.hh"
#include "dynamic_schedulable.hh"

#include <memory>

namespace sgpem
{
  class DynamicThread;
  class DynamicProcess;
  class StaticThread;
  class Request;
  class DynamicRequest;

  class SG_DLLLOCAL DynamicThread : public DynamicSchedulable, public Thread
  {
  public:
    /**
      \brief Constructor.
      \param core The static counterpart to this object.
      \param parent The parent process that spawned this thread.
     */
    DynamicThread(StaticThread* core, DynamicProcess* parent);

    /**
      \brief Copy constructor.
      \param other The dynamic thread to clone.
      \param parent The parent process that spawned this thread.
     */
    DynamicThread(const DynamicThread &other, DynamicProcess* parent);

    /**
      \brief Destructor.
     */
    virtual ~DynamicThread();

    /**
      \brief Gets the owning process.
      \return A reference to the DynamicProcess that owns this thread.
    */
    DynamicProcess& get_process();

    /**
      \brief Gets this thread's state.
      \return The current Schedulable::state of this object.
    */
    state get_state() const;

    /**
      \brief Sets/gets this thread's state.
      \param new_state The desired Schedulable::state of this object.
      \return The previous state.
    */
    state set_state(state new_state);

    /**
      \brief Gets the last istant this schedulable has
        been put in a Running state.

      \return Current value of last_acquisition.
     */
    int get_last_acquisition() const;

    /**
      \brief Sets/gets the last istant this schedulable
      has been put in a Running state.

      \param instant New value for last_acquisition.
      \return Previous value of last_acquisition.
     */
    void set_last_acquisition(int instant);

    /**
      \brief Gets the last instant this schedulable has changed its state
        from running to something else.

      \return Current value of last_release.
     */
    int get_last_release() const;

    /**
      \brief Sets/gets the last instant this schedulable has changed
        its state from running to something else.

      \param instant New value for last_release.
      \return Previous value of last_release.
     */
    void set_last_release(int instant);

    /**
      \brief Gets total running time of this thread.

      \return Current value of _run_for.
    */
    unsigned int get_elapsed_time() const;

    /**
      \brief Decreases the schedulable remaining time by one unit.
    */
    void decrease_remaining_time();

    /**
      \brief Serializes this object via the provided visitor.
      Calls translator->from_thread(this).
     */
    void serialize(SerializeVisitor& translator) const;

    /**
      \brief Gets a reference to static counterpart of this object.
      \return A reference to static counterpart of this object.
     */
    virtual StaticThread& get_core();

    /**
      \brief Gets a const reference to static counterpart of this object.
      \return A const reference to static counterpart of this object.
     */
    virtual const StaticThread& get_core() const;



    /**
      \brief Returns ::Requests pointers this ::Thread did to some ::Resource.
        Since C++ (unfortunately) doesn't support covariance for return
        types when they're contained into std::vector<T>, some black magic
        (downcasting) will have to happen inside the backend.
        Does also the job of "add_request" and "remove_request"
      \return A reference to the DynamicRequests pointers vector.
     */
    std::vector<Request*> get_requests();

    /**
      \brief Returns ::DynamicRequest pointers this ::Thread did to some ::Resource.
        Since C++ (unfortunately) doesn't support covariance for return
        types when they're contained into std::vector<T>, some black magic
        (downcasting) will have to happen inside the backend.
        Does also the job of "add_request" and "remove_request"
      \return A reference to the DynamicRequests pointers vector.
     */
    std::vector<DynamicRequest*>& get_dynamic_requests();

  private:
    /**
      \brief Private copy constructor; avoids public construction of
      DynamicThread without owning process.
     */
    DynamicThread(const DynamicThread &other);

    /**
      \brief Pointer to static counterpart of this object.
     */
    std::shared_ptr<StaticThread> _core;

    /**
      \brief The current state of this thread.

       See Scheduler.step_forward() to know how this state changes.
     */
    state _state;

    /**
      \brief Container with this thread's requests.
     */
    std::vector<DynamicRequest*> _dynamic_requests;

    /**
      \brief Pointer to this thread parent.
     */
    DynamicProcess* _parent;

    /**
      \brief Total running time of this thread
    */
    unsigned int _ran_for;

    /**
      \brief The last istant this schedulable has been put in a Running state.
     */
    int _last_acquisition;

    /**
      \brief The last instant this schedulable has changed its state
        from running to something else.
     */
    int _last_release;
  };

}

#endif

