// src/backend/concrete_thread_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 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 "concrete_thread_statistics.hh"
#include <sgpemv2/simulation.hh>
#include <sgpemv2/history.hh>
#include <sgpemv2/environment.hh>
#include <sgpemv2/schedulable.hh>
#include <sgpemv2/process.hh>
#include <sgpemv2/thread.hh>
#include <sgpemv2/resource.hh>
#include <sgpemv2/request.hh>
#include <iostream>

using namespace std;
using namespace sgpem;

/**
	The constructor executes all calculations examinating or only the Thread object
	or the whole History

*/
ConcreteThreadStatistics::ConcreteThreadStatistics(const Thread* core, const int& instant): _core(core)
{
	//initializations
	_total_inactivity 		= 0;
	_execution_time 		= 0;
	_response_time 			= -1;
	_real_arrival_time		= -1;
	_turn_around			= 0;
	_resource_usage_time	= 0;	
	_resource_waitings_time	= 0;
	
	bool iniziato = false;	//useful for _response_time	
	
	const History& 										hist = Simulation::get_instance().get_history();	//prendo la lista delle risorse
	const map<Environment::resource_key_t, Resource*> 	res  = hist.get_environment_at(0).get_resources();
	
	//****** iterate through HISTORY to retreive informations
	for (int time=0; time < instant; time++)
	{		
		const Environment& 		env 	= hist.get_environment_at(time);
		const vector<Process*> 	procs 	= env.get_processes();
		
		//looks for the process that owns this thread
		for (uint i_p=0; i_p < procs.size(); i_p++)
		{
			const vector<Thread*> threads = procs[i_p]->get_threads();
			//looks for the thread "core"
			for (uint i_t = 0; i_t < threads.size(); i_t++)
			{
				if ( (*threads[i_t]) == (*core) )	//FOUND!!
				{
					if (threads[i_t]->get_state() == Schedulable::state_running)
					{						
						iniziato = true;
						if( _response_time == -1)	//arrives and runs immediately
						{
							_response_time = 0;
							_real_arrival_time = time -  procs[i_p]->get_arrival_time() -1;
						}
						_execution_time++;
					}
					if (threads[i_t]->get_state() != Schedulable::state_future &&
									   threads[i_t]->get_state() != Schedulable::state_terminated)
					{
						_turn_around++;
						if (!iniziato && _response_time == -1)	//arrives and doesn't run
						{
							_response_time = 0;	
							_real_arrival_time = time -  procs[i_p]->get_arrival_time() -1;
						}
					}					
					if (threads[i_t]->get_state() == Schedulable::state_blocked
							|| threads[i_t]->get_state() == Schedulable::state_ready)
					{
						_total_inactivity++;
						if (!iniziato && _response_time != -1)
							_response_time++;
						
						if (threads[i_t]->get_state() == Schedulable::state_blocked)
							_resource_waitings_time++;
					}
				}
			}	//threads	
		}	//procs
		
		
		//for each resource check requests at this istant:
		//if the request of this thread is allocated then increase _resource_usage_time
		Environment::Resources::const_iterator res_iter = res.begin();
		while(res_iter != res.end())
		{
			Environment::resource_key_t key = (*res_iter).first;
			vector<SubRequest*> req = env.get_request_queue(key);
			for (uint i_r=0; i_r < req.size(); i_r++)
				if( (*req[i_r]).get_request().get_thread() == (*core) && (*req[i_r]).get_state() == Request::state_allocated)
					_resource_usage_time++;
			
			res_iter++;
		}		
		
	}//istants
	
	//set other variables
	_execution_progress = (100*_execution_time)/core->get_total_cpu_time();	
	if (_turn_around == 0)
		_efficiency = -1;
	else
		_efficiency = (_execution_time*100)/_turn_around;
}


ConcreteThreadStatistics::~ConcreteThreadStatistics()
{	
}

int			
ConcreteThreadStatistics::get_execution_time() const
{
	return _execution_time;
}

int	
ConcreteThreadStatistics::get_execution_progress() const
{
	return _execution_progress;
}

int	
ConcreteThreadStatistics::get_total_inactivity() const
{
	return _total_inactivity;
}

int	
ConcreteThreadStatistics::get_response_time() const
{
	return _response_time;
}

int	
ConcreteThreadStatistics::get_turn_around() const
{
	return _turn_around;
}

int
ConcreteThreadStatistics::get_efficiency() const
{
	return _efficiency;	
}

int
ConcreteThreadStatistics::get_resource_usage_time() const
{
	return _resource_usage_time;
}

int
ConcreteThreadStatistics::get_resource_waitings_time() const
{
	return _resource_waitings_time;
}

int
ConcreteThreadStatistics::get_real_arrival_time() const
{
	return _real_arrival_time;
}

const Thread* 	
ConcreteThreadStatistics::get_core() const
{
	return _core;	
}
