classdef QNfactory
	%QNFactory Create QN with the given characteristics
	
	methods (Static)
		
		function qn = newSapErpQN(numDialogUsers)
			% NEWSAPERPQN
			% Create a queuing network for the SAP ERP application
			% numDialogUsers: number of dialog users (other types of users
			% are proportional to the number of dialog users).
			% qn: new queuing network
			
			numStations = 2;
			numClasses = 3;
			ecuConvAS =  1.535;
			ecuConvDB = ecuConvAS;
			
			rates = [0.000029 0.000029 0.000029; ...
						0.008346/ecuConvAS 0.02087/ecuConvAS 0.03032/ecuConvAS; ...
						0.2202/ecuConvDB 0.8299/ecuConvDB 3.286/ecuConvDB];
			NK = [numDialogUsers; numDialogUsers*0.2652; numDialogUsers*0.06657];
			
			N = sum(NK);
			P = zeros((numStations+1)*numClasses, (numStations+1)*numClasses);
			for k=1:numClasses
				P(k:numClasses:end,k:numClasses:end) = [0 1 1;1 0 0;1 0 0];
			end

			[S, sched, classMatch, refNodes, nodeNames, classNames] = ... 
				QNfactory.basics(numStations, numClasses);
			qn = CMCQNCS(numStations+1, numClasses, N, S, rates, sched, P, NK, ...
				classMatch, refNodes, nodeNames, classNames);
		end
		
		function qn = new2TierQN(numClasses, sumUsers, minRate, sumRates, minBackProb)
			% Create a QN with 2 stations of the type:
			% DELAYNODE-->NODE_1-->NODE_2
			%    /|\        |        |
			%     \------------------|
			% numClasses: total number of classes of users
			% sumUsers: total number of users
			% minRate: minimum rate for each station
			% sumRates: sum of the rates of all the stations
			% minBackProb: minimum probability for a user to visit station 2 after
			%					visiting station 1
			
			numStations = 2;
			
			P = zeros((numStations+1)*numClasses, (numStations+1)*numClasses);
			pm = zeros(numStations+1, numStations+1, numClasses);
			
			pm(1,2,:) = 1;
			pm(3,1,:) = 1;
			
			for kk=1:numClasses
				pm(2,3,kk) = minBackProb + rand*(1-minBackProb);
				pm(2,1,kk) = 1 - pm(2,3,kk);
			end
			
			for kk=1:numClasses
 				P(kk:numClasses:end, kk:numClasses:end) = pm(:,:,kk);
			end
			
			[rates] = QNfactory.generateRates(numStations, numClasses, minRate, sumRates);	
			[N, NK] = QNfactory.users(numClasses, sumUsers);
			[S, sched, classMatch, refNodes, nodeNames, classNames] = QNfactory.basics(2, numClasses);
			qn = CMCQNCS(numStations+1, numClasses, N, S, rates, sched, P, NK, classMatch, refNodes, nodeNames, classNames);
		end
		
		function qn = newTetraQN(numClasses, sumUsers, minRate, sumRates)
			% Create a QN with 4 stations of the type:
			% DELAYNODE-->NODE_1-->NODE_2-->NODE_3---|
			%    /|\                 |----->NODE_4---|
			%     \------------------|---------------|
			% numClasses: total number of classes of users
			% sumUsers: total number of users
			% minRate: minimum rate for each station
			% sumRates: sum of the rates of all the stations
			
			numStations = 4;
			
			P = zeros((numStations+1)*numClasses, (numStations+1)*numClasses);
			pm = zeros(numStations+1, numStations+1, numClasses);
			
			pm(1,2,:) = 1;
			pm(2,3,:) = 1;
			pm(4,1,:) = 1;
			pm(5,1,:) = 1;
			
			for kk=1:numClasses
				pm(3,[1 4 5],kk) = rand(1,3);
				pm(3,[1 4 5],kk) = pm(3,[1 4 5],kk)/sum(pm(3,[1 4 5],kk));
			end
			
			for kk=1:numClasses
 				P(kk:numClasses:end, kk:numClasses:end) = pm(:,:,kk);
			end
			
			[rates] = QNfactory.generateRates(numStations, numClasses, minRate, sumRates);	
			[N, NK] = QNfactory.users(numClasses, sumUsers);
			[S, sched, classMatch, refNodes, nodeNames, classNames] = QNfactory.basics(4, numClasses);
			qn = CMCQNCS(numStations+1, numClasses, N, S, rates, sched, P, NK, classMatch, refNodes, nodeNames, classNames);
		end
		
		
		function qn = newSequenceQN(numStations, numClasses, sumUsers, minRate, sumRates)
			% Create a QN with N stations of the type:
			% DELAYNODE-->NODE_1-->NODE_2-->...--->NODE_N
			%    /|\                                 |
			%     \----------------------------------|
			% numStations: total number of non-delay nodes
			% numClasses: total number of classes of users
			% sumUsers: total number of users (sum among all classes)
			% minRate: minimum rate for each station for each class
			% sumRates: sum of the rates of all the stations for each class
			
			P = QNfactory.sequenceTopology(numStations, numClasses);
			rates = QNfactory.generateRates(numStations, numClasses, minRate, sumRates);
			[N, NK] = QNfactory.users(numClasses, sumUsers);
			[S, sched, classMatch, refNodes, nodeNames, classNames] = QNfactory.basics(numStations, numClasses);
			qn = CMCQNCS(numStations+1, numClasses, N, S, rates, sched, P, NK, classMatch, refNodes, nodeNames, classNames);
		end
		
		function [P] = sequenceTopology(numStations, numClasses)
			% Generate sequential topology
			
			P = zeros((numStations+1)*numClasses, (numStations+1)*numClasses);
			pm = zeros(numStations+1, numStations+1);
			
			for ii=1:numStations+1
				for jj=ii+1:numStations+1
					pm(ii,jj) = 1;
				end
			end
			pm(numStations+1,1) = 1;
			
			for kk=1:numClasses
 				P(kk:numClasses:end, kk:numClasses:end) = pm;
			end
		end		
		
		function [rates] = generateRates(numStations, numClasses, minRate, sumRates)
			% Generate rates
			
			rateUnit = (sumRates - minRate*numClasses)/(10*numClasses);
			
			if rateUnit<0
				error('Sum of rates is less than numClasses*minRates');
			end
			
			rates = ones(numStations+1, numClasses);
			rates = rates * minRate;
			rates(1,:) = 1;
			
			for ii=2:numStations+1
				while sum(rates(ii, :)) < sumRates
					jj = randi([1,numClasses]);
					rates(ii, jj) = rates(ii, jj) + 1;
				end
			end
		end
		
		
		function [N, NK] = users(numClasses, sumUsers)
			% users - Generate the number of users for each class
			% such that the total number of users is sumUsers and each class
			% has at least a user.
			
			if sumUsers < numClasses
				error('There are not enough users to cover all classes');
			end
			
			N = sumUsers;
			NK=ones(numClasses, 1);
			
			while sum(NK)<N
				ii = randi([1,numClasses]);
				NK(ii) = NK(ii) + 1;
			end
		end
		
		function [S, sched, classMatch, refNodes, nodeNames, classNames] = basics(numStations, numClasses)
			% basics - Generate basics infos
			
			S = ones(numStations+1, 1);
			S(1) = -1;
			sched = cell(numStations+1, 1);
			sched(1) = {'inf'};
			sched(2:end) = {'ps'};
			classMatch = eye(numClasses);
			refNodes = ones(numClasses, 1);
			nodeNames = cell(numStations+1, 1);
			nodeNames(1) = {'delay'};
			for ii=1:numStations
				nodeNames(ii+1) = {['n' num2str(ii)]}; 
			end
			classNames = cell(numClasses, 1);
			for ii=1:numClasses
				classNames(ii) = {['k' num2str(ii)]};
			end
			
		end
		
	end
	
end

