// src/backend/concrete_simulation_statistics.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 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/.


#include "concrete_simulation_statistics.hh"
#include <sgpemv2/statistics.hh>
#include <sgpemv2/simulation.hh>
#include <sgpemv2/history.hh>
#include <sgpemv2/environment.hh>

#include <iostream>
#include <math.h>

using namespace std;
using namespace sgpem;

ConcreteSimulationStatistics::~ConcreteSimulationStatistics()
{
}

ConcreteSimulationStatistics::ConcreteSimulationStatistics(const std::vector<ConcreteProcessStatistics>& proc_stats, const int& instant)
{
  _average_inactivity_time = 0;
  _average_turn_around = 0;
  _average_response_time = 0;
  _average_efficiency = 0;
  _terminated_processes = 0;
  _terminated_threads = 0;
  _average_execution_progress = 0 ;
  _average_processes_throughput = 0;
  _average_threads_throughput = 0;
  
  int started_schedulables_count = 0;  //useful for stats thath can be -1
  
  if (instant == -1)
    return;
  
  //get infos that don't depend on the Processes statistics
  //but on the current environment:
  
  //iterate through all processes
  vector<Process*> procs = Simulation::get_instance().get_history().get_environment_at(instant).get_processes();
  for (unsigned int i=0; i < procs.size(); i++)
  {
    if (procs[i]->get_state() == Schedulable::state_terminated)
      _terminated_processes++;
    vector<Thread*> threads = procs[i]->get_threads();
    //iterate through all threads of this process
    for (unsigned int ii=0; ii < threads.size(); ii++)
      if (threads[ii]->get_state() == Schedulable::state_terminated)
        _terminated_threads++;
  }
  
  //Examinate processes and threads statistics:
  //SUM all values from processes and threads
  
  vector<ConcreteProcessStatistics>::const_iterator p;
  for (p = proc_stats.begin(); p != proc_stats.end(); p++)
  {
  
    if (p->get_response_time() != -1)
    {
      started_schedulables_count++;
      _average_response_time += p->get_response_time();
      _average_efficiency += p->get_efficiency();
      _average_inactivity_time += p->get_total_inactivity();
      _average_turn_around += p->get_turn_around();
      _average_execution_progress += p->get_execution_progress();
    }
  
    //iterate through all threads of this process
    vector<const ThreadStatistics*> thread_stats = p->get_threads_statistics();
    vector<const ThreadStatistics*>::const_iterator t;
    for (t=thread_stats.begin(); t != thread_stats.end(); t++)
      if ((*t)->get_response_time() != -1)
      {
        started_schedulables_count++;
        _average_response_time += (*t)->get_response_time();
        _average_efficiency += (*t)->get_efficiency();
        _average_inactivity_time += (*t)->get_total_inactivity();
        _average_turn_around += (*t)->get_turn_around();
        _average_execution_progress += (*t)->get_execution_progress();
      }
  
  }
  
  //make the AVERAGE and ROUND the values
  if (started_schedulables_count != 0)
  {
    modff(((_average_response_time / started_schedulables_count) * 100.0f) / 100.0f, &_average_response_time);
    modff(((_average_efficiency / started_schedulables_count) * 100.0f) / 100.0f, &_average_efficiency);
    modff(((_average_inactivity_time / started_schedulables_count) * 100.0f) / 100.0f, &_average_inactivity_time);
    modff(((_average_turn_around / started_schedulables_count) * 100.0f) / 100.0f, &_average_turn_around);
    modff(((_average_execution_progress / started_schedulables_count) * 100.0f) / 100.0f, &_average_execution_progress);
  }
  if (instant != 0)
  {
    modff((((float)_terminated_processes / (float)instant) * 1000.0f) / 1000.0f, &_average_processes_throughput);
    modff((((float)_terminated_threads  / (float)instant) * 1000.0f) / 1000.0f, &_average_threads_throughput);
  }
}
  



float  
ConcreteSimulationStatistics::get_average_inactivity_time() const 
{
  return _average_inactivity_time;
}

float  
ConcreteSimulationStatistics::get_average_execution_progress() const 
{
  return _average_execution_progress;
}

float  
ConcreteSimulationStatistics::get_average_turn_around() const 
{
  return _average_turn_around;
}

float  
ConcreteSimulationStatistics::get_average_response_time() const 
{
  return _average_response_time;
}

float  
ConcreteSimulationStatistics::get_average_efficiency() const 
{
  return _average_efficiency;
}

int  
ConcreteSimulationStatistics::get_terminated_processes() const 
{
  return _terminated_processes;
}

int  
ConcreteSimulationStatistics::get_terminated_threads() const 
{
  return _terminated_threads;
}

float  
ConcreteSimulationStatistics::get_average_processes_throughput() const 
{
  return _average_processes_throughput;
}

float  
ConcreteSimulationStatistics::get_average_threads_throughput() const 
{
  return _average_threads_throughput;
}


