// src/backend/dynamic_request.cc - 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 2 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, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

#include "dynamic_request.hh"
#include "static_request.hh"
#include "dynamic_sub_request.hh"
#include "dynamic_thread.hh"
#include <sgpemv2/serialize_visitor.hh>

#include <sgpemv2/templates/deletor.tcc>
#include <sgpemv2/templates/smartp.tcc>

#include <algorithm>
#include <functional>
#include <cassert>

using namespace sgpem;
using namespace std;

DynamicRequest::DynamicRequest(StaticRequest *core,
                               DynamicThread* owner) :
    _static_request(core), _dynamic_thread(owner)
{
  assert(core != NULL);
  assert(owner != NULL);
  // Leave this line: it helps us with a compiler warning if
  // the get_dynamic* method signature changes:
  std::vector<DynamicRequest*>& siblings = owner->get_dynamic_requests();
  siblings.push_back(this);
}

DynamicRequest::DynamicRequest(const DynamicRequest& other, DynamicThread* owner) :
    _static_request(other._static_request), _dynamic_thread(owner)
{
  typedef vector<DynamicSubRequest*> SubReqVec;

  assert(owner != NULL);

  const SubReqVec& other_subs = other._dynamic_subrequests;

  // Not sure of this, but the constructor of DynamicSubRequest should take care
  // of adding itself to the vector of sub requests. This is only my opinion,
  // but I think this is a complicated way of doing things...
  for (SubReqVec::const_iterator it = other_subs.begin(); it != other_subs.end(); ++it)
    new DynamicSubRequest(*(*it), this);

  // Leave this line: it helps us with a compiler warning if
  // the get_dynamic* method signature changes:
  std::vector<DynamicRequest*>& siblings = owner->get_dynamic_requests();
  siblings.push_back(this);
}


DynamicRequest::~DynamicRequest()
{
  for_each(_dynamic_subrequests.begin(), _dynamic_subrequests.end(),
           memory::deletor<DynamicSubRequest>());
}


bool
DynamicRequest::operator==(const Request& op2) const
{
  assert(dynamic_cast<const DynamicRequest*>(&op2) != NULL);
  return _static_request == dynamic_cast<const DynamicRequest&>(op2)._static_request;
}


vector<SubRequest*>
DynamicRequest::get_subrequests()
{
  return std::vector<SubRequest*>(_dynamic_subrequests.begin(), _dynamic_subrequests.end());
}


vector<DynamicSubRequest*>&
DynamicRequest::get_dynamic_subrequests()
{
  return _dynamic_subrequests;
}


DynamicThread&
DynamicRequest::get_thread()
{
  return *_dynamic_thread;
}

unsigned int
DynamicRequest::get_instant() const
{
  return _static_request->get_instant();
}

Request::state
DynamicRequest::get_state() const
{
  typedef std::vector<DynamicSubRequest*> SubReqs;

  state result = state_future;

#ifndef NDEBUG
  // Only for debug:
  bool at_least_once = false;
#endif // ~NDEBUG

  const SubReqs& sreqs = _dynamic_subrequests;
  for (SubReqs::const_iterator it = sreqs.begin(); it != sreqs.end(); it++)
  {
    SubRequest& cur = **it;

    switch (cur.get_state())
    {
    case state_allocated:
      return state_allocated;
    case state_unallocable:
      return state_unallocable;
    default:

#ifndef NDEBUG
      // We want to be sure that all subrequests
      // have the same state since state_allocable,
      // state_terminated and state_future are mutually
      // exclusive
      if (at_least_once)
        assert(result == cur.get_state());
      at_least_once = true;
#endif //~ NDEBUG

      result = cur.get_state();
    }
  }
  return result;
}


void
DynamicRequest::serialize(SerializeVisitor& translator) const
{
  translator.from_request(*this);
}


StaticRequest&
DynamicRequest::get_core()
{
  return *_static_request;
}


const StaticRequest&
DynamicRequest::get_core() const
{
  return *_static_request;
}
