function [qnRefactored, nrefactorings] = softwareRefactorJobReassignment(qn, maxDuplications, maxIterations)
	% SOFTWAREREFACTORJOBREASSIGNMENT
	%
	% This function applies all the possible job reassignments to improve the
	% demand score (minimize the variance).
	%
	% INPUT
	% qn: queuing network
	% maxDuplications: maximum number of additional duplications for the current queuing
	% center (vector of qn.M size)
	% maxIterations: max number of iterations
	%
	% OUTPUT
	% qnRefactored: new qn after applying refactorings
	% nrefactorings: number of refactorings that have been performed
	
	nrefactorings = 0;
	myqn = qn;
	maxdup = maxDuplications;
	
	
	for zz=1:maxIterations;
		qnv = QNValue(myqn);
		filter = true(qn.M, qn.K);
		for ii=1:qn.M
			indexDemands = qnv.demands(ii,:);
			nonZeroDemands = indexDemands(indexDemands>0);
			if maxdup(ii)==0 || strcmp(qn.sched(ii),'inf') || length(nonZeroDemands)<=1
				filter(ii,:)=false;
				continue;
			end
		end
		filteredDemands = qnv.demands;
		filteredDemands(~filter) = 0;
		maxDemands = max(filteredDemands);
		for ii=1:qn.M
			for jj=1:qn.K
				if qnv.demands(ii,jj)<maxDemands(jj) || qnv.demands(ii,jj)==0
					filter(ii,jj) = false;
				end
			end
		end

		if any(any(filter))
			[ii, jj] = find(filter);
			index = ii(1);
			k = jj(1);
			myqn = jobReAssignment(myqn, index, k);
			nrefactorings = nrefactorings + 1;
			maxdup = [maxdup(1:index); maxdup(index:end)];
			maxdup(index) = 0;
			maxdup(index+1) = maxdup(index+1) - 1;
		else 
			break;
		end
	end
	
	
	
% 	for ii=1:maxIterations;
% 		qnv = QNValue(myqn);
% 		[score] = evaluateJobReassignment(qnv);
% 		score(maxdup <= 0) = 0;
% 		maxscore = max(score);
% 		if maxscore < eps
% 			qnRefactored = myqn;
% 			return;
% 		end
% 		
% 		index = find(score == maxscore);
% 		index = index(1);
% 		myqn = jobReAssignment(myqn, index);
% 		nrefactorings = nrefactorings + 1;
% 		maxdup = [maxdup(1:index); maxdup(index:end)];
% 		maxdup(index) = 0;
% 		maxdup(index+1) = maxdup(index+1) - 1;
% 	end
	
	qnRefactored = myqn;

end