/*
 * Instituto Superior de Engenharia do Porto
 *
 * Estruturas de Informação
 *
 * 2000/2001
 *
 * ------------------------------------------
 *
 * classe para simular um scheduler de um sistema operativo
 *		
 * sistemaoperativo.cpp
 *
 */

#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
#include "arvpesq.h"
#include "heapv.h"
#include "sistemaoperativo.h"

int getChave(const CProcesso& proc)
{
	return proc.getId();
}

#ifdef __USE_ARVPESQ

void CSistemaOperativo::altera_prioridade(CProcesso& proc, const CProcesso& nova)
{
	proc.setPrioridade(nova.getPrioridade());
}

void CSistemaOperativo::altera_PC(CProcesso& proc, const CProcesso& nova)
{
	proc.setPC(nova.getPC());
}

void CSistemaOperativo::insere_heap(const CProcesso& proc, void* pVoidHeap)
{
	CKeyHeapV<int, CProcesso>* pHeap = (CKeyHeapV<int, CProcesso>*)pVoidHeap;
	pHeap->insert(proc, proc.getPrioridade());
}

void CSistemaOperativo::Run(const CProcesso& proc)
{
	cout << "Running: " << setw(10) << proc.getName() << " | id: " << setw(5) << proc.getId();
	cout << " | Pri: " << setw(5) << proc.getPrioridade() << " | PC: " << setw(5) << proc.getPC() << endl;

	/*
	CProcesso nova;
	nova.m_PC = proc.m_PC + 100;
	m_ProcTable.update(proc.m_nId, nova, altera_PC);
	*/
	CProcesso& p = m_ProcTable.getForUpdate(proc.getId());
	p.incPC(quantum(proc.getPrioridade()));
}

#else

int CSistemaOperativo::procura(int nProcID)
{
	for (int i = 0; i < m_ProcTable.size(); i++)
	{
		if (m_ProcTable[i].getId() == nProcID)
			return i;
	}
	return -1;
}

void CSistemaOperativo::Run(int idxProc)
{
	CProcesso& proc = m_ProcTable[idxProc];

	cout << "Running: " << setw(10) << proc.getName() << " | id: " << setw(5) << proc.getId();
	cout << " | Pri: " << setw(5) << proc.getPrioridade() << " | PC: " << setw(5) << proc.getPC() << endl;

	proc.incPC();
}

#endif

void CSistemaOperativo::Schedule()
{
#ifdef __USE_ARVPESQ

	if (m_ProcTable.vazia())
		return;

	CKeyHeapV<unsigned int, CProcesso> heap;
	/*
	list<CProcesso> l1;
	m_ProcTable.findall(l1);

	list<CProcesso>::iterator i;
	for (i = l1.begin(); i != l1.end(); i++)
		heap.insert(*i, (*i).m_nPri);
	*/
	m_ProcTable.findall(insere_heap, (void*)&heap);

	//schedule
	while (!heap.empty())
	{
		unsigned int pri;
		CProcesso proc;
		heap.extract_min(proc, pri);

		//give time slice
		Run(proc);
	}

#else

	if (m_ProcTable.size() == 0)
		return;

	CKeyHeapV<unsigned int, int> heap;

	for (int i = 0; i < m_ProcTable.size(); i++)
		heap.insert(i, m_ProcTable[i].getPrioridade());

	//schedule
	while (!heap.empty())
	{
		unsigned int pri;
		int idx;
		heap.extract_min(idx, pri);

		//give time slice
		Run(idx);
	}
#endif
}

int CSistemaOperativo::CriaProcesso(string sExec, unsigned int nPriInicial /* = MAX_PRIORIDADE-1 */)
{
#ifdef __USE_ARVPESQ
	m_ProcTable.inserir(CProcesso(m_nLastProcID, nPriInicial, sExec));
#else
	m_ProcTable.push_back(CProcesso(m_nLastProcID, nPriInicial, sExec));
#endif
	return ++m_nLastProcID;
}

bool CSistemaOperativo::AlteraPrioridade(int nProcID, unsigned int nNovaPri)
{
#ifdef __USE_ARVPESQ

	CProcesso nova;
	nova.setPrioridade(nNovaPri);
	return m_ProcTable.update(nProcID, nova, altera_prioridade);
#else

	int i = procura(nProcID);
	if (i == -1)
		return false;

	m_ProcTable[i].setPrioridade(nNovaPri);
	return true;
#endif
}

bool CSistemaOperativo::MataProcesso(int nProcID)
{
#ifdef __USE_ARVPESQ

	CProcesso dummy;
	m_ProcTable.eliminar(nProcID, dummy);
	return true;
#else

	int i = procura(nProcID);
	if (i == -1)
		return false;

	m_ProcTable.erase(m_ProcTable.begin()+i);
	return true;
#endif
}


